1 /*	$OpenBSD: pppoe_session.c,v 1.12 2021/03/29 03:54:40 yasuoka 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 
29 /**@file
30  * Session management of PPPoE protocol
31  * $Id: pppoe_session.c,v 1.12 2021/03/29 03:54:40 yasuoka Exp $
32  */
33 
34 #include <sys/types.h>
35 #include <sys/socket.h>
36 #include <sys/uio.h>
37 #include <netinet/in.h>
38 #include <net/if.h>
39 #if defined(__NetBSD__)
40 #include <net/if_ether.h>
41 #else
42 #include <netinet/if_ether.h>
43 #endif
44 #include <net/if_dl.h>
45 #include <time.h>
46 #include <string.h>
47 #include <stdlib.h>
48 #include <stdio.h>
49 #include <event.h>
50 #include <syslog.h>
51 #include <stdarg.h>
52 
53 #include "hash.h"
54 #include "slist.h"
55 #include "debugutil.h"
56 #include "bytebuf.h"
57 #include "pppoe.h"
58 #include "pppoe_local.h"
59 
60 #include "npppd.h"
61 #include "ppp.h"
62 
63 #ifdef	PPPOE_SESSION_DEBUG
64 #define	PPPOE_SESSION_ASSERT(x)	ASSERT(x)
65 #define	PPPOE_SESSION_DBG(x)	pppoe_session_log x
66 #else
67 #define	PPPOE_SESSION_ASSERT(x)
68 #define	PPPOE_SESSION_DBG(x)
69 #endif
70 
71 #define	pppoed_listener_this(sess)					\
72 	((pppoed_listener *)slist_get(&(sess)->pppoed->listener, 	\
73 	    (sess)->listener_index))
74 
75 static void  pppoe_session_log (pppoe_session *, int, const char *, ...) __printflike(3,4);
76 static int   pppoe_session_send_PADS (pppoe_session *, struct pppoe_tlv *,
77     struct pppoe_tlv *);
78 static int   pppoe_session_send_PADT (pppoe_session *);
79 static int   pppoe_session_ppp_output (npppd_ppp *, u_char *, int, int);
80 static void  pppoe_session_close_by_ppp(npppd_ppp *);
81 static int   pppoe_session_bind_ppp (pppoe_session *);
82 static void  pppoe_session_dispose_event(int, short, void *);
83 
84 /* Initialize PPPoE session context */
85 int
pppoe_session_init(pppoe_session * _this,pppoed * _pppoed,int idx,int session_id,u_char * ether_addr)86 pppoe_session_init(pppoe_session *_this, pppoed *_pppoed, int idx,
87     int session_id, u_char *ether_addr)
88 {
89 	memset(_this, 0, sizeof(pppoe_session));
90 
91 	_this->pppoed = _pppoed;
92 	_this->session_id = session_id;
93 	_this->listener_index = idx;
94 	memcpy(_this->ether_addr, ether_addr, ETHER_ADDR_LEN);
95 
96 	memcpy(_this->ehdr.ether_dhost, ether_addr, ETHER_ADDR_LEN);
97 	memcpy(_this->ehdr.ether_shost, pppoe_session_sock_ether_addr(_this),
98 	    ETHER_ADDR_LEN);
99 
100 	evtimer_set(&_this->ev_disposing, pppoe_session_dispose_event, _this);
101 
102 	return 0;
103 }
104 
105 /* Disconnect PPPoE session */
106 void
pppoe_session_disconnect(pppoe_session * _this)107 pppoe_session_disconnect(pppoe_session *_this)
108 {
109 	struct timeval tv;
110 
111 	if (_this->state != PPPOE_SESSION_STATE_DISPOSING) {
112 		pppoe_session_send_PADT(_this);
113 
114 		/* free process should be par event */
115 		timerclear(&tv);
116 		evtimer_add(&_this->ev_disposing, &tv);
117 		_this->state = PPPOE_SESSION_STATE_DISPOSING;
118 	}
119 	if (_this->ppp != NULL)
120 		ppp_phy_downed(_this->ppp);
121 }
122 
123 /* Stop PPPoE session */
124 void
pppoe_session_stop(pppoe_session * _this)125 pppoe_session_stop(pppoe_session *_this)
126 {
127 	if (_this->state != PPPOE_SESSION_STATE_DISPOSING)
128 		pppoe_session_disconnect(_this);
129 
130 }
131 
132 /* Finish PPPoE session */
133 void
pppoe_session_fini(pppoe_session * _this)134 pppoe_session_fini(pppoe_session *_this)
135 {
136 	evtimer_del(&_this->ev_disposing);
137 }
138 
139 /* call back function from event(3) */
140 static void
pppoe_session_dispose_event(int fd,short ev,void * ctx)141 pppoe_session_dispose_event(int fd, short ev, void *ctx)
142 {
143 	pppoe_session *_this;
144 
145 	_this = ctx;
146 	pppoed_pppoe_session_close_notify(_this->pppoed, _this);
147 }
148 
149 /*
150  * I/O
151  */
152 void
pppoe_session_input(pppoe_session * _this,u_char * pkt,int lpkt)153 pppoe_session_input(pppoe_session *_this, u_char *pkt, int lpkt)
154 {
155 	int rval;
156 	npppd_ppp *ppp;
157 
158 	ppp = _this->ppp;
159 	if (_this->ppp == NULL)
160 		return;
161 
162 	if (_this->state != PPPOE_SESSION_STATE_RUNNING)
163 		return;
164 
165 	rval = ppp->recv_packet(ppp, pkt, lpkt, 0);
166 	if (_this->ppp == NULL)	/* ppp is freed */
167 		return;
168 
169 	if (rval == 2) {
170 		/*
171 		 * Quit this function before statistics counter
172 		 * is processed when the packet will be processed by
173 		 * PIPEX. Because current NPPPD PPPOE implementation
174 		 * is receiving all packet from BPF even though the
175 		 * PIPEX will process it.
176 		 */
177 	} else if (rval != 0)  {
178 		ppp->ierrors++;
179 	} else {
180 		ppp->ipackets++;
181 		ppp->ibytes += lpkt;
182 	}
183 
184 	return;
185 }
186 
187 static int
pppoe_session_output(pppoe_session * _this,int is_disc,u_char * pkt,int lpkt)188 pppoe_session_output(pppoe_session *_this, int is_disc, u_char *pkt,
189     int lpkt)
190 {
191 	int sz, niov, tlen;
192 	struct iovec iov[4];
193 	struct pppoe_header pppoe0, *pppoe;
194 	char pad[ETHERMIN];
195 
196 
197 	niov = 0;
198 	tlen = 0;
199 	iov[niov].iov_base = &_this->ehdr;
200 	iov[niov++].iov_len = sizeof(_this->ehdr);
201 
202 	if (is_disc) {
203 		_this->ehdr.ether_type = htons(ETHERTYPE_PPPOEDISC);
204 		iov[niov].iov_base = pkt;
205 		iov[niov++].iov_len = lpkt;
206 		pppoe = (struct pppoe_header *)pkt;
207 		pppoe->length = htons(lpkt - sizeof(pppoe0));
208 		tlen += lpkt;
209 	} else {
210 		_this->ehdr.ether_type = htons(ETHERTYPE_PPPOE);
211 		pppoe0.ver = PPPOE_RFC2516_VER;
212 		pppoe0.type = PPPOE_RFC2516_TYPE;
213 		pppoe0.code = 0;
214 		pppoe0.session_id = htons(_this->session_id);
215 		pppoe0.length = htons(lpkt);
216 		iov[niov].iov_base = &pppoe0;
217 		iov[niov++].iov_len = sizeof(pppoe0);
218 		tlen += sizeof(pppoe0);
219 		iov[niov].iov_base = pkt;
220 		iov[niov++].iov_len = lpkt;
221 		tlen += lpkt;
222 	}
223 	if (tlen < ETHERMIN) {
224 		memset(pad, 0, ETHERMIN - tlen);
225 		iov[niov].iov_base = pad;
226 		iov[niov++].iov_len = ETHERMIN - tlen;
227 	}
228 
229 	sz = writev(pppoe_session_sock_bpf(_this), iov, niov);
230 
231 	return (sz > 0)? 0 : -1;
232 }
233 
234 static int
pppoe_session_send_PADT(pppoe_session * _this)235 pppoe_session_send_PADT(pppoe_session *_this)
236 {
237 	u_char bufspace[2048];
238 	bytebuffer *buf;
239 	struct pppoe_header pppoe;
240 	int rval = 0;
241 	struct pppoe_tlv tlv;
242 
243 	if ((buf = bytebuffer_wrap(bufspace, sizeof(bufspace))) == NULL) {
244 		pppoe_session_log(_this, LOG_ERR,
245 		"bytebuffer_wrap() failed on %s(): %m", __func__);
246 		return -1;
247 	}
248 	bytebuffer_clear(buf);
249 
250 	/*
251 	 * PPPoE Header
252 	 */
253 	memset(&pppoe, 0, sizeof(pppoe));
254 	pppoe.ver = PPPOE_RFC2516_VER;
255 	pppoe.type = PPPOE_RFC2516_TYPE;
256 	pppoe.code = PPPOE_CODE_PADT;
257 	pppoe.session_id = htons(_this->session_id);
258 	bytebuffer_put(buf, &pppoe, sizeof(pppoe));
259 
260 	/*
261 	 * Tag - End-of-List
262 	 */
263 	tlv.type = htons(PPPOE_TAG_END_OF_LIST);
264 	tlv.length = 0;
265 	bytebuffer_put(buf, &tlv, sizeof(tlv));
266 	tlv.type = htons(PPPOE_TAG_END_OF_LIST);
267 	tlv.length = 0;
268 	bytebuffer_put(buf, &tlv, sizeof(tlv));
269 
270 	bytebuffer_flip(buf);
271 	if (pppoe_session_output(_this, 1, bytebuffer_pointer(buf),
272 	    bytebuffer_remaining(buf)) != 0) {
273 		pppoe_session_log(_this, LOG_ERR, "pppoed_output failed: %m");
274 		rval = 1;
275 	}
276 	pppoe_session_log(_this, LOG_INFO, "SendPADT");
277 
278 	bytebuffer_unwrap(buf);
279 	bytebuffer_destroy(buf);
280 
281 	return rval;
282 }
283 
284 /* send PADS */
285 static int
pppoe_session_send_PADS(pppoe_session * _this,struct pppoe_tlv * hostuniq,struct pppoe_tlv * service_name)286 pppoe_session_send_PADS(pppoe_session *_this, struct pppoe_tlv *hostuniq,
287     struct pppoe_tlv *service_name)
288 {
289 	int rval, len;
290 	u_char bufspace[2048], msgbuf[80];
291 	bytebuffer *buf;
292 	struct pppoe_header pppoe;
293 	struct pppoe_tlv tlv;
294 
295 	if ((buf = bytebuffer_wrap(bufspace, sizeof(bufspace))) == NULL) {
296 		pppoe_session_log(_this, LOG_ERR,
297 		"bytebuffer_wrap() failed on %s(): %m", __func__);
298 		return -1;
299 	}
300 	bytebuffer_clear(buf);
301 
302 	/*
303 	 * PPPoE Header
304 	 */
305 	memset(&pppoe, 0, sizeof(pppoe));
306 	pppoe.ver = PPPOE_RFC2516_VER;
307 	pppoe.type = PPPOE_RFC2516_TYPE;
308 	pppoe.code = PPPOE_CODE_PADS;
309 	pppoe.session_id = htons(_this->session_id);
310 	bytebuffer_put(buf, &pppoe, sizeof(pppoe));
311 
312 	/*
313 	 * Tag - Service-Name
314 	 */
315 	msgbuf[0] = '\0';
316 	if (service_name != NULL) {
317 		tlv.type = htons(PPPOE_TAG_SERVICE_NAME);
318 		tlv.length = htons(service_name->length);
319 		bytebuffer_put(buf, &tlv, sizeof(tlv));
320 
321 		len = service_name->length;
322 		if (len > 0) {
323 			bytebuffer_put(buf, service_name->value, len);
324 			strlcpy(msgbuf, service_name->value,
325 			    MINIMUM(len + 1, sizeof(msgbuf)));
326 		}
327 	}
328 
329 	/*
330 	 * Tag - Host-Uniq
331 	 */
332 	if (hostuniq != NULL) {
333 		tlv.type = htons(PPPOE_TAG_HOST_UNIQ);
334 		tlv.length = htons(hostuniq->length);
335 		bytebuffer_put(buf, &tlv, sizeof(tlv));
336 		bytebuffer_put(buf, hostuniq->value, hostuniq->length);
337 	}
338 	tlv.type = htons(PPPOE_TAG_END_OF_LIST);
339 	tlv.length = 0;
340 	bytebuffer_put(buf, &tlv, sizeof(tlv));
341 
342 	bytebuffer_flip(buf);
343 	rval = 0;
344 	if (pppoe_session_output(_this, 1, bytebuffer_pointer(buf),
345 	    bytebuffer_remaining(buf)) != 0) {
346 		pppoe_session_log(_this, LOG_ERR, "pppoed_output failed: %m");
347 		rval = 1;
348 	}
349 	pppoe_session_log(_this, LOG_INFO, "SendPADS serviceName=%s "
350 	    "hostUniq=%s", msgbuf,
351 	    hostuniq? pppoed_tlv_value_string(hostuniq) : "none");
352 
353 	bytebuffer_unwrap(buf);
354 	bytebuffer_destroy(buf);
355 
356 	return rval;
357 }
358 
359 /* process PADR from the peer */
360 int
pppoe_session_recv_PADR(pppoe_session * _this,slist * tag_list)361 pppoe_session_recv_PADR(pppoe_session *_this, slist *tag_list)
362 {
363 	pppoed *pppoed0 = _this->pppoed;
364 	struct pppoe_tlv *tlv, *hostuniq, *service_name, *ac_cookie;
365 
366 	service_name = NULL;
367 	hostuniq = NULL;
368 	ac_cookie = NULL;
369 	for (slist_itr_first(tag_list); slist_itr_has_next(tag_list); ) {
370 		tlv = slist_itr_next(tag_list);
371 		if (tlv->type == PPPOE_TAG_HOST_UNIQ)
372 			hostuniq = tlv;
373 		if (tlv->type == PPPOE_TAG_SERVICE_NAME)
374 			service_name = tlv;
375 		if (tlv->type == PPPOE_TAG_AC_COOKIE)
376 			ac_cookie = tlv;
377 	}
378 
379 	if (ac_cookie) {
380 		/* avoid a session which has already has cookie. */
381 		if (hash_lookup(pppoed0->acookie_hash,
382 		    (void *)ac_cookie->value) != NULL)
383 			goto fail;
384 
385 		_this->acookie = *(uint32_t *)(ac_cookie->value);
386 		hash_insert(pppoed0->acookie_hash,
387 			(void *)(intptr_t)_this->acookie, _this);
388 	}
389 
390 	if (pppoe_session_send_PADS(_this, hostuniq, service_name) != 0)
391 		goto fail;
392 
393 	if (pppoe_session_bind_ppp(_this) != 0)
394 		goto fail;
395 
396 	_this->state = PPPOE_SESSION_STATE_RUNNING;
397 	return 0;
398 fail:
399 	return -1;
400 }
401 
402 /* process PADT from the peer */
403 int
pppoe_session_recv_PADT(pppoe_session * _this,slist * tag_list)404 pppoe_session_recv_PADT(pppoe_session *_this, slist *tag_list)
405 {
406 	pppoe_session_log(_this, LOG_INFO, "RecvPADT");
407 
408 	pppoe_session_stop(_this);
409 	_this->state = PPPOE_SESSION_STATE_DISPOSING;
410 
411 	return 0;
412 }
413 
414 /*
415  * Log
416  */
417 static void
pppoe_session_log(pppoe_session * _this,int prio,const char * fmt,...)418 pppoe_session_log(pppoe_session *_this, int prio, const char *fmt, ...)
419 {
420 	char logbuf[BUFSIZ];
421 	va_list ap;
422 
423 	PPPOE_SESSION_ASSERT(_this != NULL);
424 	va_start(ap, fmt);
425 #ifdef	PPPOED_MULTIPLE
426 	snprintf(logbuf, sizeof(logbuf), "pppoed id=%u session=%d %s",
427 	    _this->pppoed->id, _this->session_id, fmt);
428 #else
429 	snprintf(logbuf, sizeof(logbuf), "pppoed if=%s session=%d %s",
430 	    pppoe_session_listen_ifname(_this), _this->session_id, fmt);
431 #endif
432 	vlog_printf(prio, logbuf, ap);
433 	va_end(ap);
434 }
435 
436 /*
437  * PPP
438  */
439 static int
pppoe_session_ppp_output(npppd_ppp * ppp,u_char * pkt,int lpkt,int flag)440 pppoe_session_ppp_output(npppd_ppp *ppp, u_char *pkt, int lpkt, int flag)
441 {
442 	int rval;
443 	pppoe_session *_this;
444 
445 	_this = ppp->phy_context;
446 
447 	rval = pppoe_session_output(_this, 0, pkt, lpkt);
448 
449 	if (_this->ppp == NULL)		/* ppp is freed */
450 		return 0;
451 
452 	if (rval != 0) {
453 		ppp->oerrors++;
454 	} else {
455 		ppp->opackets++;
456 		ppp->obytes += lpkt;
457 	}
458 
459 	return 0;
460 }
461 
462 static void
pppoe_session_close_by_ppp(npppd_ppp * ppp)463 pppoe_session_close_by_ppp(npppd_ppp *ppp)
464 {
465 	pppoe_session *_this;
466 
467 	_this = ppp->phy_context;
468 	PPPOE_SESSION_ASSERT(_this != NULL);
469 	if (_this != NULL)
470 		/* do this before pptp_call_disconnect() */
471 		_this->ppp = NULL;
472 
473 	pppoe_session_disconnect(_this);
474 }
475 
476 /* bind for PPP */
477 static int
pppoe_session_bind_ppp(pppoe_session * _this)478 pppoe_session_bind_ppp(pppoe_session *_this)
479 {
480 	int len;
481 	npppd_ppp *ppp;
482 	struct sockaddr_dl sdl;
483 
484 	ppp = NULL;
485 	if ((ppp = ppp_create()) == NULL)
486 		goto fail;
487 
488 	PPPOE_SESSION_ASSERT(_this->ppp == NULL);
489 
490 	if (_this->ppp != NULL)
491 		return -1;
492 
493 	_this->ppp = ppp;
494 
495 	ppp->tunnel_type = NPPPD_TUNNEL_PPPOE;
496 	ppp->tunnel_session_id = _this->session_id;
497 	ppp->phy_context = _this;
498 	ppp->send_packet = pppoe_session_ppp_output;
499 	ppp->phy_close = pppoe_session_close_by_ppp;
500 
501 	strlcpy(ppp->phy_label, PPPOE_SESSION_LISTENER_TUN_NAME(_this),
502 	    sizeof(ppp->phy_label));
503 
504 	memset(&sdl, 0, sizeof(sdl));
505 	sdl.sdl_len = sizeof(sdl);
506 	sdl.sdl_family = AF_LINK;
507 	sdl.sdl_index = if_nametoindex(pppoe_session_listen_ifname(_this));
508 	len = strlen(pppoe_session_listen_ifname(_this));
509 	memcpy(sdl.sdl_data, pppoe_session_listen_ifname(_this), len);
510 	sdl.sdl_nlen = len;
511 	sdl.sdl_alen = ETHER_ADDR_LEN;
512 	memcpy(sdl.sdl_data + len, _this->ether_addr, ETHER_ADDR_LEN);
513 
514 	memcpy(&ppp->phy_info.peer_dl, &sdl, sizeof(sdl));
515 
516 	if (ppp_init(npppd_get_npppd(), ppp) != 0)
517 		goto fail;
518 	ppp->has_acf = 0;
519 
520 
521 	pppoe_session_log(_this, LOG_NOTICE, "logtype=PPPBind ppp=%d", ppp->id);
522 	ppp_start(ppp);
523 
524 	return 0;
525 fail:
526 	pppoe_session_log(_this, LOG_ERR, "failed binding ppp");
527 
528 	if (ppp != NULL)
529 		ppp_destroy(ppp);
530 	_this->ppp = NULL;
531 
532 	return 1;
533 }
534