xref: /openbsd/usr.sbin/npppd/npppd/npppd_iface.c (revision 178263fa)
1 /*	$OpenBSD: npppd_iface.c,v 1.15 2021/02/01 07:44:58 mvs 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 /* $Id: npppd_iface.c,v 1.15 2021/02/01 07:44:58 mvs Exp $ */
29 /**@file
30  * The interface of npppd and kernel.
31  * This is an implementation to use tun(4) or pppx(4).
32  */
33 #include <sys/types.h>
34 #include <sys/ioctl.h>
35 #include <sys/socket.h>
36 #include <sys/uio.h>
37 #include <sys/sockio.h>
38 #include <netinet/in.h>
39 #include <netinet/ip.h>
40 #include <arpa/inet.h>
41 #include <net/if_dl.h>
42 #include <net/if_tun.h>
43 #include <net/if_types.h>
44 #include <net/if.h>
45 #include <net/pipex.h>
46 
47 #include <fcntl.h>
48 
49 #include <syslog.h>
50 #include <stdio.h>
51 #include <stdlib.h>
52 #include <string.h>
53 #include <unistd.h>
54 #include <errno.h>
55 #include <stdarg.h>
56 
57 #include <time.h>
58 #include <event.h>
59 #include "radish.h"
60 
61 #include "npppd_defs.h"
62 #include "npppd_local.h"
63 #include "npppd_subr.h"
64 #include "debugutil.h"
65 #include "npppd_iface.h"
66 
67 #ifdef USE_NPPPD_PIPEX
68 #include <net/if.h>
69 #if defined(__NetBSD__)
70 #include <net/if_ether.h>
71 #else
72 #include <netinet/if_ether.h>
73 #endif
74 #include <net/pipex.h>
75 #endif /* USE_NPPPD_PIPEX */
76 
77 #ifdef	NPPPD_IFACE_DEBUG
78 #define	NPPPD_IFACE_DBG(x)	npppd_iface_log x
79 #define	NPPPD_IFACE_ASSERT(cond)				\
80 	if (!(cond)) {						\
81 	    fprintf(stderr,					\
82 		"\nASSERT(" #cond ") failed on %s() at %s:%d.\n"\
83 		, __func__, __FILE__, __LINE__);		\
84 	    abort(); 						\
85 	}
86 #else
87 #define	NPPPD_IFACE_ASSERT(cond)
88 #define	NPPPD_IFACE_DBG(x)
89 #endif
90 
91 static void  npppd_iface_network_input_ipv4(npppd_iface *, struct pppx_hdr *,
92 		u_char *, int);
93 static void  npppd_iface_network_input(npppd_iface *, u_char *, int);
94 static int   npppd_iface_setup_ip(npppd_iface *);
95 static void  npppd_iface_io_event_handler (int, short, void *);
96 static int   npppd_iface_log (npppd_iface *, int, const char *, ...)
97 		__printflike(3,4);
98 
99 
100 /** initialize npppd_iface */
101 void
npppd_iface_init(npppd * npppd,npppd_iface * _this,struct iface * iface)102 npppd_iface_init(npppd *npppd, npppd_iface *_this, struct iface *iface)
103 {
104 
105 	NPPPD_IFACE_ASSERT(_this != NULL);
106 	memset(_this, 0, sizeof(npppd_iface));
107 
108 	_this->npppd = npppd;
109 	strlcpy(_this->ifname, iface->name, sizeof(_this->ifname));
110 	_this->using_pppx = iface->is_pppx;
111 	_this->set_ip4addr = 1;
112 	_this->ip4addr = iface->ip4addr;
113 	_this->ipcpconf = iface->ipcpconf;
114 	_this->devf = -1;
115 	_this->initialized = 1;
116 }
117 
118 static int
npppd_iface_setup_ip(npppd_iface * _this)119 npppd_iface_setup_ip(npppd_iface *_this)
120 {
121 	int sock, if_flags, changed;
122 	struct in_addr gw, assigned;
123 	struct sockaddr_in *sin0;
124 	struct ifreq ifr;
125 	struct ifaliasreq ifra;
126 	npppd_ppp *ppp;
127 
128 	NPPPD_IFACE_ASSERT(_this != NULL);
129 
130 	sock = -1;
131 	changed = 0;
132 	memset(&ifr, 0, sizeof(ifr));
133 
134 	/* get address which was assigned to interface */
135 	assigned.s_addr = INADDR_NONE;
136 	memset(&ifr, 0, sizeof(ifr));
137 	memset(&ifra, 0, sizeof(ifra));
138 	strlcpy(ifr.ifr_name, _this->ifname, sizeof(ifr.ifr_name));
139 	strlcpy(ifra.ifra_name, _this->ifname, sizeof(ifra.ifra_name));
140 	sin0 = (struct sockaddr_in *)&ifr.ifr_addr;
141 
142 	if (priv_get_if_addr(_this->ifname, &assigned) != 0) {
143 		if (errno != EADDRNOTAVAIL) {
144 			npppd_iface_log(_this, LOG_ERR,
145 			    "get ip address failed: %m");
146 			goto fail;
147 		}
148 		assigned.s_addr = 0;
149 	}
150 
151 	if (assigned.s_addr != _this->ip4addr.s_addr)
152 		changed = 1;
153 
154 	if (priv_get_if_flags(_this->ifname, &if_flags) != 0) {
155 		npppd_iface_log(_this, LOG_ERR,
156 		    "ioctl(,SIOCGIFFLAGS) failed: %m");
157 		goto fail;
158 	}
159 	if_flags = ifr.ifr_flags;
160 	if (_this->set_ip4addr != 0 && changed) {
161 		do {
162 			struct in_addr dummy;
163 			if (priv_delete_if_addr(_this->ifname) != 0) {
164 				if (errno == EADDRNOTAVAIL)
165 					break;
166 				npppd_iface_log(_this, LOG_ERR,
167 				    "delete ipaddress %s failed: %m",
168 				    _this->ifname);
169 				goto fail;
170 			}
171 			if (priv_get_if_addr(_this->ifname, &dummy) != 0) {
172 				if (errno == EADDRNOTAVAIL)
173 					break;
174 				npppd_iface_log(_this, LOG_ERR,
175 				    "cannot get ipaddress %s failed: %m",
176 				    _this->ifname);
177 				goto fail;
178 			}
179 		} while (1);
180 
181 		/* ifconfig tun1 down */
182 		if (priv_set_if_flags(_this->ifname,
183 		    if_flags & ~(IFF_UP | IFF_BROADCAST)) != 0) {
184 			npppd_iface_log(_this, LOG_ERR,
185 			    "disabling %s failed: %m", _this->ifname);
186 			goto fail;
187 		}
188 		if (priv_set_if_addr(_this->ifname, &_this->ip4addr) != 0 &&
189 		    errno != EEXIST) {
190 			npppd_iface_log(_this, LOG_ERR,
191 			    "Cannot assign tun device ip address: %m");
192 			goto fail;
193 		}
194 		/* erase old route */
195 		if (assigned.s_addr != 0) {
196 			gw.s_addr = htonl(INADDR_LOOPBACK);
197 			in_host_route_delete(&assigned, &gw);
198 		}
199 
200 		assigned.s_addr = _this->ip4addr.s_addr;
201 
202 	}
203 	_this->ip4addr.s_addr = assigned.s_addr;
204 	if (npppd_iface_ip_is_ready(_this)) {
205 		if (changed) {
206 			/*
207 			 * If there is a PPP session which was assigned
208 			 * interface IP address, disconnect it.
209 			 */
210 			ppp = npppd_get_ppp_by_ip(_this->npppd, _this->ip4addr);
211 			if (ppp != NULL) {
212 				npppd_iface_log(_this, LOG_ERR,
213 				    "Assigning %s, but ppp=%d is using "
214 				    "the address. Requested the ppp to stop",
215 				    inet_ntoa(_this->ip4addr), ppp->id);
216 				ppp_stop(ppp, "Administrative reason");
217 			}
218 		}
219 		/* ifconfig tun1 up */
220 		if (priv_set_if_flags(_this->ifname,
221 		    if_flags | IFF_UP | IFF_MULTICAST) != 0) {
222 			npppd_iface_log(_this, LOG_ERR,
223 			    "enabling %s failed: %m", _this->ifname);
224 			goto fail;
225 		}
226 		/*
227 		 * Add routing entry to communicate from host itself to
228 		 * _this->ip4addr.
229 		 */
230 		gw.s_addr = htonl(INADDR_LOOPBACK);
231 		in_host_route_add(&_this->ip4addr, &gw, LOOPBACK_IFNAME, 0);
232 	}
233 	close(sock); sock = -1;
234 
235 	return 0;
236 fail:
237 	if (sock >= 0)
238 		close(sock);
239 
240 	return 1;
241 }
242 
243 /** set tunnel end address */
244 int
npppd_iface_reinit(npppd_iface * _this,struct iface * iface)245 npppd_iface_reinit(npppd_iface *_this, struct iface *iface)
246 {
247 	int rval;
248 	struct in_addr backup;
249 	char buf0[128], buf1[128];
250 
251 	_this->ipcpconf = iface->ipcpconf;
252 	backup = _this->ip4addr;
253 	_this->ip4addr = iface->ip4addr;
254 
255 	if (_this->using_pppx)
256 		return 0;
257 	if ((rval = npppd_iface_setup_ip(_this)) != 0)
258 		return rval;
259 
260 	if (backup.s_addr != _this->ip4addr.s_addr) {
261 		npppd_iface_log(_this, LOG_INFO, "Reinited ip4addr %s=>%s",
262 			(backup.s_addr != INADDR_ANY)
263 			    ?  inet_ntop(AF_INET, &backup, buf0, sizeof(buf0))
264 			    : "(not assigned)",
265 			(_this->ip4addr.s_addr != INADDR_ANY)
266 			    ?  inet_ntop(AF_INET, &_this->ip4addr, buf1,
267 				    sizeof(buf1))
268 			    : "(not assigned)");
269 	}
270 
271 	return 0;
272 }
273 
274 /** start npppd_iface */
275 int
npppd_iface_start(npppd_iface * _this)276 npppd_iface_start(npppd_iface *_this)
277 {
278 	char            buf[PATH_MAX];
279 
280 	NPPPD_IFACE_ASSERT(_this != NULL);
281 
282 	/* open device file */
283 	snprintf(buf, sizeof(buf), "/dev/%s", _this->ifname);
284 	if ((_this->devf = priv_open(buf, O_RDWR | O_NONBLOCK)) < 0) {
285 		npppd_iface_log(_this, LOG_ERR, "open(%s) failed: %m", buf);
286 		goto fail;
287 	}
288 
289 	event_set(&_this->ev, _this->devf, EV_READ | EV_PERSIST,
290 	    npppd_iface_io_event_handler, _this);
291 	event_add(&_this->ev, NULL);
292 
293 	if (_this->using_pppx == 0) {
294 		if (npppd_iface_setup_ip(_this) != 0)
295 			goto fail;
296 	}
297 
298 #ifndef USE_NPPPD_PIPEX
299 	if (_this->using_pppx) {
300 		npppd_iface_log(_this, LOG_ERR,
301 		    "pipex is required when using pppx interface");
302 		goto fail;
303 	}
304 #endif /* USE_NPPPD_PIPEX */
305 
306 	if (_this->using_pppx) {
307 		npppd_iface_log(_this, LOG_INFO, "Started pppx");
308 	} else {
309 		npppd_iface_log(_this, LOG_INFO, "Started ip4addr=%s",
310 			(npppd_iface_ip_is_ready(_this))?
311 			    inet_ntop(AF_INET, &_this->ip4addr, buf,
312 			    sizeof(buf)) : "(not assigned)");
313 	}
314 	_this->started = 1;
315 
316 	return 0;
317 fail:
318 	if (_this->devf >= 0) {
319 		event_del(&_this->ev);
320 		close(_this->devf);
321 	}
322 	_this->devf = -1;
323 
324 	return -1;
325 }
326 
327 /** stop to use npppd_iface */
328 void
npppd_iface_stop(npppd_iface * _this)329 npppd_iface_stop(npppd_iface *_this)
330 {
331 	struct in_addr gw;
332 
333 	NPPPD_IFACE_ASSERT(_this != NULL);
334 	if (_this->using_pppx == 0) {
335 		priv_delete_if_addr(_this->ifname);
336 		gw.s_addr = htonl(INADDR_LOOPBACK);
337 		in_host_route_delete(&_this->ip4addr, &gw);
338 	}
339 	if (_this->devf >= 0) {
340 		event_del(&_this->ev);
341 		close(_this->devf);
342 		npppd_iface_log(_this, LOG_INFO, "Stopped");
343 	}
344 	_this->devf = -1;
345 	_this->started = 0;
346 	event_del(&_this->ev);
347 }
348 
349 /** finalize npppd_iface */
350 void
npppd_iface_fini(npppd_iface * _this)351 npppd_iface_fini(npppd_iface *_this)
352 {
353 	NPPPD_IFACE_ASSERT(_this != NULL);
354 	_this->initialized = 0;
355 }
356 
357 
358 /***********************************************************************
359  * I/O related functions
360  ***********************************************************************/
361 /** I/O event handler */
362 static void
npppd_iface_io_event_handler(int fd,short evtype,void * data)363 npppd_iface_io_event_handler(int fd, short evtype, void *data)
364 {
365 	int sz;
366 	u_char buffer[8192];
367 	npppd_iface *_this;
368 
369 	NPPPD_IFACE_ASSERT((evtype & EV_READ) != 0);
370 
371 	_this = data;
372 	NPPPD_IFACE_ASSERT(_this->devf >= 0);
373 	do {
374 		sz = read(_this->devf, buffer, sizeof(buffer));
375 		if (sz <= 0) {
376 			if (sz == 0)
377 				npppd_iface_log(_this, LOG_ERR,
378 				    "file is closed");
379 			else if (errno == EAGAIN)
380 				break;
381 			else
382 				npppd_iface_log(_this, LOG_ERR,
383 				    "read failed: %m");
384 			npppd_iface_stop(_this);
385 			return;
386 		}
387 		npppd_iface_network_input(_this, buffer, sz);
388 
389 	} while (1 /* CONSTCOND */);
390 
391 	return;
392 }
393 
394 /** structure of argument of npppd_iface_network_input_delegate */
395 struct npppd_iface_network_input_arg{
396 	npppd_iface *_this;
397 	u_char *pktp;
398 	int lpktp;
399 };
400 
401 /** callback function which works for each PPP session */
402 static int
npppd_iface_network_input_delegate(struct radish * radish,void * args0)403 npppd_iface_network_input_delegate(struct radish *radish, void *args0)
404 {
405 	npppd_ppp *ppp;
406 	struct sockaddr_npppd *snp;
407 	struct npppd_iface_network_input_arg *args;
408 
409 	snp = radish->rd_rtent;
410 
411 	if (snp->snp_type == SNP_PPP) {
412 		args = args0;
413 		ppp = snp->snp_data_ptr;
414 		if (ppp_iface(ppp) != args->_this)
415 			return 0;
416 #ifdef	USE_NPPPD_MPPE
417 		if (MPPE_SEND_READY(ppp)) {
418 			/* output via MPPE if MPPE started */
419 			mppe_pkt_output(&ppp->mppe, PPP_PROTO_IP, args->pktp,
420 			    args->lpktp);
421 		} else if (MPPE_IS_REQUIRED(ppp)) {
422 			/* in case MPPE not started but MPPE is mandatory, */
423 			/* it is not necessary to log because of multicast. */
424 			return 0;
425 		}
426 #endif
427 		ppp_output(ppp, PPP_PROTO_IP, 0, 0, args->pktp, args->lpktp);
428 	}
429 
430 	return 0;
431 }
432 
433 static void
npppd_iface_network_input_ipv4(npppd_iface * _this,struct pppx_hdr * pppx,u_char * pktp,int lpktp)434 npppd_iface_network_input_ipv4(npppd_iface *_this, struct pppx_hdr *pppx,
435     u_char *pktp, int lpktp)
436 {
437 	struct ip *iphdr;
438 	npppd *_npppd;
439 	npppd_ppp *ppp;
440 	struct npppd_iface_network_input_arg input_arg;
441 
442 	NPPPD_IFACE_ASSERT(_this != NULL);
443 	NPPPD_IFACE_ASSERT(pktp != NULL);
444 
445 	iphdr = (struct ip *)pktp;
446 	_npppd = _this->npppd;
447 
448 	if (lpktp < sizeof(iphdr)) {
449 		npppd_iface_log(_this, LOG_ERR, "Received short packet.");
450 		return;
451 	}
452 	if (_this->using_pppx)
453 		ppp = npppd_get_ppp_by_id(_npppd, pppx->pppx_id);
454 	else {
455 		if (IN_MULTICAST(ntohl(iphdr->ip_dst.s_addr))) {
456 			NPPPD_IFACE_ASSERT(
457 			    ((npppd *)(_this->npppd))->rd != NULL);
458 			input_arg._this = _this;
459 			input_arg.pktp = pktp;
460 			input_arg.lpktp = lpktp;
461 			/* delegate */
462 			rd_walktree(((npppd *)(_this->npppd))->rd,
463 			    npppd_iface_network_input_delegate, &input_arg);
464 			return;
465 		}
466 		ppp = npppd_get_ppp_by_ip(_npppd, iphdr->ip_dst);
467 	}
468 
469 	if (ppp == NULL) {
470 #ifdef NPPPD_DEBUG
471 		log_printf(LOG_INFO, "%s received a packet to unknown "
472 		    "%s.", _this->ifname, inet_ntoa(iphdr->ip_dst));
473 #endif
474 		return;
475 	}
476 #ifndef NO_ADJUST_MSS
477 	if (ppp->adjust_mss) {
478 		adjust_tcp_mss(pktp, lpktp, MRU_IPMTU(ppp->peer_mru));
479 	}
480 #endif
481 	if (ppp->timeout_sec > 0 && !ip_is_idle_packet(iphdr, lpktp))
482 		ppp_reset_idle_timeout(ppp);
483 
484 #ifdef	USE_NPPPD_MPPE
485 	if (MPPE_SEND_READY(ppp)) {
486 		/* output via MPPE if MPPE started */
487 		mppe_pkt_output(&ppp->mppe, PPP_PROTO_IP, pktp, lpktp);
488 		return;
489 	} else if (MPPE_IS_REQUIRED(ppp)) {
490 		/* in case MPPE not started but MPPE is mandatory */
491 		ppp_log(ppp, LOG_WARNING, "A packet received from network, "
492 		    "but MPPE is not started.");
493 		return;
494 	}
495 #endif
496 	ppp_output(ppp, PPP_PROTO_IP, 0, 0, pktp, lpktp);
497 }
498 
499 /**
500  * This function is called when an input packet come from network(tun).
501  * Currently, it assumes that it input IPv4 packet.
502  */
503 static void
npppd_iface_network_input(npppd_iface * _this,u_char * pktp,int lpktp)504 npppd_iface_network_input(npppd_iface *_this, u_char *pktp, int lpktp)
505 {
506 	uint32_t af;
507 	struct pppx_hdr *pppx = NULL;
508 
509 	if (_this->using_pppx) {
510 		if (lpktp < sizeof(struct pppx_hdr)) {
511 			npppd_iface_log(_this, LOG_ERR,
512 			    "Received short packet.");
513 			return;
514 		}
515 		pppx = (struct pppx_hdr *)pktp;
516 		pktp += sizeof(struct pppx_hdr);
517 		lpktp -= sizeof(struct pppx_hdr);
518 	}
519 
520 	if (lpktp < sizeof(uint32_t)) {
521 		npppd_iface_log(_this, LOG_ERR, "Received short packet.");
522 		return;
523 	}
524 	GETLONG(af, pktp);
525 	lpktp -= sizeof(uint32_t);
526 
527 	switch (af) {
528 	case AF_INET:
529 		npppd_iface_network_input_ipv4(_this, pppx, pktp, lpktp);
530 		break;
531 
532 	default:
533 		NPPPD_IFACE_ASSERT(0);
534 		break;
535 
536 	}
537 }
538 
539 /** write to tunnel device */
540 void
npppd_iface_write(npppd_iface * _this,npppd_ppp * ppp,int proto,u_char * pktp,int lpktp)541 npppd_iface_write(npppd_iface *_this, npppd_ppp *ppp, int proto, u_char *pktp,
542     int lpktp)
543 {
544 	int niov = 0, tlen;
545 	uint32_t th;
546 	struct iovec iov[3];
547 	struct pppx_hdr pppx;
548 	NPPPD_IFACE_ASSERT(_this != NULL);
549 	NPPPD_IFACE_ASSERT(_this->devf >= 0);
550 
551 	tlen = 0;
552 	th = htonl(proto);
553 	if (_this->using_pppx) {
554 		pppx.pppx_proto = npppd_pipex_proto(ppp->tunnel_type);
555 		pppx.pppx_id = ppp->tunnel_session_id;
556 		iov[niov].iov_base = &pppx;
557 		iov[niov++].iov_len = sizeof(pppx);
558 		tlen += sizeof(pppx);
559 	}
560 	iov[niov].iov_base = &th;
561 	iov[niov++].iov_len = sizeof(th);
562 	tlen += sizeof(th);
563 	iov[niov].iov_base = pktp;
564 	iov[niov++].iov_len = lpktp;
565 	tlen += lpktp;
566 
567 	if (writev(_this->devf, iov, niov) != tlen)
568 		npppd_iface_log(_this, LOG_ERR, "write failed: %m");
569 }
570 
571 /***********************************************************************
572  * misc functions
573  ***********************************************************************/
574 /** Log it which starts the label based on this instance. */
575 static int
npppd_iface_log(npppd_iface * _this,int prio,const char * fmt,...)576 npppd_iface_log(npppd_iface *_this, int prio, const char *fmt, ...)
577 {
578 	int status;
579 	char logbuf[BUFSIZ];
580 	va_list ap;
581 
582 	NPPPD_IFACE_ASSERT(_this != NULL);
583 
584 	va_start(ap, fmt);
585 	snprintf(logbuf, sizeof(logbuf), "%s %s", _this->ifname, fmt);
586 	status = vlog_printf(prio, logbuf, ap);
587 	va_end(ap);
588 
589 	return status;
590 }
591