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