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