]> git.meshlink.io Git - meshlink/commitdiff
Merge branch 'master' of git://tinc-vpn.org/tinc into 1.1
authorGuus Sliepen <guus@tinc-vpn.org>
Sat, 25 Feb 2012 21:52:57 +0000 (22:52 +0100)
committerGuus Sliepen <guus@tinc-vpn.org>
Sat, 25 Feb 2012 21:52:57 +0000 (22:52 +0100)
1  2 
src/route.c

diff --combined src/route.c
index 32be4dec404f06c2fffe6e53ef7c699343d064d0,666f48f6b4631d32e5021d1428bc8b607517f658..c73ac9f2e5374c9aaba874bdefd3381b7666d797
  
  #include "system.h"
  
 -#include "avl_tree.h"
 +#include "splay_tree.h"
  #include "connection.h"
 +#include "control_common.h"
  #include "ethernet.h"
  #include "ipv4.h"
  #include "ipv6.h"
  #include "logger.h"
 +#include "meta.h"
  #include "net.h"
  #include "protocol.h"
  #include "route.h"
@@@ -43,7 -41,6 +43,7 @@@ int macexpire = 600
  bool overwrite_mac = false;
  bool broadcast = true;
  mac_t mymac = {{0xFE, 0xFD, 0, 0, 0, 0}};
 +bool pcap = false;
  
  /* Sizes of various headers */
  
@@@ -60,8 -57,6 +60,8 @@@ static const size_t opt_size = sizeof(s
  #define MAX(a, b) ((a) > (b) ? (a) : (b))
  #endif
  
 +static struct event age_subnets_event;
 +
  /* RFC 1071 */
  
  static uint16_t inet_checksum(void *data, int len, uint16_t prevsum) {
  static bool ratelimit(int frequency) {
        static time_t lasttime = 0;
        static int count = 0;
 +      time_t now = time(NULL);
        
        if(lasttime == now) {
-               if(++count > frequency)
+               if(count >= frequency)
                        return true;
        } else {
                lasttime = now;
                count = 0;
        }
  
+       count++;
        return false;
  }
  
@@@ -185,43 -180,9 +186,43 @@@ static void swap_mac_addresses(vpn_pack
        memcpy(&packet->data[6], &tmp, sizeof tmp);
  }
        
 +static void age_subnets(int fd, short events, void *data) {
 +      subnet_t *s;
 +      connection_t *c;
 +      splay_node_t *node, *next, *node2;
 +      bool left = false;
 +      time_t now = time(NULL);
 +
 +      for(node = myself->subnet_tree->head; node; node = next) {
 +              next = node->next;
 +              s = node->data;
 +              if(s->expires && s->expires < now) {
 +                      ifdebug(TRAFFIC) {
 +                              char netstr[MAXNETSTR];
 +                              if(net2str(netstr, sizeof netstr, s))
 +                                      logger(LOG_INFO, "Subnet %s expired", netstr);
 +                      }
 +
 +                      for(node2 = connection_tree->head; node2; node2 = node2->next) {
 +                              c = node2->data;
 +                              if(c->status.active)
 +                                      send_del_subnet(c, s);
 +                      }
 +
 +                      subnet_del(myself, s);
 +              } else {
 +                      if(s->expires)
 +                              left = true;
 +              }
 +      }
 +
 +      if(left)
 +              event_add(&age_subnets_event, &(struct timeval){10, 0});
 +}
 +
  static void learn_mac(mac_t *address) {
        subnet_t *subnet;
 -      avl_node_t *node;
 +      splay_node_t *node;
        connection_t *c;
  
        subnet = lookup_subnet_mac(myself, address);
  
                subnet = new_subnet();
                subnet->type = SUBNET_MAC;
 -              subnet->expires = now + macexpire;
 +              subnet->expires = time(NULL) + macexpire;
                subnet->net.mac.address = *address;
                subnet->weight = 10;
                subnet_add(myself, subnet);
                        if(c->status.active)
                                send_add_subnet(c, subnet);
                }
 -      }
  
 -      if(subnet->expires)
 -              subnet->expires = now + macexpire;
 -}
 -
 -void age_subnets(void) {
 -      subnet_t *s;
 -      connection_t *c;
 -      avl_node_t *node, *next, *node2;
 -
 -      for(node = myself->subnet_tree->head; node; node = next) {
 -              next = node->next;
 -              s = node->data;
 -              if(s->expires && s->expires <= now) {
 -                      ifdebug(TRAFFIC) {
 -                              char netstr[MAXNETSTR];
 -                              if(net2str(netstr, sizeof netstr, s))
 -                                      logger(LOG_INFO, "Subnet %s expired", netstr);
 -                      }
 -
 -                      for(node2 = connection_tree->head; node2; node2 = node2->next) {
 -                              c = node2->data;
 -                              if(c->status.active)
 -                                      send_del_subnet(c, s);
 -                      }
 -
 -                      subnet_update(myself, s, false);
 -                      subnet_del(myself, s);
 -              }
 +              if(!timeout_initialized(&age_subnets_event))
 +                      timeout_set(&age_subnets_event, age_subnets, NULL);
 +              event_add(&age_subnets_event, &(struct timeval){10, 0});
 +      } else {
 +              if(subnet->expires)
 +                      subnet->expires = time(NULL) + macexpire;
        }
  }
  
