1 /* $OpenBSD: npppd_ctl.c,v 1.16 2017/08/11 16:25:59 goda Exp $ */
2
3 /*-
4 * Copyright (c) 2009 Internet Initiative Japan Inc.
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 */
28 #include <sys/socket.h>
29 #include <sys/ioctl.h>
30 #include <net/if.h>
31 #include <netinet/in.h>
32 #include <net/pipex.h>
33
34 #include <errno.h>
35 #include <event.h>
36 #include <stddef.h>
37 #include <stdio.h>
38 #include <stdlib.h>
39 #include <string.h>
40
41 #include "radish.h"
42 #include "npppd_local.h"
43 #include "npppd.h"
44 #include "log.h"
45
46 struct stopped_ppp {
47 struct npppd_who ppp_who;
48 TAILQ_ENTRY(stopped_ppp) entry;
49 };
50
51 struct npppd_ctl {
52 u_int *started_ppp;
53 int started_ppp_pos;
54 int started_ppp_siz;
55 TAILQ_HEAD(, stopped_ppp) stopped_ppps;
56 npppd *npppd;
57 bool is_monitoring;
58 bool responding;
59 };
60
61 static int npppd_ctl_who_walk_rd(struct radish *, void *);
62 static int npppd_ctl_who0 (struct npppd_ctl *, bool);
63 static void npppd_who_init (struct npppd_who *, npppd_ppp *);
64 #ifdef USE_NPPPD_PIPEX
65 static int npppd_ppp_get_pipex_stat(struct npppd_who *_this, npppd_ppp *ppp);
66 #endif
67
68 struct npppd_ctl *
npppd_ctl_create(npppd * _this)69 npppd_ctl_create(npppd *_this)
70 {
71 struct npppd_ctl *ctl;
72
73 if ((ctl = calloc(1, sizeof(struct npppd_ctl))) == NULL)
74 return (NULL);
75 ctl->npppd = _this;
76 TAILQ_INIT(&ctl->stopped_ppps);
77
78 return (ctl);
79 }
80
81 void
npppd_ctl_destroy(struct npppd_ctl * _this)82 npppd_ctl_destroy(struct npppd_ctl *_this)
83 {
84 if (_this != NULL) {
85 free(_this->started_ppp);
86 free(_this);
87 }
88 }
89
90 int
npppd_ctl_who(struct npppd_ctl * _this)91 npppd_ctl_who(struct npppd_ctl *_this)
92 {
93 return (npppd_ctl_who0(_this, false));
94 }
95
96 int
npppd_ctl_monitor(struct npppd_ctl * _this)97 npppd_ctl_monitor(struct npppd_ctl *_this)
98 {
99 _this->is_monitoring = true;
100 return (0);
101 }
102
103 int
npppd_ctl_who_and_monitor(struct npppd_ctl * _this)104 npppd_ctl_who_and_monitor(struct npppd_ctl *_this)
105 {
106 return (npppd_ctl_who0(_this, true));
107 }
108
109 static int
npppd_ctl_who0(struct npppd_ctl * _this,bool is_monitoring)110 npppd_ctl_who0(struct npppd_ctl *_this, bool is_monitoring)
111 {
112 _this->is_monitoring = is_monitoring;
113 _this->responding = true;
114 if (rd_walktree(_this->npppd->rd, npppd_ctl_who_walk_rd, _this) != 0)
115 return (-1);
116 return (0);
117 }
118
119 int
npppd_ctl_add_started_ppp_id(struct npppd_ctl * _this,u_int ppp_id)120 npppd_ctl_add_started_ppp_id(struct npppd_ctl *_this, u_int ppp_id)
121 {
122 int started_ppp_siz;
123 u_int *started_ppp;
124
125 if (!_this->is_monitoring && !_this->responding)
126 return (-1);
127 if (_this->started_ppp_pos + 1 >= _this->started_ppp_siz) {
128 started_ppp_siz = _this->started_ppp_siz + 128;
129 started_ppp = reallocarray(_this->started_ppp,
130 started_ppp_siz, sizeof(u_int));
131 if (started_ppp == NULL)
132 return (-1);
133 _this->started_ppp = started_ppp;
134 _this->started_ppp_siz = started_ppp_siz;
135 }
136 _this->started_ppp[_this->started_ppp_pos++] = ppp_id;
137
138 /* reset the event */
139
140 return (0);
141 }
142
143 int
npppd_ctl_add_stopped_ppp(struct npppd_ctl * _this,npppd_ppp * ppp)144 npppd_ctl_add_stopped_ppp(struct npppd_ctl *_this, npppd_ppp *ppp)
145 {
146 struct stopped_ppp *stopped;
147
148 if (!_this->is_monitoring)
149 return (-1);
150 if ((stopped = malloc(sizeof(struct stopped_ppp))) == NULL) {
151 log_warn("malloc() failed in %s()", __func__);
152 return (-1);
153 }
154 npppd_who_init(&stopped->ppp_who, ppp);
155 TAILQ_INSERT_TAIL(&_this->stopped_ppps, stopped, entry);
156
157 return (0);
158 }
159
160 static int
npppd_ctl_who_walk_rd(struct radish * rd,void * ctx)161 npppd_ctl_who_walk_rd(struct radish *rd, void *ctx)
162 {
163 struct npppd_ctl *_this = ctx;
164 struct sockaddr_npppd *snp;
165 npppd_ppp *ppp;
166
167 snp = rd->rd_rtent;
168 if (snp->snp_type == SNP_PPP) {
169 ppp = snp->snp_data_ptr;
170 if (npppd_ctl_add_started_ppp_id(_this, ppp->id) != 0)
171 return (-1);
172 }
173
174 return (0);
175 }
176
177 int
npppd_ctl_disconnect(struct npppd_ctl * _this,u_int * ppp_id,int count)178 npppd_ctl_disconnect(struct npppd_ctl *_this, u_int *ppp_id, int count)
179 {
180 int i, n;
181 npppd_ppp *ppp;
182
183 for (n = 0, i = 0; i < count; i++) {
184 if ((ppp = npppd_get_ppp_by_id(_this->npppd, ppp_id[i]))
185 != NULL) {
186 ppp_stop(ppp, NULL);
187 n++;
188 }
189 }
190
191 return (n);
192 }
193
194 int
npppd_ctl_imsg_compose(struct npppd_ctl * _this,struct imsgbuf * ibuf)195 npppd_ctl_imsg_compose(struct npppd_ctl *_this, struct imsgbuf *ibuf)
196 {
197 int i, cnt;
198 u_char pktbuf[MAX_IMSGSIZE - IMSG_HEADER_SIZE];
199 struct npppd_who_list *who_list;
200 npppd_ppp *ppp;
201 struct stopped_ppp *e, *t;
202
203 if (ibuf->w.queued)
204 return (0);
205
206 cnt = 0;
207 if (!TAILQ_EMPTY(&_this->stopped_ppps)) {
208 who_list = (struct npppd_who_list *)pktbuf;
209 who_list->more_data = 0;
210 TAILQ_FOREACH_SAFE(e, &_this->stopped_ppps, entry, t) {
211 if (offsetof(struct npppd_who_list, entry[cnt + 1])
212 > sizeof(pktbuf)) {
213 who_list->more_data = 1;
214 break;
215 }
216 TAILQ_REMOVE(&_this->stopped_ppps, e, entry);
217 memcpy(&who_list->entry[cnt], &e->ppp_who,
218 sizeof(who_list->entry[0]));
219 cnt++;
220 free(e);
221 }
222 who_list->entry_count = cnt;
223 if (imsg_compose(ibuf, IMSG_PPP_STOP, 0, 0, -1, pktbuf,
224 offsetof(struct npppd_who_list, entry[cnt])) == -1)
225 return (-1);
226
227 return (0);
228 }
229 if (_this->responding || _this->started_ppp_pos > 0) {
230 who_list = (struct npppd_who_list *)pktbuf;
231 who_list->more_data = 0;
232 for (cnt = 0, i = 0; i < _this->started_ppp_pos; i++) {
233 if (offsetof(struct npppd_who_list, entry[cnt + 1])
234 > sizeof(pktbuf)) {
235 who_list->more_data = 1;
236 break;
237 }
238 if ((ppp = npppd_get_ppp_by_id(_this->npppd,
239 _this->started_ppp[i])) == NULL)
240 /* may be disconnected */
241 continue;
242 npppd_who_init(&who_list->entry[cnt], ppp);
243 cnt++;
244 }
245 who_list->entry_count = cnt;
246 if (imsg_compose(ibuf, IMSG_PPP_START, 0, 0, -1, pktbuf,
247 offsetof(struct npppd_who_list, entry[cnt])) == -1)
248 return (-1);
249
250 if (_this->started_ppp_pos > i)
251 memmove(&_this->started_ppp[0],
252 &_this->started_ppp[i],
253 sizeof(u_int) *
254 (_this->started_ppp_pos - i));
255 _this->started_ppp_pos -= i;
256 if (who_list->more_data == 0)
257 _this->responding = false;
258 return (0);
259 }
260
261 return (0);
262 }
263
264 static void
npppd_who_init(struct npppd_who * _this,npppd_ppp * ppp)265 npppd_who_init(struct npppd_who *_this, npppd_ppp *ppp)
266 {
267 struct timespec curr_time;
268 npppd_auth_base *realm = ppp->realm;
269 npppd_iface *iface = ppp_iface(ppp);
270
271 strlcpy(_this->username, ppp->username, sizeof(_this->username));
272 _this->time = ppp->start_time;
273 clock_gettime(CLOCK_MONOTONIC, &curr_time);
274 _this->duration_sec = curr_time.tv_sec - ppp->start_monotime;
275 strlcpy(_this->tunnel_proto, npppd_ppp_tunnel_protocol_name(
276 ppp->pppd, ppp), sizeof(_this->tunnel_proto));
277
278 _this->tunnel_peer.peer_in4.sin_family = AF_UNSPEC;
279 if (((struct sockaddr *)&ppp->phy_info)->sa_len > 0) {
280 memcpy(&_this->tunnel_peer, &ppp->phy_info,
281 MINIMUM(sizeof(_this->tunnel_peer),
282 ((struct sockaddr *)&ppp->phy_info)->sa_len));
283 }
284
285 strlcpy(_this->ifname, iface->ifname, sizeof(_this->ifname));
286 if (realm == NULL)
287 _this->rlmname[0] = '\0';
288 else
289 strlcpy(_this->rlmname, npppd_auth_get_name(realm),
290 sizeof(_this->rlmname));
291
292 _this->framed_ip_address = ppp->acct_framed_ip_address;
293 _this->ipackets = ppp->ipackets;
294 _this->opackets = ppp->opackets;
295 _this->ierrors = ppp->ierrors;
296 _this->oerrors = ppp->oerrors;
297 _this->ibytes = ppp->ibytes;
298 _this->obytes = ppp->obytes;
299 _this->ppp_id = ppp->id;
300 _this->mru = ppp->peer_mru;
301
302 #ifdef USE_NPPPD_PIPEX
303 if (ppp->pipex_enabled != 0) {
304 if (npppd_ppp_get_pipex_stat(_this, ppp) != 0) {
305 log_warn(
306 "npppd_ppp_get_pipex_stat() failed in %s",
307 __func__);
308 }
309 }
310 #endif
311 }
312
313 #ifdef USE_NPPPD_PIPEX
314 static int
npppd_ppp_get_pipex_stat(struct npppd_who * _this,npppd_ppp * ppp)315 npppd_ppp_get_pipex_stat(struct npppd_who *_this, npppd_ppp *ppp)
316 {
317 npppd_iface *iface = ppp_iface(ppp);
318 struct pipex_session_stat_req req;
319 #ifdef USE_NPPPD_PPPOE
320 pppoe_session *pppoe;
321 #endif
322 #ifdef USE_NPPPD_PPTP
323 pptp_call *pptp;
324 #endif
325 #ifdef USE_NPPPD_L2TP
326 l2tp_call *l2tp;
327 #endif
328
329 if (ppp->pipex_enabled == 0)
330 return 0;
331
332 memset(&req, 0, sizeof(req));
333 switch(ppp->tunnel_type) {
334 #ifdef USE_NPPPD_PPPOE
335 case NPPPD_TUNNEL_PPPOE:
336 pppoe = (pppoe_session *)ppp->phy_context;
337
338 /* PPPOE specific information */
339 req.psr_protocol = PIPEX_PROTO_PPPOE;
340 req.psr_session_id = pppoe->session_id;
341 break;
342 #endif
343 #ifdef USE_NPPPD_PPTP
344 case NPPPD_TUNNEL_PPTP:
345 pptp = (pptp_call *)ppp->phy_context;
346
347 /* PPTP specific information */
348 req.psr_session_id = pptp->id;
349 req.psr_protocol = PIPEX_PROTO_PPTP;
350 break;
351 #endif
352 #ifdef USE_NPPPD_L2TP
353 case NPPPD_TUNNEL_L2TP:
354 l2tp = (l2tp_call *)ppp->phy_context;
355
356 /* L2TP specific information */
357 req.psr_session_id = l2tp->session_id;
358 req.psr_protocol = PIPEX_PROTO_L2TP;
359 break;
360 #endif
361 default:
362 errno = EINVAL;
363 return 1;
364 }
365
366 /* update statistics in kernel */
367 if (ioctl(iface->devf, PIPEXGSTAT, &req) != 0)
368 return 1;
369
370 _this->ipackets += req.psr_stat.ipackets;
371 _this->opackets += req.psr_stat.opackets;
372 _this->ierrors += req.psr_stat.ierrors;
373 _this->oerrors += req.psr_stat.oerrors;
374 _this->ibytes += req.psr_stat.ibytes;
375 _this->obytes += req.psr_stat.obytes;
376
377 return 0;
378 }
379 #endif
380