1 /*
2 * tun6.c - IPv6 tunnel interface definition
3 */
4
5 /***********************************************************************
6 * Copyright © 2004-2009 Rémi Denis-Courmont. *
7 * This program is free software; you can redistribute and/or modify *
8 * it under the terms of the GNU General Public License as published *
9 * by the Free Software Foundation; version 2 of the license, or (at *
10 * your option) any later version. *
11 * *
12 * This program is distributed in the hope that it will be useful, *
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. *
15 * See the GNU General Public License for more details. *
16 * *
17 * You should have received a copy of the GNU General Public License *
18 * along with this program; if not, you can get it from: *
19 * http://www.gnu.org/copyleft/gpl.html *
20 ***********************************************************************/
21
22 #ifdef HAVE_CONFIG_H
23 # include <config.h>
24 #endif
25
26 #include <gettext.h>
27
28 #include <assert.h>
29
30 #include <stdio.h> // snprintf() for BSD drivers
31 #include <string.h>
32 #include <stdlib.h> // free()
33 #include <inttypes.h>
34
35 #include <sys/types.h>
36 #include <sys/stat.h>
37 #include <fcntl.h>
38 #include <sys/ioctl.h>
39 #include <unistd.h>
40 #include <sys/uio.h> // readv() & writev()
41 #include <syslog.h>
42 #include <errno.h>
43 #include <netinet/in.h> // htons(), struct in6_addr
44
45 #include <sys/socket.h> // socket(AF_INET6, SOCK_DGRAM, 0)
46
47 #include <net/if.h> // struct ifreq, if_nametoindex(), if_indextoname()
48
49 #if defined (__linux__)
50 /*
51 * Linux tunneling driver
52 */
53 const char os_driver[] = "Linux";
54 # define USE_LINUX 1
55
56 # include <linux/if_tun.h> // TUNSETIFF - Linux tunnel driver
57 /*
58 * <linux/ipv6.h> conflicts with <netinet/in.h> and <arpa/inet.h>,
59 * so we've got to declare this structure by hand.
60 */
61 struct in6_ifreq {
62 struct in6_addr ifr6_addr;
63 uint32_t ifr6_prefixlen;
64 int ifr6_ifindex;
65 };
66
67 # include <net/route.h> // struct in6_rtmsg
68 # include <netinet/if_ether.h> // ETH_P_IPV6
69
70 typedef struct
71 {
72 uint16_t flags;
73 uint16_t proto;
74 } tun_head_t;
75
76 # define TUN_HEAD_IPV6_INITIALIZER { 0, htons (ETH_P_IPV6) }
77 # define tun_head_is_ipv6( h ) (h.proto == htons (ETH_P_IPV6))
78
79 #elif defined (__FreeBSD__) || defined (__FreeBSD_kernel__) || \
80 defined (__NetBSD__) || defined (__NetBSD_kernel__) || \
81 defined (__OpenBSD__) || defined (__OpenBSD_kernel__) || \
82 defined (__DragonFly__) || \
83 defined (__APPLE__) /* Darwin */
84 #include <ifaddrs.h>
85 /*
86 * BSD tunneling driver
87 * NOTE: the driver is NOT tested on Darwin (Mac OS X).
88 */
89 const char os_driver[] = "BSD";
90 # define USE_BSD 1
91
92 // Auto-loading
93 # ifdef HAVE_KLDLOAD
94 # include <sys/param.h>
95 # include <sys/linker.h>
96 # endif
97
98 // TUNSIFHEAD or TUNSLMODE
99 # if defined (HAVE_NET_IF_TUN_H)
100 # include <net/if_tun.h>
101 # elif defined (HAVE_NET_TUN_IF_TUN_H)
102 # include <net/tun/if_tun.h>
103 # elif defined (__APPLE__)
104 # define TUNSIFHEAD _IOW('t', 96, int)
105 # endif
106
107 # ifdef HAVE_NET_IF_VAR_H
108 # include <net/if_var.h>
109 # endif
110
111 # include <net/if_dl.h> // struct sockaddr_dl
112 # include <net/route.h> // AF_ROUTE things
113 # include <netinet6/in6_var.h> // struct in6_aliasreq
114 # include <netinet6/nd6.h> // ND6_INFINITE_LIFETIME
115
116 # include <pthread.h>
117
118 typedef uint32_t tun_head_t;
119
120 # define TUN_HEAD_IPV6_INITIALIZER htonl (AF_INET6)
121 # define tun_head_is_ipv6( h ) (h == htonl (AF_INET6))
122
123 #else
124 const char os_driver[] = "Generic";
125
126 # warning Unknown host OS. The driver will probably not work.
127 #endif
128
129 #include <libtun6/tun6.h>
130
131 #define safe_strcpy( tgt, src ) \
132 ((strlcpy (tgt, src, sizeof (tgt)) >= sizeof (tgt)) ? -1 : 0)
133
134 struct tun6
135 {
136 int id, fd, reqfd;
137 #if defined (USE_BSD)
138 char orig_name[IFNAMSIZ];
139 #endif
140 };
141
142 /**
143 * Tries to allocate a tunnel interface from the kernel.
144 *
145 * @param req_name may be an interface name for the virtual network device
146 * (it might be ignored on some OSes).
147 * If NULL, an internal default will be used.
148 *
149 * @return NULL on error.
150 */
tun6_create(const char * req_name)151 tun6 *tun6_create (const char *req_name)
152 {
153 (void)bindtextdomain (PACKAGE_NAME, LOCALEDIR);
154 tun6 *t = (tun6 *)malloc (sizeof (*t));
155 if (t == NULL)
156 return NULL;
157 memset (t, 0, sizeof (*t));
158
159 int reqfd = t->reqfd = socket (AF_INET6, SOCK_DGRAM, 0);
160 if (reqfd == -1)
161 {
162 free (t);
163 return NULL;
164 }
165
166 fcntl (reqfd, F_SETFD, FD_CLOEXEC);
167
168 #if defined (USE_LINUX)
169 /*
170 * TUNTAP (Linux) tunnel driver initialization
171 */
172 static const char tundev[] = "/dev/net/tun";
173 struct ifreq req =
174 {
175 .ifr_flags = IFF_TUN
176 };
177
178 if ((req_name != NULL) && safe_strcpy (req.ifr_name, req_name))
179 {
180 free (t);
181 return NULL;
182 }
183
184 int fd = open (tundev, O_RDWR);
185 if (fd == -1)
186 {
187 syslog (LOG_ERR, _("Tunneling driver error (%s): %m"), tundev);
188 (void)close (reqfd);
189 free (t);
190 return NULL;
191 }
192
193 // Allocates the tunneling virtual network interface
194 if (ioctl (fd, TUNSETIFF, (void *)&req))
195 {
196 syslog (LOG_ERR, _("Tunneling driver error (%s): %m"), "TUNSETIFF");
197 if (errno == EBUSY)
198 syslog (LOG_INFO,
199 _("Please make sure another instance of the program is "
200 "not already running."));
201 goto error;
202 }
203
204 int id = if_nametoindex (req.ifr_name);
205 if (id == 0)
206 goto error;
207 #elif defined (USE_BSD)
208 # ifdef HAVE_KLDLOAD
209 kldload ("if_tun");
210 # endif
211 /*
212 * BSD tunnel driver initialization
213 * (see BSD src/sys/net/if_tun.{c,h})
214 */
215 int fd = open ("/dev/tun", O_RDWR);
216 if ((fd == -1) && (errno == ENOENT))
217 {
218 /*
219 * Some BSD variants or older kernel versions do not support /dev/tun,
220 * so fallback to the old scheme.
221 */
222 int saved_errno = 0;
223 for (unsigned i = 0; fd == -1; i++)
224 {
225 char tundev[5 + IFNAMSIZ];
226 snprintf (tundev, sizeof (tundev), "/dev/tun%u", i);
227
228 fd = open (tundev, O_RDWR);
229 if ((fd == -1) && (errno == ENOENT))
230 // If /dev/tun<i> does not exist,
231 // /dev/tun<i+1> won't exist either
232 break;
233
234 saved_errno = errno;
235 }
236 errno = saved_errno;
237 }
238
239 if (fd == -1)
240 {
241 syslog (LOG_ERR, _("Tunneling driver error (%s): %m"), "/dev/tun*");
242 goto error;
243 }
244 else
245 {
246 struct stat st;
247 fstat (fd, &st);
248 # ifdef HAVE_DEVNAME_R
249 devname_r (st.st_rdev, S_IFCHR, t->orig_name, sizeof (t->orig_name));
250 # else
251 const char *name = devname (st.st_rdev, S_IFCHR);
252 if (safe_strcpy (t->orig_name, name))
253 goto error;
254 # endif
255 }
256
257 int id = if_nametoindex (t->orig_name);
258 if (id == 0)
259 {
260 syslog (LOG_ERR, _("Tunneling driver error (%s): %m"),
261 t->orig_name);
262 goto error;
263 }
264
265 # ifdef TUNSIFMODE
266 /* Sets sensible tunnel type (broadcast rather than point-to-point) */
267 (void)ioctl (fd, TUNSIFMODE, &(int){ IFF_BROADCAST });
268 # endif
269
270 # if defined (TUNSIFHEAD)
271 /* Enables TUNSIFHEAD */
272 if (ioctl (fd, TUNSIFHEAD, &(int){ 1 }))
273 {
274 syslog (LOG_ERR, _("Tunneling driver error (%s): %m"),
275 "TUNSIFHEAD");
276 # if defined (__APPLE__)
277 if (errno == EINVAL)
278 syslog (LOG_NOTICE,
279 "*** Ignoring tun-tap-osx spurious error ***");
280 else
281 # endif
282 goto error;
283 }
284 # elif defined (TUNSLMODE)
285 /* Disables TUNSLMODE (deprecated opposite of TUNSIFHEAD) */
286 if (ioctl (fd, TUNSLMODE, &(int){ 0 }))
287 {
288 syslog (LOG_ERR, _("Tunneling driver error (%s): %m"),
289 "TUNSLMODE");
290 goto error;
291 }
292 #endif
293
294 /* Customizes interface name */
295 if (req_name != NULL)
296 {
297 struct ifreq req;
298 memset (&req, 0, sizeof (req));
299
300 if (if_indextoname (id, req.ifr_name) == NULL)
301 {
302 syslog (LOG_ERR, _("Tunneling driver error (%s): %m"),
303 "if_indextoname");
304 goto error;
305 }
306 else
307 if (strcmp (req.ifr_name, req_name))
308 {
309 #ifdef SIOCSIFNAME
310 char ifname[IFNAMSIZ];
311 req.ifr_data = ifname;
312
313 errno = ENAMETOOLONG;
314 if (safe_strcpy (ifname, req_name)
315 || ioctl (reqfd, SIOCSIFNAME, &req))
316 #else
317 syslog (LOG_DEBUG,
318 "Tunnel interface renaming is not supported on your operating system.\n"
319 "To run miredo properly, you need to remove the InterfaceName directive\n"
320 "from its configuration file.\n");
321 errno = ENOSYS;
322 #endif
323 {
324 syslog (LOG_ERR, _("Tunneling driver error (%s): %m"),
325 "SIOCSIFNAME");
326 goto error;
327 }
328 }
329 }
330 #else
331 # error No tunneling driver implemented on your platform!
332 #endif /* HAVE_os */
333
334 fcntl (fd, F_SETFD, FD_CLOEXEC);
335 /*int val = fcntl (fd, F_GETFL);
336 fcntl (fd, F_SETFL, ((val != -1) ? val : 0) | O_NONBLOCK);*/
337
338 t->id = id;
339 t->fd = fd;
340 return t;
341
342 error:
343 (void)close (reqfd);
344 if (fd != -1)
345 (void)close (fd);
346 syslog (LOG_ERR, _("%s tunneling interface creation failure"), os_driver);
347 free (t);
348 return NULL;
349 }
350
351
352 /**
353 * Removes a tunnel from the kernel.
354 * BEWARE: if you fork, child processes must call tun6_destroy() too.
355 *
356 * The kernel will destroy the tunnel interface once all processes called
357 * tun6_destroy and/or were terminated.
358 */
tun6_destroy(tun6 * t)359 void tun6_destroy (tun6* t)
360 {
361 assert (t != NULL);
362 assert (t->fd != -1);
363 assert (t->reqfd != -1);
364 assert (t->id != 0);
365
366 (void)tun6_setState (t, false);
367
368 #ifdef USE_BSD
369 # ifdef SIOCSIFNAME
370 /*
371 * SIOCSIFDESTROY doesn't work for tunnels (see FreeBSD PR/73673).
372 * We rename the tunnel to its canonical name to ease the life of other
373 * programs that may re-open the tunnel after us.
374 */
375 struct ifreq req;
376 memset (&req, 0, sizeof (req));
377 if (if_indextoname (t->id, req.ifr_name) != NULL)
378 {
379 if (ioctl (t->reqfd, SIOCIFDESTROY, &req))
380 {
381 if ((if_indextoname (t->id, req.ifr_name) != NULL)
382 && strcmp (t->orig_name, req.ifr_name))
383 {
384 req.ifr_data = t->orig_name;
385 (void)ioctl (t->reqfd, SIOCSIFNAME, &req);
386 }
387 }
388 }
389 # endif
390 #endif
391
392 (void)close (t->fd);
393 (void)close (t->reqfd);
394 free (t);
395 }
396
397
398 /*
399 * Unless otherwise stated, all the methods thereafter should return -1 on
400 * error, and 0 on success. Similarly, they should require root privileges.
401 */
402
403 /**
404 * @return the scope id of the tunnel device
405 */
tun6_getId(const tun6 * t)406 int tun6_getId (const tun6 *t)
407 {
408 assert (t != NULL);
409 assert (t-> id != 0);
410
411 return t->id;
412 }
413
414
415 #if defined (USE_LINUX)
416 static int
proc_write_zero(const char * path)417 proc_write_zero (const char *path)
418 {
419 int fd = open (path, O_WRONLY);
420 if (fd == -1)
421 return -1;
422
423 int retval = 0;
424
425 if (write (fd, "0", 1) != 1)
426 retval = -1;
427 if (close (fd))
428 retval = -1;
429
430 return retval;
431 }
432 #endif
433
434
435 /**
436 * Brings a tunnel interface up or down.
437 *
438 * @return 0 on success, -1 on error (see errno).
439 */
440 int
tun6_setState(tun6 * t,bool up)441 tun6_setState (tun6 *t, bool up)
442 {
443 assert (t != NULL);
444 assert (t-> id != 0);
445
446 struct ifreq req;
447 memset (&req, 0, sizeof (req));
448 if ((if_indextoname (t->id, req.ifr_name) == NULL)
449 || ioctl (t->reqfd, SIOCGIFFLAGS, &req))
450 return -1;
451
452 /* settings we want/don't want: */
453 req.ifr_flags |= IFF_NOARP;
454 req.ifr_flags &= ~(IFF_MULTICAST | IFF_BROADCAST);
455 if (up)
456 req.ifr_flags |= IFF_UP | IFF_RUNNING;
457 else
458 req.ifr_flags &= ~(IFF_UP | IFF_RUNNING);
459
460 /* Sets up the interface */
461 if ((if_indextoname (t->id, req.ifr_name) == NULL)
462 || ioctl (t->reqfd, SIOCSIFFLAGS, &req))
463 return -1;
464
465 return 0;
466 }
467
468
469 #if defined (USE_BSD)
470 /**
471 * Converts a prefix length to a netmask (used for the BSD routing)
472 */
473 static void
plen_to_mask(unsigned plen,struct in6_addr * mask)474 plen_to_mask (unsigned plen, struct in6_addr *mask)
475 {
476 assert (plen <= 128);
477
478 div_t d = div (plen, 8);
479 int i = 0;
480
481 while (i < d.quot)
482 mask->s6_addr[i++] = 0xff;
483
484 if (d.rem)
485 mask->s6_addr[i++] = 0xff << (8 - d.rem);
486
487 while (i < 16)
488 mask->s6_addr[i++] = 0;
489 }
490
491
492 static void
plen_to_sin6(unsigned plen,struct sockaddr_in6 * sin6)493 plen_to_sin6 (unsigned plen, struct sockaddr_in6 *sin6)
494 {
495 memset (sin6, 0, sizeof (struct sockaddr_in6));
496
497 sin6->sin6_family = AF_INET6;
498 # ifdef HAVE_SA_LEN
499 sin6->sin6_len = sizeof (struct sockaddr_in6);
500 # endif
501 plen_to_mask (plen, &sin6->sin6_addr);
502 }
503 #endif /* ifdef SOCAIFADDR_IN6 */
504
505
506 static int
_iface_addr(int reqfd,int id,bool add,const struct in6_addr * addr,unsigned prefix_len)507 _iface_addr (int reqfd, int id, bool add,
508 const struct in6_addr *addr, unsigned prefix_len)
509 {
510 void *req = NULL;
511 long cmd = 0;
512
513 assert (reqfd != -1);
514 assert (id != 0);
515
516 if ((prefix_len > 128) || (addr == NULL))
517 return -1;
518
519 #if defined (USE_LINUX)
520 /*
521 * Linux ioctl interface
522 */
523 union
524 {
525 struct in6_ifreq req6;
526 struct ifreq req;
527 } r;
528
529 memset (&r, 0, sizeof (r));
530 r.req6.ifr6_ifindex = id;
531 memcpy (&r.req6.ifr6_addr, addr, sizeof (r.req6.ifr6_addr));
532 r.req6.ifr6_prefixlen = prefix_len;
533
534 cmd = add ? SIOCSIFADDR : SIOCDIFADDR;
535 req = &r;
536 #elif defined (USE_BSD)
537 /*
538 * BSD ioctl interface
539 */
540 union
541 {
542 struct in6_aliasreq addreq6;
543 struct in6_ifreq delreq6;
544 } r;
545
546 if (add)
547 {
548 memset (&r.addreq6, 0, sizeof (r.addreq6));
549 if (if_indextoname (id, r.addreq6.ifra_name) == NULL)
550 return -1;
551 r.addreq6.ifra_addr.sin6_family = AF_INET6;
552 r.addreq6.ifra_addr.sin6_len = sizeof (r.addreq6.ifra_addr);
553 memcpy (&r.addreq6.ifra_addr.sin6_addr, addr,
554 sizeof (r.addreq6.ifra_addr.sin6_addr));
555
556 plen_to_sin6 (prefix_len, &r.addreq6.ifra_prefixmask);
557
558 r.addreq6.ifra_lifetime.ia6t_vltime = ND6_INFINITE_LIFETIME;
559 r.addreq6.ifra_lifetime.ia6t_pltime = ND6_INFINITE_LIFETIME;
560
561 cmd = SIOCAIFADDR_IN6;
562 req = &r.addreq6;
563 }
564 else
565 {
566 memset (&r.delreq6, 0, sizeof (r.delreq6));
567 if (if_indextoname (id, r.delreq6.ifr_name) == NULL)
568 return -1;
569 r.delreq6.ifr_addr.sin6_family = AF_INET6;
570 r.delreq6.ifr_addr.sin6_len = sizeof (r.delreq6.ifr_addr);
571 memcpy (&r.delreq6.ifr_addr.sin6_addr, addr,
572 sizeof (r.delreq6.ifr_addr.sin6_addr));
573
574 cmd = SIOCDIFADDR_IN6;
575 req = &r.delreq6;
576 }
577 #else
578 # error FIXME tunnel address setup not implemented
579 #endif
580
581 return ioctl (reqfd, cmd, req) >= 0 ? 0 : -1;
582 }
583
584
585 static int
_iface_route(int reqfd,int id,bool add,const struct in6_addr * addr,unsigned prefix_len,int rel_metric)586 _iface_route (int reqfd, int id, bool add, const struct in6_addr *addr,
587 unsigned prefix_len, int rel_metric)
588 {
589 assert (reqfd != -1);
590 assert (id != 0);
591
592 if ((prefix_len > 128) || (addr == NULL))
593 return -1;
594
595 int retval = -1;
596
597 #if defined (USE_LINUX)
598 /*
599 * Linux ioctl interface
600 */
601 struct in6_rtmsg req6 =
602 {
603 .rtmsg_flags = RTF_UP,
604 .rtmsg_ifindex = id,
605 .rtmsg_dst_len = (unsigned short)prefix_len,
606 /* By default, the Linux kernel's metric is 256 for subnets,
607 * and 1024 for gatewayed route. */
608 .rtmsg_metric = 1024 + rel_metric
609 };
610
611 /* Adds/deletes route */
612 memcpy (&req6.rtmsg_dst, addr, sizeof (req6.rtmsg_dst));
613 if (prefix_len == 128)
614 req6.rtmsg_flags |= RTF_HOST;
615 /* no gateway */
616
617 if (ioctl (reqfd, add ? SIOCADDRT : SIOCDELRT, &req6) == 0)
618 retval = 0;
619 #elif defined (USE_BSD)
620 /*
621 * BSD routing socket interface
622 * FIXME: metric unimplemented
623 */
624 (void)rel_metric;
625
626 int s = socket (AF_ROUTE, SOCK_RAW, AF_INET6);
627 if (s == -1)
628 {
629 syslog (LOG_ERR, _("Error (%s): %m"), "socket (AF_ROUTE)");
630 return -1;
631 }
632
633 static int rtm_seq = 0;
634 static pthread_mutex_t rtm_seq_mutex = PTHREAD_MUTEX_INITIALIZER;
635 struct
636 {
637 struct rt_msghdr hdr;
638 struct sockaddr_in6 dst;
639 struct sockaddr_storage gw;
640 struct sockaddr_storage dummy; /* allocate space for netmask */
641 } msg;
642
643 shutdown (s, 0);
644
645 memset (&msg, 0, sizeof (msg));
646 msg.hdr.rtm_msglen = sizeof (msg);
647 msg.hdr.rtm_version = RTM_VERSION;
648 msg.hdr.rtm_type = add ? RTM_ADD : RTM_DELETE;
649 msg.hdr.rtm_index = id;
650 msg.hdr.rtm_flags = RTF_UP | RTF_STATIC;
651 msg.hdr.rtm_addrs = RTA_DST | RTA_GATEWAY | RTA_NETMASK;
652 if (prefix_len == 128)
653 msg.hdr.rtm_flags |= RTF_HOST;
654 msg.hdr.rtm_pid = getpid ();
655
656 pthread_mutex_lock (&rtm_seq_mutex);
657 msg.hdr.rtm_seq = ++rtm_seq;
658 pthread_mutex_unlock (&rtm_seq_mutex);
659
660 msg.dst.sin6_family = AF_INET6;
661 msg.dst.sin6_len = sizeof (msg.dst);
662 memcpy (&msg.dst.sin6_addr, addr, sizeof (msg.dst.sin6_addr));
663
664 struct ifaddrs *ifap, *ifa;
665 struct sockaddr_dl *sdl = NULL;
666
667 if (getifaddrs(&ifap))
668 {
669 syslog (LOG_ERR, _("Error (%s): %m"), "getifaddrs");
670 return -1;
671 }
672 for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
673 if (ifa->ifa_addr == NULL)
674 continue;
675 if (ifa->ifa_addr->sa_family != AF_LINK)
676 continue;
677 if (id == ((struct sockaddr_dl *)ifa->ifa_addr)->sdl_index)
678 sdl = (struct sockaddr_dl *)ifa->ifa_addr;
679 }
680 if (sdl == NULL) {
681 syslog (LOG_ERR, "no sdl found");
682 freeifaddrs(ifap);
683 return -1;
684 }
685 memcpy(&msg.gw, sdl, sdl->sdl_len);
686 freeifaddrs(ifap);
687
688 struct sockaddr_in6 *mask = (struct sockaddr_in6 *)((u_char *)&msg.gw + sdl->sdl_len);
689 plen_to_sin6 (prefix_len, mask);
690
691 errno = 0;
692
693 if ((write (s, &msg, sizeof (msg)) == sizeof (msg))
694 && (errno == 0))
695 retval = 0;
696 else if (errno == EEXIST)
697 syslog (LOG_NOTICE,
698 "Miredo could not configure its network tunnel device properly.\n"
699 "There is probably another tunnel with a conflicting route present\n"
700 "(see also FreeBSD PR kern/100080).\n"
701 "Please upgrade to FreeBSD 6.3 or more recent to fix this.\n");
702 else
703 syslog (LOG_NOTICE, "Error creating a route: %m");
704
705 (void)close (s);
706 #else
707 # error FIXME route setup not implemented
708 #endif
709
710 return retval;
711 }
712
713
714 /**
715 * Adds an address with a netmask to a tunnel.
716 * Requires CAP_NET_ADMIN or root privileges.
717 *
718 * @return 0 on success, -1 in case error.
719 */
720 int
tun6_addAddress(tun6 * t,const struct in6_addr * addr,unsigned prefixlen)721 tun6_addAddress (tun6 *t, const struct in6_addr *addr, unsigned prefixlen)
722 {
723 assert (t != NULL);
724
725 int res = _iface_addr (t->reqfd, t->id, true, addr, prefixlen);
726
727 #if defined (USE_LINUX)
728 char ifname[IFNAMSIZ];
729 if ((res == 0)
730 && (if_indextoname (t->id, ifname) != NULL))
731 {
732
733 char proc_path[24 + IFNAMSIZ + 16 + 1] = "/proc/sys/net/ipv6/conf/";
734 # if 0
735 /* Disable Autoconfiguration */
736 snprintf (proc_path + 24, sizeof (proc_path) - 24,
737 "%s/accept_ra", ifname);
738 proc_write_zero (proc_path);
739
740 snprintf (proc_path + 24, sizeof (proc_path) - 24,
741 "%s/autoconf", ifname);
742 proc_write_zero (proc_path);
743 #endif
744 /* Disable ICMPv6 Redirects. */
745 snprintf (proc_path + 24, sizeof (proc_path) - 24,
746 "%s/accept_redirects", ifname);
747 proc_write_zero (proc_path);
748
749 }
750 #endif
751
752 return res;
753 }
754
755 /**
756 * Deletes an address from a tunnel.
757 * Requires CAP_NET_ADMIN or root privileges.
758 *
759 * @return 0 on success, -1 in case error.
760 */
761 int
tun6_delAddress(tun6 * t,const struct in6_addr * addr,unsigned prefixlen)762 tun6_delAddress (tun6 *t, const struct in6_addr *addr, unsigned prefixlen)
763 {
764 assert (t != NULL);
765
766 return _iface_addr (t->reqfd, t->id, false, addr, prefixlen);
767 }
768
769
770 /**
771 * Inserts a route through a tunnel into the IPv6 routing table.
772 * Requires CAP_NET_ADMIN or root privileges.
773 *
774 * @param rel_metric difference between the system's default metric
775 * for route with the speficied prefix length (positive = higher priority,
776 * negative = lower priority).
777 *
778 * @return 0 on success, -1 in case error.
779 */
780 int
tun6_addRoute(tun6 * t,const struct in6_addr * addr,unsigned prefix_len,int rel_metric)781 tun6_addRoute (tun6 *t, const struct in6_addr *addr, unsigned prefix_len,
782 int rel_metric)
783 {
784 assert (t != NULL);
785
786 return _iface_route (t->reqfd, t->id, true, addr, prefix_len, rel_metric);
787 }
788
789
790 /**
791 * Removes a route through a tunnel from the IPv6 routing table.
792 * Requires CAP_NET_ADMIN or root privileges.
793 *
794 * @return 0 on success, -1 in case error.
795 */
796 int
tun6_delRoute(tun6 * t,const struct in6_addr * addr,unsigned prefix_len,int rel_metric)797 tun6_delRoute (tun6 *t, const struct in6_addr *addr, unsigned prefix_len,
798 int rel_metric)
799 {
800 assert (t != NULL);
801
802 return _iface_route (t->reqfd, t->id, false, addr, prefix_len,
803 rel_metric);
804 }
805
806
807 /**
808 * Defines the tunnel interface Max Transmission Unit (bytes).
809 *
810 * @return 0 on success, -1 in case of error.
811 */
812 int
tun6_setMTU(tun6 * t,unsigned mtu)813 tun6_setMTU (tun6 *t, unsigned mtu)
814 {
815 assert (t != NULL);
816
817 if ((mtu < 1280) || (mtu > 65535))
818 return -1;
819
820 struct ifreq req =
821 {
822 .ifr_mtu = mtu
823 };
824 if (if_indextoname (t->id, req.ifr_name) == NULL)
825 return -1;
826
827 return ioctl (t->reqfd, SIOCSIFMTU, &req) ? -1 : 0;
828 }
829
830
831 /**
832 * Registers file descriptors in an fd_set for use with select().
833 * If any of the file descriptors is out of range (>= FD_SETSIZE), it
834 * will not be registered.
835 *
836 * @param readset a fd_set (with FD_SETSIZE no smaller than the default
837 * libc value libtun6 was compiled with).
838 *
839 * @return the "biggest" file descriptor registered (useful as the
840 * first parameter to select()). -1 if any of the file descriptors was
841 * bigger than FD_SETSIZE - 1.
842 */
843 int
tun6_registerReadSet(const tun6 * t,fd_set * readset)844 tun6_registerReadSet (const tun6 *t, fd_set *readset)
845 {
846 assert (t != NULL);
847
848 if (t->fd >= (int)FD_SETSIZE)
849 return -1;
850
851 FD_SET (t->fd, readset);
852 return t->fd;
853 }
854
855
856 /**
857 * Receives a packet from a tunnel device.
858 * @param buffer address to store packet
859 * @param maxlen buffer length in bytes (should be 65535)
860 *
861 * This function will block if there is no input.
862 *
863 * @return the packet length on success, -1 if no packet were to be received.
864 */
865 static inline int
tun6_recv_inner(int fd,void * buffer,size_t maxlen)866 tun6_recv_inner (int fd, void *buffer, size_t maxlen)
867 {
868 struct iovec vect[2];
869 tun_head_t head;
870
871 vect[0].iov_base = (char *)&head;
872 vect[0].iov_len = sizeof (head);
873 vect[1].iov_base = (char *)buffer;
874 vect[1].iov_len = maxlen;
875
876 int len = readv (fd, vect, 2);
877 if ((len < (int)sizeof (head))
878 || !tun_head_is_ipv6 (head))
879 return -1; /* only accept IPv6 packets */
880
881 return len - sizeof (head);
882 }
883
884
885 /**
886 * Checks an fd_set, and receives a packet if available.
887 * @param buffer address to store packet
888 * @param maxlen buffer length in bytes (should be 65535)
889 *
890 * This function will not block if there is no input.
891 * Use tun6_wait_recv() if you want to wait until a packet arrives.
892 *
893 * @return the packet length on success, -1 if no packet were to be received.
894 */
895 int
tun6_recv(tun6 * t,const fd_set * readset,void * buffer,size_t maxlen)896 tun6_recv (tun6 *t, const fd_set *readset, void *buffer, size_t maxlen)
897 {
898 assert (t != NULL);
899
900 int fd = t->fd;
901 if ((fd < (int)FD_SETSIZE) && !FD_ISSET (fd, readset))
902 {
903 errno = EAGAIN;
904 return -1;
905 }
906 return tun6_recv_inner (fd, buffer, maxlen);
907 }
908
909
910 /**
911 * Waits for a packet, and receives it.
912 * @param buffer address to store packet
913 * @param maxlen buffer length in bytes (should be 65535)
914 *
915 * This function will block until a packet arrives or an error occurs.
916 *
917 * @return the packet length on success, -1 if no packet were to be received.
918 */
919 int
tun6_wait_recv(tun6 * t,void * buffer,size_t maxlen)920 tun6_wait_recv (tun6 *t, void *buffer, size_t maxlen)
921 {
922 return tun6_recv_inner (t->fd, buffer, maxlen);
923 }
924
925
926 /**
927 * Sends an IPv6 packet.
928 * @param packet pointer to packet
929 * @param len packet length (bytes)
930 *
931 * @return the number of bytes succesfully transmitted on success,
932 * -1 on error.
933 */
934 int
tun6_send(tun6 * t,const void * packet,size_t len)935 tun6_send (tun6 *t, const void *packet, size_t len)
936 {
937 assert (t != NULL);
938
939 if (len > 65535)
940 return -1;
941
942 tun_head_t head = TUN_HEAD_IPV6_INITIALIZER;
943 struct iovec vect[2];
944 vect[0].iov_base = (char *)&head;
945 vect[0].iov_len = sizeof (head);
946 vect[1].iov_base = (char *)packet; /* necessary cast to non-const */
947 vect[1].iov_len = len;
948
949 int val = writev (t->fd, vect, 2);
950 if (val == -1)
951 return -1;
952
953 val -= sizeof (head);
954 if (val < 0)
955 return -1;
956
957 return val;
958 }
959
960