npppd_iface.c revision 1.14
1/*	$OpenBSD: npppd_iface.c,v 1.14 2021/01/02 13:15:15 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.14 2021/01/02 13:15:15 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
91static void  npppd_iface_network_input_ipv4(npppd_iface *, struct pppx_hdr *,
92		u_char *, int);
93static void  npppd_iface_network_input(npppd_iface *, u_char *, int);
94static int   npppd_iface_setup_ip(npppd_iface *);
95static void  npppd_iface_io_event_handler (int, short, void *);
96static int   npppd_iface_log (npppd_iface *, int, const char *, ...)
97		__printflike(3,4);
98
99
100/** initialize npppd_iface */
101void
102npppd_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
118static int
119npppd_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;
236fail:
237	if (sock >= 0)
238		close(sock);
239
240	return 1;
241}
242
243/** set tunnel end address */
244int
245npppd_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 */
275int
276npppd_iface_start(npppd_iface *_this)
277{
278	int             x;
279	char            buf[PATH_MAX];
280
281	NPPPD_IFACE_ASSERT(_this != NULL);
282
283	/* open device file */
284	snprintf(buf, sizeof(buf), "/dev/%s", _this->ifname);
285	if ((_this->devf = priv_open(buf, O_RDWR | O_NONBLOCK)) < 0) {
286		npppd_iface_log(_this, LOG_ERR, "open(%s) failed: %m", buf);
287		goto fail;
288	}
289
290	if (_this->using_pppx == 0) {
291		x = IFF_BROADCAST;
292		if (ioctl(_this->devf, TUNSIFMODE, &x) != 0) {
293			npppd_iface_log(_this, LOG_ERR,
294			    "ioctl(TUNSIFMODE=IFF_BROADCAST) failed "
295			    "in %s(): %m", __func__);
296			goto fail;
297		}
298	}
299
300	event_set(&_this->ev, _this->devf, EV_READ | EV_PERSIST,
301	    npppd_iface_io_event_handler, _this);
302	event_add(&_this->ev, NULL);
303
304	if (_this->using_pppx == 0) {
305		if (npppd_iface_setup_ip(_this) != 0)
306			goto fail;
307	}
308
309#ifndef USE_NPPPD_PIPEX
310	if (_this->using_pppx) {
311		npppd_iface_log(_this, LOG_ERR,
312		    "pipex is required when using pppx interface");
313		goto fail;
314	}
315#endif /* USE_NPPPD_PIPEX */
316
317	if (_this->using_pppx) {
318		npppd_iface_log(_this, LOG_INFO, "Started pppx");
319	} else {
320		npppd_iface_log(_this, LOG_INFO, "Started ip4addr=%s",
321			(npppd_iface_ip_is_ready(_this))?
322			    inet_ntop(AF_INET, &_this->ip4addr, buf,
323			    sizeof(buf)) : "(not assigned)");
324	}
325	_this->started = 1;
326
327	return 0;
328fail:
329	if (_this->devf >= 0) {
330		event_del(&_this->ev);
331		close(_this->devf);
332	}
333	_this->devf = -1;
334
335	return -1;
336}
337
338/** stop to use npppd_iface */
339void
340npppd_iface_stop(npppd_iface *_this)
341{
342	struct in_addr gw;
343
344	NPPPD_IFACE_ASSERT(_this != NULL);
345	if (_this->using_pppx == 0) {
346		priv_delete_if_addr(_this->ifname);
347		gw.s_addr = htonl(INADDR_LOOPBACK);
348		in_host_route_delete(&_this->ip4addr, &gw);
349	}
350	if (_this->devf >= 0) {
351		event_del(&_this->ev);
352		close(_this->devf);
353		npppd_iface_log(_this, LOG_INFO, "Stopped");
354	}
355	_this->devf = -1;
356	_this->started = 0;
357	event_del(&_this->ev);
358}
359
360/** finalize npppd_iface */
361void
362npppd_iface_fini(npppd_iface *_this)
363{
364	NPPPD_IFACE_ASSERT(_this != NULL);
365	_this->initialized = 0;
366}
367
368
369/***********************************************************************
370 * I/O related functions
371 ***********************************************************************/
372/** I/O event handler */
373static void
374npppd_iface_io_event_handler(int fd, short evtype, void *data)
375{
376	int sz;
377	u_char buffer[8192];
378	npppd_iface *_this;
379
380	NPPPD_IFACE_ASSERT((evtype & EV_READ) != 0);
381
382	_this = data;
383	NPPPD_IFACE_ASSERT(_this->devf >= 0);
384	do {
385		sz = read(_this->devf, buffer, sizeof(buffer));
386		if (sz <= 0) {
387			if (sz == 0)
388				npppd_iface_log(_this, LOG_ERR,
389				    "file is closed");
390			else if (errno == EAGAIN)
391				break;
392			else
393				npppd_iface_log(_this, LOG_ERR,
394				    "read failed: %m");
395			npppd_iface_stop(_this);
396			return;
397		}
398		npppd_iface_network_input(_this, buffer, sz);
399
400	} while (1 /* CONSTCOND */);
401
402	return;
403}
404
405/** structure of argument of npppd_iface_network_input_delegate */
406struct npppd_iface_network_input_arg{
407	npppd_iface *_this;
408	u_char *pktp;
409	int lpktp;
410};
411
412/** callback function which works for each PPP session */
413static int
414npppd_iface_network_input_delegate(struct radish *radish, void *args0)
415{
416	npppd_ppp *ppp;
417	struct sockaddr_npppd *snp;
418	struct npppd_iface_network_input_arg *args;
419
420	snp = radish->rd_rtent;
421
422	if (snp->snp_type == SNP_PPP) {
423		args = args0;
424		ppp = snp->snp_data_ptr;
425		if (ppp_iface(ppp) != args->_this)
426			return 0;
427#ifdef	USE_NPPPD_MPPE
428		if (MPPE_SEND_READY(ppp)) {
429			/* output via MPPE if MPPE started */
430			mppe_pkt_output(&ppp->mppe, PPP_PROTO_IP, args->pktp,
431			    args->lpktp);
432		} else if (MPPE_IS_REQUIRED(ppp)) {
433			/* in case MPPE not started but MPPE is mandatory, */
434			/* it is not necessary to log because of multicast. */
435			return 0;
436		}
437#endif
438		ppp_output(ppp, PPP_PROTO_IP, 0, 0, args->pktp, args->lpktp);
439	}
440
441	return 0;
442}
443
444static void
445npppd_iface_network_input_ipv4(npppd_iface *_this, struct pppx_hdr *pppx,
446    u_char *pktp, int lpktp)
447{
448	struct ip *iphdr;
449	npppd *_npppd;
450	npppd_ppp *ppp;
451	struct npppd_iface_network_input_arg input_arg;
452
453	NPPPD_IFACE_ASSERT(_this != NULL);
454	NPPPD_IFACE_ASSERT(pktp != NULL);
455
456	iphdr = (struct ip *)pktp;
457	_npppd = _this->npppd;
458
459	if (lpktp < sizeof(iphdr)) {
460		npppd_iface_log(_this, LOG_ERR, "Received short packet.");
461		return;
462	}
463	if (_this->using_pppx)
464		ppp = npppd_get_ppp_by_id(_npppd, pppx->pppx_id);
465	else {
466		if (IN_MULTICAST(ntohl(iphdr->ip_dst.s_addr))) {
467			NPPPD_IFACE_ASSERT(
468			    ((npppd *)(_this->npppd))->rd != NULL);
469			input_arg._this = _this;
470			input_arg.pktp = pktp;
471			input_arg.lpktp = lpktp;
472			/* delegate */
473			rd_walktree(((npppd *)(_this->npppd))->rd,
474			    npppd_iface_network_input_delegate, &input_arg);
475			return;
476		}
477		ppp = npppd_get_ppp_by_ip(_npppd, iphdr->ip_dst);
478	}
479
480	if (ppp == NULL) {
481#ifdef NPPPD_DEBUG
482		log_printf(LOG_INFO, "%s received a packet to unknown "
483		    "%s.", _this->ifname, inet_ntoa(iphdr->ip_dst));
484#endif
485		return;
486	}
487#ifndef NO_ADJUST_MSS
488	if (ppp->adjust_mss) {
489		adjust_tcp_mss(pktp, lpktp, MRU_IPMTU(ppp->peer_mru));
490	}
491#endif
492	if (ppp->timeout_sec > 0 && !ip_is_idle_packet(iphdr, lpktp))
493		ppp_reset_idle_timeout(ppp);
494
495#ifdef	USE_NPPPD_MPPE
496	if (MPPE_SEND_READY(ppp)) {
497		/* output via MPPE if MPPE started */
498		mppe_pkt_output(&ppp->mppe, PPP_PROTO_IP, pktp, lpktp);
499		return;
500	} else if (MPPE_IS_REQUIRED(ppp)) {
501		/* in case MPPE not started but MPPE is mandatory */
502		ppp_log(ppp, LOG_WARNING, "A packet received from network, "
503		    "but MPPE is not started.");
504		return;
505	}
506#endif
507	ppp_output(ppp, PPP_PROTO_IP, 0, 0, pktp, lpktp);
508}
509
510/**
511 * This function is called when an input packet come from network(tun).
512 * Currently, it assumes that it input IPv4 packet.
513 */
514static void
515npppd_iface_network_input(npppd_iface *_this, u_char *pktp, int lpktp)
516{
517	uint32_t af;
518	struct pppx_hdr *pppx = NULL;
519
520	if (_this->using_pppx) {
521		if (lpktp < sizeof(struct pppx_hdr)) {
522			npppd_iface_log(_this, LOG_ERR,
523			    "Received short packet.");
524			return;
525		}
526		pppx = (struct pppx_hdr *)pktp;
527		pktp += sizeof(struct pppx_hdr);
528		lpktp -= sizeof(struct pppx_hdr);
529	}
530
531	if (lpktp < sizeof(uint32_t)) {
532		npppd_iface_log(_this, LOG_ERR, "Received short packet.");
533		return;
534	}
535	GETLONG(af, pktp);
536	lpktp -= sizeof(uint32_t);
537
538	switch (af) {
539	case AF_INET:
540		npppd_iface_network_input_ipv4(_this, pppx, pktp, lpktp);
541		break;
542
543	default:
544		NPPPD_IFACE_ASSERT(0);
545		break;
546
547	}
548}
549
550/** write to tunnel device */
551void
552npppd_iface_write(npppd_iface *_this, npppd_ppp *ppp, int proto, u_char *pktp,
553    int lpktp)
554{
555	int niov = 0, tlen;
556	uint32_t th;
557	struct iovec iov[3];
558	struct pppx_hdr pppx;
559	NPPPD_IFACE_ASSERT(_this != NULL);
560	NPPPD_IFACE_ASSERT(_this->devf >= 0);
561
562	tlen = 0;
563	th = htonl(proto);
564	if (_this->using_pppx) {
565		pppx.pppx_proto = npppd_pipex_proto(ppp->tunnel_type);
566		pppx.pppx_id = ppp->tunnel_session_id;
567		iov[niov].iov_base = &pppx;
568		iov[niov++].iov_len = sizeof(pppx);
569		tlen += sizeof(pppx);
570	}
571	iov[niov].iov_base = &th;
572	iov[niov++].iov_len = sizeof(th);
573	tlen += sizeof(th);
574	iov[niov].iov_base = pktp;
575	iov[niov++].iov_len = lpktp;
576	tlen += lpktp;
577
578	if (writev(_this->devf, iov, niov) != tlen)
579		npppd_iface_log(_this, LOG_ERR, "write failed: %m");
580}
581
582/***********************************************************************
583 * misc functions
584 ***********************************************************************/
585/** Log it which starts the label based on this instance. */
586static int
587npppd_iface_log(npppd_iface *_this, int prio, const char *fmt, ...)
588{
589	int status;
590	char logbuf[BUFSIZ];
591	va_list ap;
592
593	NPPPD_IFACE_ASSERT(_this != NULL);
594
595	va_start(ap, fmt);
596	snprintf(logbuf, sizeof(logbuf), "%s %s", _this->ifname, fmt);
597	status = vlog_printf(prio, logbuf, ap);
598	va_end(ap);
599
600	return status;
601}
602