xref: /openbsd/usr.sbin/npppd/npppd/npppd_ctl.c (revision e83549be)
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