LTP GCOV extension - code coverage report
Current view: directory - trunk/libtun6 - tun6.c
Test: lcov.info
Date: 2007-05-09 Instrumented lines: 167
Code covered: 13.8 % Executed lines: 23

       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                 : 

Generated by: LTP GCOV extension version 1.5