@@@ -349,7 -333,7 +350,7 @@@ static void fragment_ipv4_packet(node_
        todo = ntohs(ip.ip_len) - ip_size;
  
        if(ether_size + ip_size + todo != packet->len) {
 -              ifdebug(TRAFFIC) logger(LOG_WARNING, "Length of packet (%d) doesn't match length in IPv4 header (%zd)", packet->len, ether_size + ip_size + todo);
 +              ifdebug(TRAFFIC) logger(LOG_WARNING, "Length of packet (%d) doesn't match length in IPv4 header (%d)", packet->len, (int)(ether_size + ip_size + todo));
                return;
        }
  
@@@ -416,6 -400,11 +417,11 @@@ static void route_ipv4_unicast(node_t *
                packet->priority = packet->data[15];
  
        via = (subnet->owner->via == myself) ? subnet->owner->nexthop : subnet->owner->via;
+       if(via == source) {
+               ifdebug(TRAFFIC) logger(LOG_ERR, "Routing loop for packet from %s (%s)!", source->name, source->hostname);
+               return;
+       }
        
        if(directonly && subnet->owner != via)
                return route_ipv4_unreachable(source, packet, ICMP_DEST_UNREACH, ICMP_NET_ANO);
@@@ -515,7 -504,7 +521,7 @@@ static void route_ipv6_unreachable(node
  
        /* Generate checksum */
        
 -      checksum = inet_checksum(&pseudo, sizeof(pseudo), ~0);
 +      checksum = inet_checksum(&pseudo, sizeof pseudo, ~0);
        checksum = inet_checksum(&icmp6, icmp6_size, checksum);
        checksum = inet_checksum(packet->data + ether_size + ip6_size + icmp6_size, ntohl(pseudo.length) - icmp6_size, checksum);
  
@@@ -568,6 -557,11 +574,11 @@@ static void route_ipv6_unicast(node_t *
  
        via = (subnet->owner->via == myself) ? subnet->owner->nexthop : subnet->owner->via;
        
+       if(via == source) {
+               ifdebug(TRAFFIC) logger(LOG_ERR, "Routing loop for packet from %s (%s)!", source->name, source->hostname);
+               return;
+       }
+       
        if(directonly && subnet->owner != via)
                return route_ipv6_unreachable(source, packet, ICMP6_DST_UNREACH, ICMP6_DST_UNREACH_ADMIN);
  
@@@ -642,7 -636,7 +653,7 @@@ static void route_neighborsol(node_t *s
  
        /* Generate checksum */
  
 -      checksum = inet_checksum(&pseudo, sizeof(pseudo), ~0);
 +      checksum = inet_checksum(&pseudo, sizeof pseudo, ~0);
        checksum = inet_checksum(&ns, ns_size, checksum);
        if(has_opt) {
                checksum = inet_checksum(&opt, opt_size, checksum);
  
        /* Generate checksum */
  
 -      checksum = inet_checksum(&pseudo, sizeof(pseudo), ~0);
 +      checksum = inet_checksum(&pseudo, sizeof pseudo, ~0);
        checksum = inet_checksum(&ns, ns_size, checksum);
        if(has_opt) {
                checksum = inet_checksum(&opt, opt_size, checksum);
@@@ -766,7 -760,7 +777,7 @@@ static void route_arp(node_t *source, v
        /* Check if this is a valid ARP request */
  
        if(ntohs(arp.arp_hrd) != ARPHRD_ETHER || ntohs(arp.arp_pro) != ETH_P_IP ||
 -         arp.arp_hln != ETH_ALEN || arp.arp_pln != sizeof(addr) || ntohs(arp.arp_op) != ARPOP_REQUEST) {
 +         arp.arp_hln != ETH_ALEN || arp.arp_pln != sizeof addr || ntohs(arp.arp_op) != ARPOP_REQUEST) {
                ifdebug(TRAFFIC) logger(LOG_WARNING, "Cannot route packet: received unknown type ARP request");
                return;
        }
        memcpy(packet->data, packet->data + ETH_ALEN, ETH_ALEN);        /* copy destination address */
        packet->data[ETH_ALEN * 2 - 1] ^= 0xFF; /* mangle source address so it looks like it's not from us */
  
 -      memcpy(&addr, arp.arp_tpa, sizeof(addr));       /* save protocol addr */
 -      memcpy(arp.arp_tpa, arp.arp_spa, sizeof(addr)); /* swap destination and source protocol address */
 -      memcpy(arp.arp_spa, &addr, sizeof(addr));       /* ... */
 +      memcpy(&addr, arp.arp_tpa, sizeof addr);        /* save protocol addr */
 +      memcpy(arp.arp_tpa, arp.arp_spa, sizeof addr);  /* swap destination and source protocol address */
 +      memcpy(arp.arp_spa, &addr, sizeof addr);        /* ... */
  
        memcpy(arp.arp_tha, arp.arp_sha, ETH_ALEN);     /* set target hard/proto addr */
        memcpy(arp.arp_sha, packet->data + ETH_ALEN, ETH_ALEN); /* add fake source hard addr */
@@@ -866,19 -860,6 +877,19 @@@ static void route_mac(node_t *source, v
        send_packet(subnet->owner, packet);
  }
  
 +static void send_pcap(vpn_packet_t *packet) {
 +      pcap = false;
 +      for(splay_node_t *node = connection_tree->head; node; node = node->next) {
 +              connection_t *c = node->data;
 +              if(!c->status.pcap)
 +                      continue;
 +              else
 +                      pcap = true;
 +              if(send_request(c, "%d %d %d", CONTROL, REQ_PCAP, packet->len))
 +                      send_meta(c, (char *)packet->data, packet->len);
 +      }
 +}
 +
  static bool do_decrement_ttl(node_t *source, vpn_packet_t *packet) {
        uint16_t type = packet->data[12] << 8 | packet->data[13];
  
                                return false;
  
                        if(packet->data[22] < 1) {
-                               route_ipv4_unreachable(source, packet, ICMP_TIME_EXCEEDED, ICMP_EXC_TTL);
+                               if(packet->data[25] != IPPROTO_ICMP || packet->data[46] != ICMP_TIME_EXCEEDED)
+                                       route_ipv4_unreachable(source, packet, ICMP_TIME_EXCEEDED, ICMP_EXC_TTL);
                                return false;
                        }
  
                                return false;
  
                        if(packet->data[21] < 1) {
-                               route_ipv6_unreachable(source, packet, ICMP6_TIME_EXCEEDED, ICMP6_TIME_EXCEED_TRANSIT);
+                               if(packet->data[20] != IPPROTO_ICMPV6 || packet->data[54] != ICMP6_TIME_EXCEEDED)
+                                       route_ipv6_unreachable(source, packet, ICMP6_TIME_EXCEEDED, ICMP6_TIME_EXCEED_TRANSIT);
                                return false;
                        }
  
  }
  
  void route(node_t *source, vpn_packet_t *packet) {
 +      if(pcap)
 +              send_pcap(packet);
 +
        if(forwarding_mode == FMODE_KERNEL && source != myself) {
                send_packet(myself, packet);
                return;