LTP GCOV extension - code coverage report
Current view: directory - trunk/libteredo - teredo.c
Test: lcov.info
Date: 2007-05-09 Instrumented lines: 104
Code covered: 9.6 % Executed lines: 10

       1                 : /*
       2                 :  * teredo.c - Common Teredo helper functions
       3                 :  * $Id: teredo.c 1946 2007-04-10 19:23:59Z remi $
       4                 :  *
       5                 :  * See "Teredo: Tunneling IPv6 over UDP through NATs"
       6                 :  * for more information
       7                 :  */
       8                 : 
       9                 : /***********************************************************************
      10                 :  *  Copyright © 2004-2007 Rémi Denis-Courmont.                         *
      11                 :  *  This program is free software; you can redistribute and/or modify  *
      12                 :  *  it under the terms of the GNU General Public License as published  *
      13                 :  *  by the Free Software Foundation; version 2 of the license.         *
      14                 :  *                                                                     *
      15                 :  *  This program is distributed in the hope that it will be useful,    *
      16                 :  *  but WITHOUT ANY WARRANTY; without even the implied warranty of     *
      17                 :  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.               *
      18                 :  *  See the GNU General Public License for more details.               *
      19                 :  *                                                                     *
      20                 :  *  You should have received a copy of the GNU General Public License  *
      21                 :  *  along with this program; if not, you can get it from:              *
      22                 :  *  http://www.gnu.org/copyleft/gpl.html                               *
      23                 :  ***********************************************************************/
      24                 : 
      25                 : #ifdef HAVE_CONFIG_H
      26                 : # include <config.h>
      27                 : #endif
      28                 : 
      29                 : #include <string.h> // memcpy()
      30                 : 
      31                 : #include <inttypes.h> /* for Mac OS X */
      32                 : #include <sys/types.h>
      33                 : #include <sys/uio.h>
      34                 : #include <netinet/in.h>
      35                 : #include <netinet/ip6.h>
      36                 : 
      37                 : #include <fcntl.h>
      38                 : #include <sys/socket.h>
      39                 : #include <errno.h>
      40                 : 
      41                 : #ifndef SOL_IP
      42                 : # define SOL_IP IPPROTO_IP
      43                 : #endif
      44                 : 
      45                 : #include "teredo.h"
      46                 : #include "teredo-udp.h"
      47                 : 
      48                 : /*
      49                 :  * Teredo addresses
      50                 :  */
      51                 : const struct in6_addr teredo_restrict =
      52                 :         /* Vista variant */
      53                 : { { { 0xfe, 0x80, 0, 0, 0, 0, 0, 0,
      54                 :         0, 0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff } } };
      55                 : 
      56                 :         /* XP variant */
      57                 : //      { { { 0xfe, 0x80, 0, 0, 0, 0, 0, 0,
      58                 : //                  0, 0, 'T', 'E', 'R', 'E', 'D', 'O' } } };
      59                 : 
      60                 : const struct in6_addr teredo_cone =
      61                 :         { { { 0xfe, 0x80, 0, 0, 0, 0, 0, 0,
      62                 :                     0x80, 0, 'T', 'E', 'R', 'E', 'D', 'O' } } };
      63                 : 
      64                 : /**
      65                 :  * Opens a Teredo UDP/IPv4 socket.
      66                 :  * Thread-safe, not cancellation-safe.
      67                 :  *
      68                 :  * @return -1 on error.
      69                 :  */
      70                 : int teredo_socket (uint32_t bind_ip, uint16_t port)
      71               1 : {
      72                 :         struct sockaddr_in myaddr =
      73                 :         {
      74                 :                 .sin_family = AF_INET,
      75                 : #ifdef HAVE_SA_LEN
      76                 :                 .sin_len = sizeof (struct sockaddr_in),
      77                 : #endif
      78                 :                 .sin_port = port,
      79                 :                 .sin_addr.s_addr = bind_ip
      80               1 :         };
      81                 : 
      82               1 :         int fd = socket (AF_INET, SOCK_DGRAM, IPPROTO_UDP);
      83               1 :         if (fd == -1)
      84               0 :                 return -1; // failure
      85                 : 
      86               1 :         fcntl (fd, F_SETFD, FD_CLOEXEC);
      87               1 :         setsockopt (fd, SOL_SOCKET, SO_REUSEADDR, &(int){ 1 }, sizeof (int));
      88                 : 
      89               1 :         if (bind (fd, (struct sockaddr *)&myaddr, sizeof (myaddr)))
      90                 :         {
      91               0 :                 close (fd);
      92               0 :                 return -1;
      93                 :         }
      94                 : 
      95                 : #ifdef IP_PMTUDISC_DONT
      96                 :         /* 
      97                 :          * This tells the (Linux) kernel not to set the Don't Fragment flags
      98                 :          * on UDP packets we send. This is recommended by the Teredo
      99                 :          * specifiation.
     100                 :          */
     101               1 :         setsockopt (fd, SOL_IP, IP_MTU_DISCOVER, &(int){ IP_PMTUDISC_DONT },
     102                 :                     sizeof (int));
     103                 : #endif
     104                 :         /*
     105                 :          * Teredo multicast packets always have a TTL of 1.
     106                 :          */
     107               1 :         setsockopt (fd, SOL_IP, IP_MULTICAST_TTL, &(int){ 1 }, sizeof (int));
     108               1 :         return fd;
     109                 : }
     110                 : 
     111                 : 
     112                 : /**
     113                 :  * Sends an UDP/IPv4 datagram.
     114                 :  * Thread-safe, cancellation-safe, cancellation point.
     115                 :  *
     116                 :  * @param fd socket from which to send.
     117                 :  * @param iov scatter-gather array containing the datagram payload.
     118                 :  * @param count number of entry in the scatter-gather array.
     119                 :  * @param dest_ip destination IPv4 (network byte order).
     120                 :  * @param dest_port destination UDP port (network byte order).
     121                 :  *
     122                 :  * @return number of bytes sent or -1 on error.
     123                 :  */
     124                 : 
     125                 : int teredo_sendv (int fd, const struct iovec *iov, size_t count,
     126                 :                   uint32_t dest_ip, uint16_t dest_port)
     127               0 : {
     128                 :         struct sockaddr_in addr =
     129                 :         {
     130                 :                 .sin_family = AF_INET,
     131                 : #ifdef HAVE_SA_LEN
     132                 :                 .sin_len = sizeof (struct sockaddr_in),
     133                 : #endif
     134                 :                 .sin_port = dest_port,
     135                 :                 .sin_addr.s_addr = dest_ip
     136               0 :         };
     137                 : 
     138                 :         struct msghdr msg =
     139                 :         {
     140                 :                 .msg_name = &addr,
     141                 :                 .msg_namelen = sizeof (addr),
     142                 :                 .msg_iov = (struct iovec *)iov,
     143                 :                 .msg_iovlen = count
     144               0 :         };
     145                 : 
     146               0 :         for (int tries = 0; tries < 10; tries++)
     147                 :         {
     148               0 :                 int res = sendmsg (fd, &msg, 0);
     149               0 :                 if (res != -1)
     150               0 :                         return res;
     151                 :                 /*
     152                 :                  * NOTE:
     153                 :                  * We must ignore ICMP errors returned by sendto() because they are
     154                 :                  * asynchronous, so that in most case they refer to a packet which was
     155                 :                  * sent earlier already, most likely to another destination.
     156                 :                  * That means we also ignore EHOSTUNREACH when it is generated by the
     157                 :                  * kernel routing table (meaning we are not attached to the network);
     158                 :                  * while it would have been a good idea to handle that case properly.
     159                 :                  * There does not seem to be any sane solution to this issue.
     160                 :                  *
     161                 :                  * NOTE 2:
     162                 :                  * To prevent an infinite loop in case of a really unreachable
     163                 :                  * destination, we must have a limit on the number of sendto()
     164                 :                  * attempts.
     165                 :                  */
     166               0 :                 switch (errno)
     167                 :                 {
     168                 :                         /*case EMSGSIZE:*/ /* ICMP fragmentation needed *
     169                 :                          * given we don't ensure that the length is below 65507, we
     170                 :                          * must not ignore that error */
     171                 :                         case ENETUNREACH: /* ICMP address unreachable */
     172                 :                         case EHOSTUNREACH: /* ICMP destination unreachable */
     173                 :                         case ENOPROTOOPT: /* ICMP protocol unreachable */
     174                 :                         case ECONNREFUSED: /* ICMP port unreachable */
     175                 :                         case EOPNOTSUPP: /* ICMP source route failed
     176                 :                                                         - should not happen */
     177                 :                         case EHOSTDOWN: /* ICMP host unknown */
     178                 : #ifdef ENONET
     179                 :                         case ENONET: /* ICMP host isolated */
     180                 : #endif
     181                 :                                 continue;
     182                 :         
     183                 :                         default:
     184               0 :                                 return -1; /* hard error */
     185                 :                 }
     186                 :         }
     187                 : 
     188               0 :         return -1;
     189                 : }
     190                 : 
     191                 : 
     192                 : /**
     193                 :  * Sends an UDP/IPv4 datagram.
     194                 :  * Thread-safe, cancellation safe, cancellation point.
     195                 :  *
     196                 :  * @return number of bytes sent, or -1 on error.
     197                 :  */
     198                 : int teredo_send (int fd, const void *packet, size_t plen,
     199                 :                  uint32_t dest_ip, uint16_t dest_port)
     200               0 : {
     201               0 :         struct iovec iov = { (void *)packet, plen };
     202               0 :         return teredo_sendv (fd, &iov, 1, dest_ip, dest_port);
     203                 : }
     204                 : 
     205                 : 
     206                 : static int teredo_recv_inner (int fd, struct teredo_packet *p, int flags)
     207               0 : {
     208                 :         // Receive a UDP packet
     209                 :         struct sockaddr_in ad;
     210                 :         int length = recvfrom (fd, p->buf, sizeof (p->buf), flags,
     211                 :                                (struct sockaddr *)&ad,
     212               0 :                                &(socklen_t){ sizeof (ad) });
     213                 : 
     214               0 :         if (length < 2) // too small or error
     215               0 :                 return -1;
     216                 : 
     217               0 :         p->source_ipv4 = ad.sin_addr.s_addr;
     218               0 :         p->source_port = ad.sin_port;
     219                 : 
     220               0 :         uint8_t *ptr = p->buf;
     221                 : 
     222               0 :         p->auth_nonce = NULL;
     223               0 :         p->auth_conf_byte = 0;
     224               0 :         p->orig_ipv4 = 0;
     225               0 :         p->orig_port = 0;
     226                 : 
     227                 :         // Teredo Authentication header
     228               0 :         if ((ptr[0] == 0) && (ptr[1] == teredo_auth_hdr))
     229                 :         {
     230                 :                 uint8_t id_len, au_len;
     231                 : 
     232               0 :                 length -= 13;
     233               0 :                 if (length < 0)
     234               0 :                         return -1; // too small
     235               0 :                 ptr += 2;
     236                 : 
     237                 :                 /* ID and Auth */
     238               0 :                 id_len = *ptr++;
     239               0 :                 au_len = *ptr++;
     240                 : 
     241                 :                 /* TODO: secure qualification */
     242               0 :                 length -= id_len + au_len;
     243               0 :                 if (length < 0)
     244               0 :                         return -1;
     245               0 :                 ptr += id_len + au_len;
     246                 : 
     247                 : 
     248                 :                 /* Nonce + confirmation byte */
     249               0 :                 p->auth_nonce = ptr;
     250               0 :                 ptr += 8;
     251               0 :                 p->auth_conf_byte = *ptr++;
     252                 :         }
     253                 : 
     254                 :         // Teredo Origin Indication
     255               0 :         if ((ptr[0] == 0) && (ptr[1] == teredo_orig_ind))
     256                 :         {
     257                 :                 uint32_t addr;
     258                 :                 uint16_t port;
     259                 : 
     260               0 :                 length -= 8;
     261               0 :                 if (length < 0)
     262               0 :                         return -1; /* too small */
     263               0 :                 ptr += 2;
     264                 : 
     265                 :                 /* Obfuscated port */
     266               0 :                 memcpy (&port, ptr, 2);
     267               0 :                 ptr += 2;
     268               0 :                 p->orig_port = ~port;
     269                 : 
     270                 :                 /* Obfuscated IPv4 */
     271               0 :                 memcpy (&addr, ptr, 4);
     272               0 :                 ptr += 4;
     273               0 :                 p->orig_ipv4 = ~addr;
     274                 :         }
     275                 : 
     276                 :         /* length <= 65507 = sizeof(buf) */
     277               0 :         p->ip6_len = length;
     278               0 :         p->ip6 = ptr;
     279                 : 
     280               0 :         return 0;
     281                 : }
     282                 : 
     283                 : 
     284                 : /**
     285                 :  * Receives and parses a Teredo packet from a socket. Never blocks.
     286                 :  * Thread-safe, cancellation-safe, cancellation point.
     287                 :  *
     288                 :  * @param fd socket file descriptor
     289                 :  * @param p teredo_packet receive buffer
     290                 :  *
     291                 :  * @return 0 on success, -1 in error.
     292                 :  * Errors might be caused by :
     293                 :  *  - lower level network I/O,
     294                 :  *  - malformatted packets,
     295                 :  *  - no data pending.
     296                 :  */
     297                 : int teredo_recv (int fd, struct teredo_packet *p)
     298               0 : {
     299               0 :         return teredo_recv_inner (fd, p, MSG_DONTWAIT);
     300                 : }
     301                 : 
     302                 : 
     303                 : #if defined (__FreeBSD__) || defined (__APPLE__)
     304                 : # define HAVE_BROKEN_RECVFROM 1
     305                 : # include <sys/poll.h>
     306                 : #endif
     307                 : 
     308                 : /**
     309                 :  * Waits for, receives and parses a Teredo packet from a socket.
     310                 :  * Thread-safe, cancellation-safe, cancellation point.
     311                 :  *
     312                 :  * @param fd socket file descriptor
     313                 :  * @param p teredo_packet receive buffer
     314                 :  *
     315                 :  * @return 0 on success, -1 in error.
     316                 :  * Errors might be caused by :
     317                 :  *  - lower level network I/O,
     318                 :  *  - malformatted packets,
     319                 :  *  - a race condition if two thread are waiting on the same
     320                 :  *    non-blocking socket for receiving.
     321                 :  */
     322                 : int teredo_wait_recv (int fd, struct teredo_packet *p)
     323               0 : {
     324                 : #ifdef HAVE_BROKEN_RECVFROM
     325                 :         // recvfrom() is not a cancellation point on FreeBSD 6.1...
     326                 :         struct pollfd ufd = { .fd = fd, .events = POLLIN };
     327                 :         if (poll (&ufd, 1, -1) == -1)
     328                 :                 return -1;
     329                 : #endif
     330                 : 
     331               0 :         return teredo_recv_inner (fd, p, 0);
     332                 : }
     333                 : 
     334                 : 
     335                 : /* This does not fit anywhere and is needed by both relay and server */
     336                 : #include <stdbool.h>
     337                 : 
     338                 : /**
     339                 :  * Computes an Internet checksum over a scatter-gather array.
     340                 :  * Buffers need not be aligned neither of even length.
     341                 :  * Jumbograms are supported (though you probably don't care).
     342                 :  */
     343                 : static uint16_t in_cksum (const struct iovec *iov, size_t n)
     344               0 : {
     345               0 :         uint32_t sum = 0;
     346                 :         union
     347                 :         {
     348                 :                 uint16_t word;
     349                 :                 uint8_t  bytes[2];
     350                 :         } w;
     351               0 :         bool odd = false;
     352                 : 
     353               0 :         while (n > 0)
     354                 :         {
     355               0 :                 const uint8_t *ptr = iov->iov_base;
     356                 : 
     357               0 :                 for (size_t len = iov->iov_len; len > 0; len--)
     358                 :                 {
     359               0 :                         if (odd)
     360                 :                         {
     361               0 :                                 w.bytes[1] = *ptr++;
     362               0 :                                 sum += w.word;
     363               0 :                                 if (sum > 0xffff)
     364               0 :                                         sum -= 0xffff;
     365                 :                         }
     366                 :                         else
     367               0 :                                 w.bytes[0] = *ptr++;
     368               0 :                         odd = !odd;
     369                 :                 }
     370                 : 
     371               0 :                 iov++;
     372               0 :                 n--;
     373                 :         }
     374                 : 
     375               0 :         if (odd)
     376                 :         {
     377               0 :                 w.bytes[1] = 0;
     378               0 :                 sum += w.word;
     379               0 :                 if (sum > 0xffff)
     380               0 :                         sum -= 0xffff;
     381                 :         }
     382                 : 
     383               0 :         return sum ^ 0xffff;
     384                 : }
     385                 : 
     386                 : 
     387                 : /**
     388                 :  * Computes an IPv6 layer-3 checksum.
     389                 :  * The input buffers do not need to be aligned neither of even length.
     390                 :  * Jumbo datagrams are supported.
     391                 :  */
     392                 : uint16_t
     393                 : teredo_cksum (const void *src, const void *dst, uint8_t protocol,
     394                 :               const struct iovec *data, size_t n)
     395               0 : {
     396               0 :         struct iovec iov[3 + n];
     397               0 :         size_t plen = 0;
     398               0 :         for (size_t i = 0; i < n; i++)
     399                 :         {
     400               0 :                 iov[3 + i].iov_base = data[i].iov_base;
     401               0 :                 plen += (iov[3 + i].iov_len = data[i].iov_len);
     402                 :         }
     403                 : 
     404               0 :         uint32_t pseudo[4] = { htonl (plen), htonl (protocol) };
     405               0 :         iov[0].iov_base = (void *)src;
     406               0 :         iov[0].iov_len = 16;
     407               0 :         iov[1].iov_base = (void *)dst;
     408               0 :         iov[1].iov_len = 16;
     409               0 :         iov[2].iov_base = pseudo;
     410               0 :         iov[2].iov_len = 8;
     411                 : 
     412               0 :         return in_cksum (iov, 3 + n);
     413                 : }
     414                 : 

Generated by: LTP GCOV extension version 1.5