LTP GCOV extension - code coverage report
Current view: directory - trunk/libteredo - relay.c
Test: lcov.info
Date: 2007-05-09 Instrumented lines: 336
Code covered: 8.9 % Executed lines: 30

       1                 : /*
       2                 :  * relay.c - Teredo relay core
       3                 :  * $Id: relay.c 1938 2007-02-22 20:55:28Z 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 <gettext.h>
      30                 : 
      31                 : #include <stdbool.h>
      32                 : #include <string.h>
      33                 : #include <time.h>
      34                 : #include <stdlib.h> // malloc()
      35                 : #include <assert.h>
      36                 : #include <inttypes.h>
      37                 : 
      38                 : #include <sys/types.h>
      39                 : #include <sys/time.h>
      40                 : #include <netinet/in.h>
      41                 : #include <netinet/ip6.h> // struct ip6_hdr
      42                 : #include <netinet/icmp6.h> // ICMP6_DST_UNREACH_*
      43                 : #include <pthread.h>
      44                 : 
      45                 : #include "teredo.h"
      46                 : #include "v4global.h" // is_ipv4_global_unicast()
      47                 : #include "teredo-udp.h"
      48                 : 
      49                 : #include "packets.h"
      50                 : #include "tunnel.h"
      51                 : #include "maintain.h"
      52                 : #include "clock.h"
      53                 : #include "peerlist.h"
      54                 : #ifdef MIREDO_TEREDO_CLIENT
      55                 : # include "security.h"
      56                 : #endif
      57                 : #include "debug.h"
      58                 : 
      59                 : struct teredo_tunnel
      60                 : {
      61                 :         struct teredo_peerlist *list;
      62                 :         void *opaque;
      63                 : #ifdef MIREDO_TEREDO_CLIENT
      64                 :         struct teredo_maintenance *maintenance;
      65                 :         
      66                 :         teredo_state_up_cb up_cb;
      67                 :         teredo_state_down_cb down_cb;
      68                 : #endif
      69                 :         teredo_recv_cb recv_cb;
      70                 :         teredo_icmpv6_cb icmpv6_cb;
      71                 : 
      72                 :         teredo_state state;
      73                 :         pthread_rwlock_t state_lock;
      74                 : 
      75                 :         // ICMPv6 rate limiting
      76                 :         struct
      77                 :         {
      78                 :                 pthread_mutex_t lock;
      79                 :                 int count;
      80                 :                 teredo_clock_t last;
      81                 :         } ratelimit;
      82                 : 
      83                 :         // Asynchronous packet reception
      84                 :         struct
      85                 :         {
      86                 :                 pthread_t thread;
      87                 :                 bool running;
      88                 :         } recv;
      89                 : 
      90                 :         int fd;
      91                 : };
      92                 : 
      93                 : #ifdef HAVE_LIBJUDY
      94                 : # define MAX_PEERS 1048576
      95                 : #else
      96                 : # define MAX_PEERS 1024
      97                 : #endif
      98                 : #define ICMP_RATE_LIMIT_MS 100
      99                 : 
     100                 : #if 0
     101                 : static unsigned QualificationRetries; // maintain.c
     102                 : static unsigned QualificationTimeOut; // maintain.c
     103                 : static unsigned ServerNonceLifetime;  // maintain.c
     104                 : static unsigned RestartDelay;         // maintain.c
     105                 : 
     106                 : static unsigned MaxQueueBytes;        // peerlist.c
     107                 : static unsigned MaxPeers;             // here
     108                 : static unsigned IcmpRateLimitMs;      // here
     109                 : #endif
     110                 : 
     111                 : /**
     112                 :  * Rate limiter around ICMPv6 unreachable error packet emission callback.
     113                 :  *
     114                 :  * @param code ICMPv6 unreachable error code.
     115                 :  * @param in IPv6 packet that caused the error.
     116                 :  * @param len byte length of the IPv6 packet at <in>.
     117                 :  */
     118                 : static void
     119                 : teredo_send_unreach (teredo_tunnel *restrict tunnel, uint8_t code,
     120                 :                      const void *restrict in, size_t len)
     121               0 : {
     122                 :         struct
     123                 :         {
     124                 :                 struct icmp6_hdr hdr;
     125                 :                 char fill[1280 - sizeof (struct ip6_hdr) - sizeof (struct icmp6_hdr)];
     126                 :         } buf;
     127               0 :         teredo_clock_t now = teredo_clock ();
     128                 : 
     129                 :         /* ICMPv6 rate limit */
     130               0 :         pthread_mutex_lock (&tunnel->ratelimit.lock);
     131               0 :         if (now != tunnel->ratelimit.last)
     132                 :         {
     133               0 :                 tunnel->ratelimit.last = now;
     134               0 :                 tunnel->ratelimit.count =
     135                 :                         ICMP_RATE_LIMIT_MS ? (int)(1000 / ICMP_RATE_LIMIT_MS) : -1;
     136                 :         }
     137                 : 
     138               0 :         if (tunnel->ratelimit.count == 0)
     139                 :         {
     140                 :                 /* rate limit exceeded */
     141               0 :                 pthread_mutex_unlock (&tunnel->ratelimit.lock);
     142               0 :                 return;
     143                 :         }
     144               0 :         if (tunnel->ratelimit.count > 0)
     145               0 :                 tunnel->ratelimit.count--;
     146               0 :         pthread_mutex_unlock (&tunnel->ratelimit.lock);
     147                 : 
     148               0 :         len = BuildICMPv6Error (&buf.hdr, ICMP6_DST_UNREACH, code, in, len);
     149                 :         struct in6_addr dst;
     150               0 :         memcpy (&dst, &((const struct ip6_hdr *)in)->ip6_src, sizeof (dst));
     151               0 :         tunnel->icmpv6_cb (tunnel->opaque, &buf.hdr, len, &dst);
     152                 : }
     153                 : 
     154                 : #if 0
     155                 : /*
     156                 :  * Sends an ICMPv6 Destination Unreachable error to the IPv6 Internet.
     157                 :  * Unfortunately, this will use a local-scope address as source, which is not
     158                 :  * quite good.
     159                 :  */
     160                 : void
     161                 : TeredoRelay::EmitICMPv6Error (const void *packet, size_t length,
     162                 :                                                           const struct in6_addr *dst)
     163                 : {
     164                 :         /* TODO should be implemented with BuildIPv6Error() */
     165                 :         /* that is currently dead code */
     166                 : 
     167                 :         /* F-I-X-M-E: using state implies locking */
     168                 :         size_t outlen = BuildIPv6Error (&buf.hdr, &state.addr.ip6,
     169                 :                                         ICMP6_DST_UNREACH, code, in, inlen);
     170                 :         tunnel->recv_cb (tunnel->opaque, &buf, outlen);
     171                 : }
     172                 : #endif
     173                 : 
     174                 : 
     175                 : #ifdef MIREDO_TEREDO_CLIENT
     176                 : static void
     177                 : teredo_state_change (const teredo_state *state, void *self)
     178               0 : {
     179               0 :         teredo_tunnel *tunnel = (teredo_tunnel *)self;
     180                 : 
     181               0 :         pthread_rwlock_wrlock (&tunnel->state_lock);
     182               0 :         bool previously_up = tunnel->state.up;
     183               0 :         memcpy (&tunnel->state, state, sizeof (tunnel->state));
     184                 : 
     185               0 :         if (tunnel->state.up)
     186                 :         {
     187                 :                 /*
     188                 :                  * NOTE: we get an hold on both state and peer list locks here.
     189                 :                  * As such, in any case, attempting to acquire the state lock while
     190                 :                  * the peer list is locked is STRICTLY FORBIDDEN to avoid an obvious
     191                 :                  * inter-locking deadlock.
     192                 :                  */
     193               0 :                 teredo_list_reset (tunnel->list, MAX_PEERS);
     194               0 :                 tunnel->up_cb (tunnel->opaque,
     195                 :                                &tunnel->state.addr.ip6, tunnel->state.mtu);
     196                 :         }
     197                 :         else
     198               0 :         if (previously_up)
     199               0 :                 tunnel->down_cb (tunnel->opaque);
     200                 : 
     201                 :         /*
     202                 :          * NOTE: the lock is retained until here to ensure notifications remain
     203                 :          * properly ordered. Unfortunately, we cannot be re-entrant from within
     204                 :         * up_cb/down_cb.
     205                 :          */
     206               0 :         pthread_rwlock_unlock (&tunnel->state_lock);
     207               0 : }
     208                 : 
     209                 : /**
     210                 :  * @return 0 if a ping may be sent. 1 if one was sent recently
     211                 :  * -1 if the peer seems unreachable.
     212                 :  */
     213                 : static int CountPing (teredo_peer *peer, teredo_clock_t now)
     214               0 : {
     215                 :         int res;
     216                 : 
     217               0 :         if (peer->pings == 0)
     218               0 :                 res = 0;
     219                 :         // don't test more than 4 times (once + 3 repeats)
     220               0 :         else if (peer->pings >= 4)
     221               0 :                 res = -1;
     222                 :         // test must be separated by at least 2 seconds
     223                 :         else
     224               0 :         if (((now - peer->last_ping) & 0x1ff) <= 2)
     225               0 :                 res = 1;
     226                 :         else
     227               0 :                 res = 0; // can test again!
     228                 : 
     229               0 :         if (res == 0)
     230                 :         {
     231               0 :                 peer->last_ping = now;
     232               0 :                 peer->pings++;
     233                 :         }
     234                 : 
     235               0 :         return res;
     236                 : }
     237                 : 
     238                 : 
     239                 : static inline bool IsClient (const teredo_tunnel *tunnel)
     240               0 : {
     241               0 :         return tunnel->maintenance != NULL;
     242                 : }
     243                 : #endif
     244                 : 
     245                 : 
     246                 : /*
     247                 :  * Returs true if the packet whose header is passed as a parameter looks
     248                 :  * like a Teredo bubble.
     249                 :  */
     250                 : static inline bool IsBubble (const struct ip6_hdr *hdr)
     251               0 : {
     252               0 :         return (hdr->ip6_plen == 0) && (hdr->ip6_nxt == IPPROTO_NONE);
     253                 : }
     254                 : 
     255                 : 
     256                 : /*
     257                 :  * Returns 0 if a bubble may be sent, -1 if no more bubble may be sent,
     258                 :  * 1 if a bubble may be sent later.
     259                 :  */
     260                 : static int CountBubble (teredo_peer *peer, teredo_clock_t now)
     261               0 : {
     262                 :         /* § 5.2.6 - sending bubbles */
     263                 :         int res;
     264                 : 
     265               0 :         if (peer->bubbles > 0)
     266                 :         {
     267               0 :                 if (peer->bubbles >= 4)
     268                 :                 {
     269                 :                         // don't send if 4 bubbles already sent within 300 seconds
     270               0 :                         if ((now - peer->last_tx) <= 300)
     271               0 :                                 res = -1;
     272                 :                         else
     273                 :                         {
     274                 :                                 // reset counter every 300 seconds
     275               0 :                                 peer->bubbles = 0;
     276               0 :                                 res = 0;
     277                 :                         }
     278                 :                 }
     279                 :                 else
     280                 :                 // don't send if last tx was 2 seconds ago or fewer
     281               0 :                 if ((now - peer->last_tx) <= 2)
     282               0 :                         res = 1;
     283                 :                 else
     284               0 :                         res = 0;
     285                 :         }
     286                 :         else
     287               0 :                 res = 0;
     288                 : 
     289               0 :         if (res == 0)
     290                 :         {
     291               0 :                 peer->last_tx = now;
     292               0 :                 peer->bubbles++;
     293                 :         }
     294                 : 
     295               0 :         return res;
     296                 : }
     297                 : 
     298                 : 
     299                 : static inline void SetMappingFromPacket (teredo_peer *peer,
     300                 :                                          const struct teredo_packet *p)
     301               0 : {
     302               0 :         SetMapping (peer, p->source_ipv4, p->source_port);
     303               0 : }
     304                 : 
     305                 : 
     306                 : /**
     307                 :  * Encapsulates an IPv6 packet, forward it to a Teredo peer and release the
     308                 :  * Teredo peers list. It is (obviously) assumed that the peers list lock is
     309                 :  * held upon entry.
     310                 :  *
     311                 :  * @return 0 on success, -1 in case of UDP/IPv4 network error.
     312                 :  */
     313                 : static
     314                 : int teredo_encap (teredo_tunnel *restrict tunnel, teredo_peer *restrict peer,
     315                 :                   const void *restrict data, size_t len, teredo_clock_t now)
     316               0 : {
     317               0 :         uint32_t ipv4 = peer->mapped_addr;
     318               0 :         uint16_t port = peer->mapped_port;
     319               0 :         TouchTransmit (peer, now);
     320               0 :         teredo_list_release (tunnel->list);
     321                 : 
     322               0 :         return (teredo_send (tunnel->fd,
     323                 :                              data, len, ipv4, port) == (int)len) ? 0 : -1;
     324                 : }
     325                 : 
     326                 : /**
     327                 :  * Transmits a packet coming from the IPv6 Internet, toward a Teredo node
     328                 :  * (as specified per paragraph 5.4.1). That's what the specification calls
     329                 :  * “Packet transmission”.
     330                 :  *
     331                 :  * It is assumed that the IPv6 packet is valid (if not, it will be dropped by
     332                 :  * the receiving Teredo peer). It is furthermore assumed that the packet is at
     333                 :  * least 40 bytes long (room for the IPv6 header and that it is properly
     334                 :  * aligned.
     335                 :  *
     336                 :  * The packet size should not exceed the MTU (1280 bytes by default).
     337                 :  * In any case, sending will fail if the packets size exceeds 65507 bytes
     338                 :  * (maximum size for a UDP packet's payload).
     339                 :  *
     340                 :  * Thread-safety: This function is thread-safe.
     341                 :  *
     342                 :  * @return 0 on success, -1 on error.
     343                 :  */
     344                 : int teredo_transmit (teredo_tunnel *restrict tunnel,
     345                 :                      const struct ip6_hdr *restrict packet, size_t length)
     346               0 : {
     347               0 :         assert (tunnel != NULL);
     348                 : 
     349                 :         const union teredo_addr *dst =
     350               0 :                 (const union teredo_addr *)&packet->ip6_dst;
     351                 : 
     352                 :         /* Drops multicast destination, we cannot handle these */
     353               0 :         if (dst->ip6.s6_addr[0] == 0xff)
     354               0 :                 return 0;
     355                 : 
     356                 :         teredo_state s;
     357               0 :         pthread_rwlock_rdlock (&tunnel->state_lock);
     358               0 :         memcpy (&s, &tunnel->state, sizeof (s));
     359                 :         /*
     360                 :          * We can afford to use a slightly outdated state, but we cannot afford to
     361                 :          * use an inconsistent state, hence this lock.
     362                 :         */
     363               0 :         pthread_rwlock_unlock (&tunnel->state_lock);
     364                 : 
     365                 : #ifdef MIREDO_TEREDO_CLIENT
     366               0 :         if (IsClient (tunnel) && !s.up)
     367                 :         {
     368                 :                 /* Client not qualified */
     369               0 :                 teredo_send_unreach (tunnel, ICMP6_DST_UNREACH_ADDR, packet, length);
     370               0 :                 return 0;
     371                 :         }
     372                 : #endif
     373                 : 
     374               0 :         if (dst->teredo.prefix != s.addr.teredo.prefix)
     375                 :         {
     376                 :                 /* Non-Teredo destination */
     377                 : #ifdef MIREDO_TEREDO_CLIENT
     378               0 :                 if (IsClient (tunnel))
     379                 :                 {
     380                 :                         const union teredo_addr *src =
     381               0 :                                 (const union teredo_addr *)&packet->ip6_src;
     382                 : 
     383               0 :                         if (src->teredo.prefix != s.addr.teredo.prefix)
     384                 :                         {
     385                 :                                 // Teredo servers and relays would reject the packet
     386                 :                                 // if it does not have a Teredo source.
     387               0 :                                 teredo_send_unreach (tunnel, ICMP6_DST_UNREACH_ADMIN,
     388                 :                                                      packet, length);
     389               0 :                                 return 0;
     390                 :                         }
     391                 :                 }
     392                 :                 else
     393                 : #endif
     394                 :                 {
     395                 :                         // Teredo relays only routes toward Teredo clients.
     396                 :                         // The routing table must be misconfigured.
     397               0 :                         teredo_send_unreach (tunnel, ICMP6_DST_UNREACH_ADDR,
     398                 :                                              packet, length);
     399               0 :                         return 0;
     400                 :                 }
     401                 :         }
     402                 :         else
     403                 :         {
     404                 :                 /* Teredo destination */
     405               0 :                 assert (dst->teredo.prefix == s.addr.teredo.prefix);
     406                 :                 /*
     407                 :                  * Ignores Teredo clients with incorrect server IPv4.
     408                 :                  * This check is only specified for client case 4 & 5.
     409                 :                  * That said, it can never fail in the other client cases (either
     410                 :                  * because the peer is already known which means it already passed
     411                 :                  * this check, or because the peer is not a Teredo client.
     412                 :                  * As for the relay, I consider the check should also be done, even if
     413                 :                  * it wasn't specified (TBD: double check the spec).
     414                 :                  * Doing the check earlier, while it has an additionnal cost, makes
     415                 :                  * sure that the peer will be added to the list if it is not already
     416                 :                  * in it, which avoids a double peer list lookup (failed lookup, then
     417                 :                  * insertion), which is a big time saver under heavy load.
     418                 :                  */
     419               0 :                 uint32_t peer_server = IN6_TEREDO_SERVER (dst);
     420               0 :                 if (!is_ipv4_global_unicast (peer_server) || (peer_server == 0))
     421               0 :                         return 0;
     422                 :         }
     423                 : 
     424                 :         bool created;
     425               0 :         teredo_clock_t now = teredo_clock ();
     426               0 :         struct teredo_peerlist *list = tunnel->list;
     427                 : 
     428                 : //      syslog (LOG_DEBUG, "packet to be sent");
     429               0 :         teredo_peer *p = teredo_list_lookup (list, &dst->ip6, &created);
     430               0 :         if (p == NULL)
     431               0 :                 return -1; /* error */
     432                 : 
     433               0 :         if (!created)
     434                 :         {
     435                 : //              syslog (LOG_DEBUG, " peer is %strusted", p->trusted ? "" : "NOT ");
     436                 : //              syslog (LOG_DEBUG, " peer is %svalid", IsValid (p, now) ? "" : "NOT ");
     437                 : //              syslog (LOG_DEBUG, " pings = %u, bubbles = %u", p->pings, p->bubbles);
     438                 : 
     439                 :                 /* Case 1 (paragraphs 5.2.4 & 5.4.1): trusted peer */
     440               0 :                 if (p->trusted && IsValid (p, now))
     441                 :                         /* Already known -valid- peer */
     442               0 :                         return teredo_encap (tunnel, p, packet, length, now);
     443                 :         }
     444                 :         else
     445                 :         {
     446               0 :                 p->trusted = p->bubbles = p->pings = 0;
     447                 : //              syslog (LOG_DEBUG, " peer unknown and created");
     448                 :         }
     449                 : 
     450                 :         // Unknown, untrusted, or too old peer
     451                 :         // (thereafter refered to as simply "untrusted")
     452                 : 
     453                 : #ifdef MIREDO_TEREDO_CLIENT
     454                 :         /* Untrusted non-Teredo node */
     455               0 :         if (dst->teredo.prefix != s.addr.teredo.prefix)
     456                 :         {
     457                 :                 int res;
     458                 : 
     459               0 :                 assert (IsClient (tunnel));
     460                 : 
     461                 :                 /* Client case 2: direct IPv6 connectivity test */
     462                 :                 // TODO: avoid code duplication
     463               0 :                 if (created)
     464                 :                 {
     465               0 :                         p->mapped_port = 0;
     466               0 :                         p->mapped_addr = 0;
     467                 :                 }
     468                 : 
     469               0 :                 teredo_enqueue_out (p, packet, length);
     470               0 :                 res = CountPing (p, now);
     471               0 :                 teredo_list_release (list);
     472                 : 
     473               0 :                 if (res == 0)
     474               0 :                         res = SendPing (tunnel->fd, &s.addr, &dst->ip6);
     475                 : 
     476               0 :                 if (res == -1)
     477               0 :                         teredo_send_unreach (tunnel, ICMP6_DST_UNREACH_ADDR,
     478                 :                                              packet, length);
     479                 : 
     480                 : //              syslog (LOG_DEBUG, " ping peer returned %d", res);
     481               0 :                 return 0;
     482                 :         }
     483                 : #endif
     484                 : 
     485                 :         // Untrusted Teredo client
     486                 : 
     487                 :         /* Client case 3: TODO: implement local discovery */
     488                 : 
     489               0 :         if (created)
     490                 :                 /* Unknown Teredo clients */
     491               0 :                 SetMapping (p, IN6_TEREDO_IPV4 (dst), IN6_TEREDO_PORT (dst));
     492                 : 
     493                 : #ifdef LIBTEREDO_ALLOW_CONE
     494                 :         /* Client case 4 & relay case 2: new cone peer */
     495                 :         if (IN6_IS_TEREDO_ADDR_CONE (dst))
     496                 :         {
     497                 :                 p->trusted = 1;
     498                 :                 p->bubbles = /*p->pings -USELESS- =*/ 0;
     499                 :                 return teredo_encap (tunnel, p, packet, length);
     500                 :         }
     501                 : #endif
     502                 : 
     503                 :         /* Client case 5 & relay case 3: untrusted non-cone peer */
     504               0 :         teredo_enqueue_out (p, packet, length);
     505                 : 
     506                 :         // Sends bubble, if rate limit allows
     507               0 :         int res = CountBubble (p, now);
     508               0 :         teredo_list_release (list);
     509               0 :         switch (res)
     510                 :         {
     511                 :                 case 0:
     512                 :                         /*
     513                 :                          * Open the return path if we are behind a
     514                 :                          * restricted NAT.
     515                 :                          */
     516               0 :                         if (!(s.addr.teredo.flags & htons (TEREDO_FLAG_CONE))
     517                 :                          && SendBubbleFromDst (tunnel->fd, &dst->ip6, false))
     518               0 :                                 return -1;
     519                 : 
     520               0 :                         return SendBubbleFromDst (tunnel->fd, &dst->ip6, true);
     521                 : 
     522                 :                 case -1: // Too many bubbles already sent
     523               0 :                         teredo_send_unreach (tunnel, ICMP6_DST_UNREACH_ADDR,
     524                 :                                              packet, length);
     525                 : 
     526                 :                 //case 1: -- between two bubbles -- nothing to do
     527                 :         }
     528                 : 
     529               0 :         return 0;
     530                 : }
     531                 : 
     532                 : 
     533                 : static
     534                 : void teredo_predecap (teredo_tunnel *restrict tunnel,
     535                 :                       teredo_peer *restrict peer, teredo_clock_t now)
     536               0 : {
     537               0 :         TouchReceive (peer, now);
     538               0 :         peer->bubbles = peer->pings = 0;
     539               0 :         teredo_queue *q = teredo_peer_queue_yield (peer);
     540               0 :         teredo_list_release (tunnel->list);
     541                 : 
     542               0 :         if (q != NULL)
     543               0 :                 teredo_queue_emit (q, tunnel->fd,
     544                 :                                    peer->mapped_addr, peer->mapped_port,
     545                 :                                    tunnel->recv_cb, tunnel->opaque);
     546               0 : }
     547                 : 
     548                 : 
     549                 : /**
     550                 :  * Receives a packet coming from the Teredo tunnel (as specified per
     551                 :  * paragraph 5.4.2). That's called “Packet reception”.
     552                 :  *
     553                 :  * This function will NOT block if no packet are pending processing; it
     554                 :  * will return immediatly.
     555                 :  *
     556                 :  * Thread-safety: This function is thread-safe.
     557                 :  */
     558                 : static void
     559                 : teredo_run_inner (teredo_tunnel *restrict tunnel,
     560                 :                   const struct teredo_packet *restrict packet)
     561               0 : {
     562               0 :         assert (tunnel != NULL);
     563               0 :         assert (packet != NULL);
     564                 : 
     565               0 :         const uint8_t *buf = packet->ip6;
     566               0 :         size_t length = packet->ip6_len;
     567                 :         struct ip6_hdr ip6;
     568                 : 
     569                 :         // Checks packet
     570               0 :         if ((length < sizeof (ip6)) || (length > 65507))
     571               0 :                 return; // invalid packet
     572                 : 
     573               0 :         memcpy (&ip6, buf, sizeof (ip6));
     574               0 :         if (((ip6.ip6_vfc >> 4) != 6)
     575                 :          || ((ntohs (ip6.ip6_plen) + sizeof (ip6)) != length))
     576               0 :                 return; // malformatted IPv6 packet
     577                 : 
     578                 :         teredo_state s;
     579               0 :         pthread_rwlock_rdlock (&tunnel->state_lock);
     580               0 :         memcpy (&s, &tunnel->state, sizeof (s));
     581                 :         /*
     582                 :          * We can afford to use a slightly outdated state, but we cannot afford to
     583                 :          * use an inconsistent state, hence this lock. Also, we cannot call
     584                 :          * teredo_maintenance_process() while holding the lock, as that would
     585                 :          * cause a deadlock at StateChange().
     586                 :          */
     587               0 :         pthread_rwlock_unlock (&tunnel->state_lock);
     588                 : 
     589                 : #ifdef MIREDO_TEREDO_CLIENT
     590                 :         /* Maintenance */
     591               0 :         if (IsClient (tunnel))
     592                 :         {
     593               0 :                 if (teredo_maintenance_process (tunnel->maintenance, packet) == 0)
     594               0 :                         return;
     595                 : 
     596               0 :                 if (!s.up)
     597               0 :                         return; /* Not qualified -> do not accept incoming packets */
     598                 : 
     599               0 :                 if ((packet->source_ipv4 == s.addr.teredo.server_ip)
     600                 :                  && (packet->source_port == htons (IPPORT_TEREDO)))
     601                 :                 {
     602               0 :                         uint32_t ipv4 = packet->orig_ipv4;
     603               0 :                         uint16_t port = packet->orig_port;
     604                 : 
     605               0 :                         if ((ipv4 == 0) && IsBubble (&ip6)
     606                 :                          && (IN6_TEREDO_PREFIX (&ip6.ip6_src) == s.addr.teredo.prefix))
     607                 :                         {
     608                 :                                 /*
     609                 :                                  * Some servers do not insert an origin indication.
     610                 :                                  * When the source IPv6 address is a Teredo address,
     611                 :                                  * we can guess the mapping. Otherwise, we're stuck.
     612                 :                                  */
     613               0 :                                 ipv4 = IN6_TEREDO_IPV4 (&ip6.ip6_src);
     614               0 :                                 port = IN6_TEREDO_PORT (&ip6.ip6_src);
     615                 :                         }
     616                 : 
     617               0 :                         if (ipv4)
     618                 :                         {
     619                 :                                 /* TODO: record sending of bubble, create a peer, etc ? */
     620               0 :                                 teredo_reply_bubble (tunnel->fd, ipv4, port, buf);
     621               0 :                                 if (IsBubble (&ip6))
     622               0 :                                         return; // don't pass bubble to kernel
     623                 :                         }
     624                 :                 }
     625                 : 
     626                 :                 /*
     627                 :                  * Normal reception of packet must only occur if it does not
     628                 :                  * come from the server, as specified. However, it is not
     629                 :                  * unlikely that our server is a relay too. Hence, we must
     630                 :                  * further process packets from it.
     631                 :                  * At the moment, we only drop bubble (see above).
     632                 :                  */
     633                 : 
     634                 :                 /*
     635                 :                  * Packets with a link-local source address are purposedly dropped to
     636                 :                  * prevent the kernel from receiving faked Router Advertisement which
     637                 :                  * could break IPv6 routing completely. Router advertisements MUST
     638                 :                  * have a link-local source address (RFC 2461).
     639                 :                  *
     640                 :                  * This is not supposed to occur except from the Teredo server for
     641                 :                  * Teredo maintenance (done above), and in hole punching packets
     642                 :                  * (bubbles). Direct bubbles can safely be ignored, so long as the
     643                 :                  * indirect ones are processed (and they are processed above).
     644                 :                  *
     645                 :                  * This check is not part of the Teredo specification, but I really
     646                 :                  * don't feel like letting link-local packets come in through the
     647                 :                  * virtual network interface.
     648                 :                  *
     649                 :                  * Only Linux defines s6_addr16, so we don't use it.
     650                 :                  */
     651               0 :                 if (ntohs ((*(uint16_t *)ip6.ip6_src.s6_addr) & 0xffc0) == 0xfe80)
     652               0 :                         return;
     653                 :         }
     654                 :         else
     655                 : #endif /* MIREDO_TEREDO_CLIENT */
     656                 :         /* Relays only accept packets from Teredo clients */
     657               0 :         if (IN6_TEREDO_PREFIX (&ip6.ip6_src) != s.addr.teredo.prefix)
     658               0 :                 return;
     659                 : 
     660                 :         /*
     661                 :          * NOTE:
     662                 :          * Clients are supposed to check that the destination is their Teredo IPv6
     663                 :          * address; this is done by the IPv6 stack. When IPv6 forwarding is enabled,
     664                 :          * Teredo clients behave like Teredo non-host-specific relays.
     665                 :          *
     666                 :          * Teredo relays are advised to accept only packets whose IPv6 destination
     667                 :          * is served by them (i.e. egress filtering from Teredo to native IPv6).
     668                 :          * The IPv6 stack firewall should be used to that end.
     669                 :          *
     670                 :          * Multicast destinations are not supposed to occur, not even for hole
     671                 :          * punching. We drop them as a precautionary measure.
     672                 :          *
     673                 :          * We purposedly don't drop packets on the basis of link-local destination
     674                 :          * as it breaks hole punching: we send Teredo bubbles with a link-local
     675                 :          * source, and get replies with a link-local destination. Indeed, the
     676                 :          * specification specifies that relays MUST look up the peer in the list
     677                 :          * and update last reception date regardless of the destination.
     678                 :          *
     679                 :          */
     680               0 :         if (ip6.ip6_dst.s6_addr[0] == 0xff)
     681               0 :                 return;
     682                 : 
     683                 :         /* Actual packet reception, either as a relay or a client */
     684                 : 
     685               0 :         teredo_clock_t now = teredo_clock ();
     686                 : 
     687                 :         // Checks source IPv6 address / looks up peer in the list:
     688               0 :         struct teredo_peerlist *list = tunnel->list;
     689               0 :         teredo_peer *p = teredo_list_lookup (list, &ip6.ip6_src, NULL);
     690                 : 
     691               0 :         if (p != NULL)
     692                 :         {
     693                 : //              syslog (LOG_DEBUG, " peer is %strusted", p->trusted ? "" : "NOT ");
     694                 : //              syslog (LOG_DEBUG, " pings = %u, bubbles = %u", p->pings, p->bubbles);
     695                 : 
     696                 :                 // Client case 1 (trusted node or (trusted) Teredo client):
     697               0 :                 if (p->trusted
     698                 :                  && (packet->source_ipv4 == p->mapped_addr)
     699                 :                  && (packet->source_port == p->mapped_port))
     700                 :                 {
     701               0 :                         teredo_predecap (tunnel, p, now);
     702               0 :                         tunnel->recv_cb (tunnel->opaque, buf, length);
     703               0 :                         return;
     704                 :                 }
     705                 : 
     706                 : #ifdef MIREDO_TEREDO_CLIENT
     707                 :                 /*
     708                 :                  * Client case 2 (untrusted non-Teredo node):
     709                 :                  * Mismatching trusted non-Teredo nodes are also accepted to recover
     710                 :                  * faster from a Teredo relay change. This is legal (client case 6).
     711                 :                  */
     712               0 :                 if (IsClient (tunnel) && (CheckPing (packet) == 0))
     713                 :                 {
     714               0 :                         p->trusted = 1;
     715               0 :                         SetMappingFromPacket (p, packet);
     716                 : 
     717               0 :                         teredo_predecap (tunnel, p, now);
     718               0 :                         return; /* don't pass ping to kernel */
     719                 :                 }
     720                 : #endif /* ifdef MIREDO_TEREDO_CLIENT */
     721                 :         }
     722                 : //      else
     723                 : //              syslog (LOG_DEBUG, " unknown peer");
     724                 : 
     725                 :         /*
     726                 :          * At this point, we have either a trusted mapping mismatch,
     727                 :          * an unlisted peer, or an un-trusted client peer.
     728                 :          */
     729               0 :         if (IN6_TEREDO_PREFIX (&ip6.ip6_src) == s.addr.teredo.prefix)
     730                 :         {
     731                 :                 // Client case 3 (unknown or untrusted matching Teredo client):
     732               0 :                 if (IN6_MATCHES_TEREDO_CLIENT (&ip6.ip6_src, packet->source_ipv4,
     733                 :                                                packet->source_port)
     734                 :                 // Extension: allow mismatch (i.e. clients behind symmetric NATs)
     735                 :                  || (IsBubble (&ip6) && (CheckBubble (packet) == 0)))
     736                 :                 {
     737                 : #ifdef MIREDO_TEREDO_CLIENT
     738               0 :                         if (IsClient (tunnel) && (p == NULL))
     739               0 :                                 p = teredo_list_lookup (list, &ip6.ip6_src, &(bool){ false });
     740                 : #endif
     741                 :                         /*
     742                 :                          * Relays are explicitly allowed to drop packets from
     743                 :                          * unknown peers. It makes it a little more difficult to route
     744                 :                          * packets through the wrong relay. The specification leaves
     745                 :                          * us a choice here. It is arguable whether accepting these
     746                 :                          * packets would make it easier to DoS the peer list.
     747                 :                          */
     748               0 :                         if (p == NULL)
     749               0 :                                 return; // list not locked (p = NULL)
     750                 : 
     751               0 :                         SetMappingFromPacket (p, packet);
     752               0 :                         p->trusted = 1;
     753               0 :                         teredo_predecap (tunnel, p, now);
     754                 : 
     755               0 :                         if (!IsBubble (&ip6)) // discard Teredo bubble
     756               0 :                                 tunnel->recv_cb (tunnel->opaque, buf, length);
     757               0 :                         return;
     758                 :                 }
     759                 : 
     760                 :                 // TODO: local Teredo
     761                 :         }
     762                 : #ifdef MIREDO_TEREDO_CLIENT
     763                 :         else
     764                 :         {
     765               0 :                 assert (IN6_TEREDO_PREFIX (&ip6.ip6_src) != s.addr.teredo.prefix);
     766               0 :                 assert (IsClient (tunnel));
     767                 : 
     768                 :                 // TODO: implement client cases 4 & 5 for local Teredo
     769                 :         
     770                 :                 /*
     771                 :                  * Default: Client case 6:
     772                 :                  * (unknown non-Teredo node or Tereco client with incorrect mapping):
     773                 :                  * We should be cautious when accepting packets there, all the
     774                 :                  * more as we don't know if we are a really client or just a
     775                 :                  * qualified relay (ie. whether the host's default route is
     776                 :                  * actually the Teredo tunnel).
     777                 :                  */
     778                 :         
     779                 :                 // TODO: avoid code duplication (direct IPv6 connectivity test)
     780               0 :                 if (p == NULL)
     781                 :                 {
     782                 :                         bool create;
     783               0 :                         p = teredo_list_lookup (list, &ip6.ip6_src, &create);
     784               0 :                         if (p == NULL)
     785               0 :                                 return; // memory error
     786                 : 
     787                 :                         /*
     788                 :                          * We have to check "create": there is a race condition whereby
     789                 :                          * another thread could have created the peer in between the two
     790                 :                          * lookups of this function, since we did not lock the list
     791                 :                          * in between.
     792                 :                          */
     793               0 :                         if (create)
     794                 :                         {
     795               0 :                                 p->mapped_port = 0;
     796               0 :                                 p->mapped_addr = 0;
     797               0 :                                 p->trusted = p->bubbles = p->pings = 0;
     798                 :                         }
     799                 : //                      syslog (LOG_DEBUG, " peer created");
     800                 :                 }
     801                 : 
     802                 : //              syslog (LOG_DEBUG, " packet queued pending Echo Reply");
     803               0 :                 teredo_enqueue_in (p, buf, length,
     804                 :                                    packet->source_ipv4, packet->source_port);
     805               0 :                 TouchReceive (p, now);
     806                 : 
     807               0 :                 int res = CountPing (p, now);
     808               0 :                 teredo_list_release (list);
     809                 : 
     810               0 :                 if (res == 0)
     811               0 :                         SendPing (tunnel->fd, &s.addr, &ip6.ip6_src);
     812                 : 
     813                 : //              syslog (LOG_DEBUG, " ping peer returned %d", res);
     814               0 :                 return;
     815                 :         }
     816                 : #endif /* ifdef MIREDO_TEREDO_CLIENT */
     817                 : 
     818                 :         // Rejected packet
     819               0 :         if (p != NULL)
     820               0 :                 teredo_list_release (list);
     821                 : }
     822                 : 
     823                 : 
     824                 : 
     825                 : static void teredo_dummy_recv_cb (void *o, const void *p, size_t l)
     826               0 : {
     827                 :         (void)o;
     828                 :         (void)p;
     829                 :         (void)l;
     830               0 : }
     831                 : 
     832                 : 
     833                 : static void teredo_dummy_icmpv6_cb (void *o, const void *p, size_t l,
     834                 :                                        const struct in6_addr *d)
     835               0 : {
     836                 :         (void)o;
     837                 :         (void)p;
     838                 :         (void)l;
     839                 :         (void)d;
     840               0 : }
     841                 : 
     842                 : 
     843                 : #ifdef MIREDO_TEREDO_CLIENT
     844                 : static void teredo_dummy_state_up_cb (void *o, const struct in6_addr *a,
     845                 :                                          uint16_t m)
     846               0 : {
     847                 :         (void)o;
     848                 :         (void)a;
     849                 :         (void)m;
     850               0 : }
     851                 : 
     852                 : 
     853                 : static void teredo_dummy_state_down_cb (void *o)
     854               0 : {
     855                 :         (void)o;
     856               0 : }
     857                 : #endif
     858                 : 
     859                 : 
     860                 : /**
     861                 :  * Creates a teredo_tunnel instance. teredo_preinit() must have been
     862                 :  * called first.
     863                 :  *
     864                 :  * Thread-safety: This function is thread-safe.
     865                 :  *
     866                 :  * @param ipv4 IPv4 (network byte order) to bind to, or 0 if unspecified.
     867                 :  * @param port UDP/IPv4 port number (network byte order) or 0 if unspecified.
     868                 :  * Note that some campus firewall drop certain UDP ports (typically those used
     869                 :  * by some P2P application); in that case, you should use a fixed port so that
     870                 :  * the kernel does not select a possibly blocked port. Also note that some
     871                 :  * severely broken NAT devices might fail if multiple NAT-ed computers use the
     872                 :  * same source UDP port number at the same time, so avoid you should
     873                 :  * paradoxically avoid querying a fixed port.
     874                 :  *
     875                 :  * @return NULL in case of failure.
     876                 :  */
     877                 : teredo_tunnel *teredo_create (uint32_t ipv4, uint16_t port)
     878               1 : {
     879               1 :         teredo_tunnel *tunnel = (teredo_tunnel *)malloc (sizeof (*tunnel));
     880               1 :         if (tunnel == NULL)
     881               0 :                 return NULL;
     882                 : 
     883               1 :         memset (tunnel, 0, sizeof (*tunnel));
     884               1 :         tunnel->state.addr.teredo.prefix = htonl (TEREDO_PREFIX);
     885                 : 
     886                 :         /*
     887                 :          * That doesn't really need to match our mapping: the address is only
     888                 :          * used to send Unreachable message... with the old method that is no
     889                 :          * longer supported (the one that involves building the IPv6 header as
     890                 :          * well as the ICMPv6 header).
     891                 :          */
     892               1 :         tunnel->state.addr.teredo.client_port = ~port;
     893               1 :         tunnel->state.addr.teredo.client_ip = ~ipv4;
     894                 : 
     895               1 :         tunnel->state.up = false;
     896               1 :         tunnel->ratelimit.count = 1;
     897                 : 
     898               1 :         tunnel->recv_cb = teredo_dummy_recv_cb;
     899               1 :         tunnel->icmpv6_cb = teredo_dummy_icmpv6_cb;
     900                 : #ifdef MIREDO_TEREDO_CLIENT
     901               1 :         tunnel->up_cb = teredo_dummy_state_up_cb;
     902               1 :         tunnel->down_cb = teredo_dummy_state_down_cb;
     903                 : #endif
     904                 : 
     905               1 :         if ((tunnel->fd = teredo_socket (ipv4, port)) != -1)
     906                 :         {
     907               1 :                 if ((tunnel->list = teredo_list_create (MAX_PEERS, 30)) != NULL)
     908                 :                 {
     909               1 :                         (void)pthread_rwlock_init (&tunnel->state_lock, NULL);
     910               1 :                         (void)pthread_mutex_init (&tunnel->ratelimit.lock, NULL);
     911               1 :                         return tunnel;
     912                 :                 }
     913               0 :                 teredo_close (tunnel->fd);
     914                 :         }
     915                 : 
     916               0 :         free (tunnel);
     917               0 :         return NULL;
     918                 : }
     919                 : 
     920                 : 
     921                 : /**
     922                 :  * Releases all resources (sockets, memory chunks...) and terminates all
     923                 :  * threads associated with a teredo_tunnel instance.
     924                 :  *
     925                 :  * Thread-safety: This function is thread-safe. However, you must obviously
     926                 :  * not call it if any other thread (including the calling one) is still using
     927                 :  * the specified tunnel in some way.
     928                 :  *
     929                 :  * @param t tunnel to be destroyed. No longer useable thereafter.
     930                 :  *
     931                 :  * @return nothing (always succeeds).
     932                 :  */
     933                 : void teredo_destroy (teredo_tunnel *t)
     934               1 : {
     935               1 :         assert (t != NULL);
     936               1 :         assert (t->fd != -1);
     937               1 :         assert (t->list != NULL);
     938                 : 
     939                 : #ifdef MIREDO_TEREDO_CLIENT
     940                 :         /* NOTE: We must NOT lock the state r/w lock here,
     941                 :          * to avoid a potential deadlock, if the state callback is called by the
     942                 :          * maintenance thread. Anyway, if the user obey the specified constraints,
     943                 :          * we need not lock anyting in teredo_destroy(). */
     944               1 :         if (t->maintenance != NULL)
     945               0 :                 teredo_maintenance_stop (t->maintenance);
     946                 : #endif
     947                 : 
     948               1 :         if (t->recv.running)
     949                 :         {
     950               0 :                 pthread_cancel (t->recv.thread);
     951               0 :                 pthread_join (t->recv.thread, NULL);
     952                 :         }
     953                 : 
     954               1 :         teredo_list_destroy (t->list);
     955               1 :         pthread_rwlock_destroy (&t->state_lock);
     956               1 :         pthread_mutex_destroy (&t->ratelimit.lock);
     957               1 :         teredo_close (t->fd);
     958               1 :         free (t);
     959               1 : }
     960                 : 
     961                 : 
     962                 : static LIBTEREDO_NORETURN void *teredo_recv_thread (void *t)
     963               0 : {
     964               0 :         teredo_tunnel *tunnel = (teredo_tunnel *)t;
     965                 : 
     966                 :         for (;;)
     967                 :         {
     968                 :                 struct teredo_packet packet;
     969                 : 
     970               0 :                 if (teredo_wait_recv (tunnel->fd, &packet) == 0)
     971                 :                 {
     972               0 :                         pthread_setcancelstate (PTHREAD_CANCEL_DISABLE, NULL);
     973               0 :                         teredo_run_inner (tunnel, &packet);
     974               0 :                         pthread_setcancelstate (PTHREAD_CANCEL_ENABLE, NULL);
     975                 :                 }
     976               0 :         }
     977                 : }
     978                 : 
     979                 : /**
     980                 :  * Spawns a new thread to perform Teredo packet reception in the background.
     981                 :  * The thread will be automatically terminated when the tunnel is destroyed.
     982                 :  *
     983                 :  * It is safe to call teredo_run_async multiple times for the same tunnel,
     984                 :  * however all call will fail (safe) after the first succesful one.
     985                 :  *
     986                 :  * Thread-safety: teredo_run_async() is not re-entrant. Calling it from
     987                 :  * multiple threads with the same teredo_tunnel objet simultanously is
     988                 :  * undefined. It is safe to call teredo_run_async() from different threads
     989                 :  * each with a different teredo_tunnel object.
     990                 :  *
     991                 :  * @return 0 on success, -1 on error.
     992                 :  */
     993                 : int teredo_run_async (teredo_tunnel *t)
     994               0 : {
     995               0 :         assert (t != NULL);
     996                 : 
     997                 :         /* already running */
     998               0 :         if (t->recv.running)
     999               0 :                 return -1;
    1000                 : 
    1001               0 :         if (pthread_create (&t->recv.thread, NULL, teredo_recv_thread, t))
    1002               0 :                 return -1;
    1003                 : 
    1004               0 :         t->recv.running = true;
    1005               0 :         return 0;
    1006                 : }
    1007                 : 
    1008                 : 
    1009                 : /**
    1010                 :  * Receives one pending packet coming from the Teredo tunnel. If you
    1011                 :  * don't use teredo_run_async(), you have to call this function as
    1012                 :  * often as possible. It is up to you to find the correct tradeoff
    1013                 :  * between busy waiting on this function for better response time of
    1014                 :  * the Teredo tunnel, and a long delay to not waste too much CPU
    1015                 :  * cycles. You should really consider using teredo_run_async() instead!
    1016                 :  * libteredo will spawn some threads even if you don't call
    1017                 :  * teredo_run_async() anyway...
    1018                 :  *
    1019                 :  * Thread-safety: This function is thread-safe.
    1020                 :  */
    1021                 : void teredo_run (teredo_tunnel *tunnel)
    1022               0 : {
    1023               0 :         assert (tunnel != NULL);
    1024                 : 
    1025                 :         struct teredo_packet packet;
    1026                 : 
    1027               0 :         if (teredo_recv (tunnel->fd, &packet))
    1028               0 :                 return;
    1029                 : 
    1030               0 :         teredo_run_inner (tunnel, &packet);
    1031                 : }
    1032                 : 
    1033                 : 
    1034                 : /**
    1035                 :  * Overrides the Teredo prefix of a Teredo relay.
    1036                 :  * Currently ignored for Teredo client (but might later restrict accepted
    1037                 :  * Teredo prefix to the specified one).
    1038                 :  *
    1039                 :  * Thread-safety: This function is thread-safe.
    1040                 :  *
    1041                 :  * @param prefix Teredo 32-bits (network byte order) prefix.
    1042                 :  *
    1043                 :  * @return 0 on success, -1 if the prefix is invalid (in which case the
    1044                 :  * teredo_tunnel instance is not modified).
    1045                 :  */
    1046                 : int teredo_set_prefix (teredo_tunnel *t, uint32_t prefix)
    1047               0 : {
    1048               0 :         assert (t != NULL);
    1049               0 :         if (!is_valid_teredo_prefix (prefix))
    1050               0 :                 return -1;
    1051                 : 
    1052               0 :         int retval = 0;
    1053                 : 
    1054               0 :         pthread_rwlock_wrlock (&t->state_lock);
    1055                 : 
    1056                 : #ifdef MIREDO_TEREDO_CLIENT
    1057               0 :         if (t->maintenance != NULL)
    1058               0 :                 retval = -1;
    1059                 :         else
    1060                 : #endif
    1061               0 :                 t->state.addr.teredo.prefix = prefix;
    1062                 : 
    1063               0 :         pthread_rwlock_unlock (&t->state_lock);
    1064               0 :         return retval;
    1065                 : }
    1066                 : 
    1067                 : 
    1068                 : /**
    1069                 :  * Defines the cone flag of the Teredo tunnel.
    1070                 :  * This only works for Teredo relays.
    1071                 :  *
    1072                 :  * Thread-safety: This function is thread-safe.
    1073                 :  *
    1074                 :  * @param cone true to disable sending of direct Teredo bubble,
    1075                 :  *             false to enable it.
    1076                 :  *
    1077                 :  * @return 0 on success, -1 on error (in which case the teredo_tunnel
    1078                 :  * instance is not modified).
    1079                 :  */
    1080                 : int teredo_set_cone_flag (teredo_tunnel *t, bool cone)
    1081               0 : {
    1082               0 :         assert (t != NULL);
    1083                 : 
    1084               0 :         int retval = 0;
    1085                 : 
    1086               0 :         pthread_rwlock_wrlock (&t->state_lock);
    1087                 : 
    1088                 : #ifdef MIREDO_TEREDO_CLIENT
    1089               0 :         if (t->maintenance != NULL)
    1090               0 :                 retval = -1;
    1091                 :         else
    1092                 : #endif
    1093               0 :         if (cone)
    1094               0 :                 t->state.addr.teredo.flags |= htons (TEREDO_FLAG_CONE);
    1095                 :         else
    1096               0 :                 t->state.addr.teredo.flags &= ~htons (TEREDO_FLAG_CONE);
    1097                 : 
    1098               0 :         pthread_rwlock_unlock (&t->state_lock);
    1099                 : 
    1100               0 :         return retval;
    1101                 : }
    1102                 : 
    1103                 : 
    1104                 : /**
    1105                 :  * Enables Teredo relay mode (this is the default).
    1106                 :  *
    1107                 :  * Thread-safety: This function is thread-safe.
    1108                 :  *
    1109                 :  * @return 0 on success, -1 on error.
    1110                 :  */
    1111                 : int teredo_set_relay_mode (teredo_tunnel *t)
    1112               0 : {
    1113                 :         int retval;
    1114                 : 
    1115                 : #ifdef MIREDO_TEREDO_CLIENT
    1116               0 :         pthread_rwlock_wrlock (&t->state_lock);
    1117               0 :         retval = (t->maintenance != NULL) ? -1 : 0;
    1118               0 :         pthread_rwlock_unlock (&t->state_lock);
    1119                 : #else
    1120                 :         (void)t;
    1121                 :         retval = 0;
    1122                 : #endif
    1123                 : 
    1124               0 :         return retval;
    1125                 : }
    1126                 : 
    1127                 : 
    1128                 : /**
    1129                 :  * Enables Teredo client mode for a teredo_tunnel and starts the Teredo
    1130                 :  * client maintenance procedure in a separate thread.
    1131                 :  *
    1132                 :  * NOTE: calling teredo_set_client_mode() multiple times on the same tunnel
    1133                 :  * is currently not supported, and will safely return an error. Future
    1134                 :  * versions might support this.
    1135                 :  *
    1136                 :  * Thread-safety: This function is thread-safe.
    1137                 :  *
    1138                 :  * @param s Teredo server's host name or “dotted quad” primary IPv4 address.
    1139                 :  * @param s2 Teredo server's secondary address (or host name), or NULL to
    1140                 :  * infer it from <s>.
    1141                 :  *
    1142                 :  * @return 0 on success, -1 in case of error.
    1143                 :  * In case of error, the teredo_tunnel instance is not modifed.
    1144                 :  */
    1145                 : int teredo_set_client_mode (teredo_tunnel *restrict t,
    1146                 :                             const char *s, const char *s2)
    1147               0 : {
    1148                 : #ifdef MIREDO_TEREDO_CLIENT
    1149               0 :         assert (t != NULL);
    1150                 : 
    1151               0 :         pthread_rwlock_wrlock (&t->state_lock);
    1152               0 :         if (t->maintenance != NULL)
    1153                 :         {
    1154               0 :                 pthread_rwlock_unlock (&t->state_lock);
    1155               0 :                 return -1;
    1156                 :         }
    1157                 : 
    1158                 :         struct teredo_maintenance *m;
    1159               0 :         m = teredo_maintenance_start (t->fd, teredo_state_change, t, s, s2,
    1160                 :                                       0, 0, 0, 0);
    1161               0 :         t->maintenance = m;
    1162               0 :         pthread_rwlock_unlock (&t->state_lock);
    1163                 : 
    1164               0 :         if (m != NULL)
    1165               0 :                 return 0;
    1166                 : #else
    1167                 :         (void)t;
    1168                 :         (void)s;
    1169                 :         (void)s2;
    1170                 : #endif
    1171               0 :         return -1;
    1172                 : }
    1173                 : 
    1174                 : 
    1175                 : /**
    1176                 :  * Thread-safety: FIXME.
    1177                 :  */
    1178                 : void *teredo_set_privdata (teredo_tunnel *t, void *opaque)
    1179               0 : {
    1180               0 :         assert (t != NULL);
    1181                 : 
    1182               0 :         void *prev = t->opaque;
    1183               0 :         t->opaque = opaque;
    1184               0 :         return prev;
    1185                 : }
    1186                 : 
    1187                 : 
    1188                 : /**
    1189                 :  * Thread-safety: FIXME.
    1190                 :  */
    1191                 : void *teredo_get_privdata (const teredo_tunnel *t)
    1192               0 : {
    1193               0 :         assert (t != NULL);
    1194                 : 
    1195               0 :         return t->opaque;
    1196                 : }
    1197                 : 
    1198                 : 
    1199                 : /**
    1200                 :  * Thread-safety: FIXME.
    1201                 :  */
    1202                 : void teredo_set_recv_callback (teredo_tunnel *restrict t, teredo_recv_cb cb)
    1203               0 : {
    1204               0 :         assert (t != NULL);
    1205               0 :         t->recv_cb = (cb != NULL) ? cb : teredo_dummy_recv_cb;
    1206               0 : }
    1207                 : 
    1208                 : 
    1209                 : /**
    1210                 :  * Thread-safety: FIXME.
    1211                 :  */
    1212                 : void teredo_set_icmpv6_callback (teredo_tunnel *restrict t,
    1213                 :                                  teredo_icmpv6_cb cb)
    1214               0 : {
    1215               0 :         assert (t != NULL);
    1216               0 :         t->icmpv6_cb = (cb != NULL) ? cb : teredo_dummy_icmpv6_cb;
    1217               0 : }
    1218                 : 
    1219                 : 
    1220                 : /**
    1221                 :  * Registers callbacks to be called when the Teredo client maintenance
    1222                 :  * procedure detects that the tunnel becomes usable (or has got a new IPv6
    1223                 :  * address, or a new MTU), or unusable respectively.
    1224                 :  * These callbacks are ignored for a Teredo relay tunnel.
    1225                 :  *
    1226                 :  * Any packet sent when the relay/client is down will be ignored.
    1227                 :  * The callbacks function might be called from a separate thread.
    1228                 :  *
    1229                 :  * Thread-safety: This function is thread-safe.
    1230                 :  *
    1231                 :  * If a callback is set to NULL, it is ignored.
    1232                 :  */
    1233                 : void teredo_set_state_cb (teredo_tunnel *restrict t, teredo_state_up_cb u,
    1234                 :                           teredo_state_down_cb d)
    1235               0 : {
    1236                 : #ifdef MIREDO_TEREDO_CLIENT
    1237               0 :         assert (t != NULL);
    1238                 : 
    1239               0 :         pthread_rwlock_wrlock (&t->state_lock);
    1240               0 :         t->up_cb = (u != NULL) ? u : teredo_dummy_state_up_cb;
    1241               0 :         t->down_cb = (d != NULL) ? d : teredo_dummy_state_down_cb;
    1242               0 :         pthread_rwlock_unlock (&t->state_lock);
    1243                 : #else
    1244                 :         (void)t;
    1245                 :         (void)u;
    1246                 :         (void)d;
    1247                 : #endif
    1248               0 : }

Generated by: LTP GCOV extension version 1.5