Code beautification, start of multicast support.
authorGuus Sliepen <guus@tinc-vpn.org>
Fri, 12 Dec 2003 19:52:25 +0000 (19:52 +0000)
committerGuus Sliepen <guus@tinc-vpn.org>
Fri, 12 Dec 2003 19:52:25 +0000 (19:52 +0000)
src/conf.c
src/net.c
src/net_packet.c
src/net_socket.c
src/protocol_subnet.c
src/route.c
src/route.h
src/subnet.c
src/subnet.h

index 57bee09..d0a2d2d 100644 (file)
@@ -19,7 +19,7 @@
     along with this program; if not, write to the Free Software
     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 
-    $Id: conf.c,v 1.9.4.76 2003/08/28 21:05:10 guus Exp $
+    $Id: conf.c,v 1.9.4.77 2003/12/12 19:52:24 guus Exp $
 */
 
 #include "system.h"
@@ -214,16 +214,14 @@ bool get_config_address(const config_t *cfg, struct addrinfo **result)
 
 bool get_config_subnet(const config_t *cfg, subnet_t ** result)
 {
-       subnet_t *subnet;
+       subnet_t subnet = {0};
 
        cp();
 
        if(!cfg)
                return false;
 
-       subnet = str2net(cfg->value);
-
-       if(!subnet) {
+       if(!str2net(&subnet, cfg->value)) {
                logger(LOG_ERR, _("Subnet expected for configuration variable %s in %s line %d"),
                           cfg->variable, cfg->file, cfg->line);
                return false;
@@ -231,17 +229,16 @@ bool get_config_subnet(const config_t *cfg, subnet_t ** result)
 
        /* Teach newbies what subnets are... */
 
-       if(((subnet->type == SUBNET_IPV4)
-               && !maskcheck(&subnet->net.ipv4.address, subnet->net.ipv4.prefixlength, sizeof(ipv4_t)))
-               || ((subnet->type == SUBNET_IPV6)
-               && !maskcheck(&subnet->net.ipv6.address, subnet->net.ipv6.prefixlength, sizeof(ipv6_t)))) {
+       if(((subnet.type == SUBNET_IPV4)
+               && !maskcheck(&subnet.net.ipv4.address, subnet.net.ipv4.prefixlength, sizeof(ipv4_t)))
+               || ((subnet.type == SUBNET_IPV6)
+               && !maskcheck(&subnet.net.ipv6.address, subnet.net.ipv6.prefixlength, sizeof(ipv6_t)))) {
                logger(LOG_ERR, _ ("Network address and prefix length do not match for configuration variable %s in %s line %d"),
                           cfg->variable, cfg->file, cfg->line);
-               free(subnet);
                return false;
        }
 
-       *result = subnet;
+       *(*result = new_subnet()) = subnet;
 
        return true;
 }
index e0b5e6f..1644976 100644 (file)
--- a/src/net.c
+++ b/src/net.c
@@ -17,7 +17,7 @@
     along with this program; if not, write to the Free Software
     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 
-    $Id: net.c,v 1.35.4.201 2003/11/17 15:30:17 guus Exp $
+    $Id: net.c,v 1.35.4.202 2003/12/12 19:52:24 guus Exp $
 */
 
 #include "system.h"
@@ -270,7 +270,7 @@ static void check_network_activity(fd_set * f)
 
        if(FD_ISSET(device_fd, f)) {
                if(read_packet(&packet))
-                       route_outgoing(&packet);
+                       route(myself, &packet);
        }
 
        for(node = connection_tree->head; node; node = node->next) {
@@ -367,7 +367,7 @@ int main_loop(void)
                        last_ping_check = now;
 
                        if(routing_mode == RMODE_SWITCH)
-                               age_mac();
+                               age_subnets();
 
                        age_past_requests();
 
index d64b6bf..af34d05 100644 (file)
@@ -17,7 +17,7 @@
     along with this program; if not, write to the Free Software
     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 
-    $Id: net_packet.c,v 1.1.2.43 2003/10/11 12:16:12 guus Exp $
+    $Id: net_packet.c,v 1.1.2.44 2003/12/12 19:52:25 guus Exp $
 */
 
 #include "system.h"
@@ -104,7 +104,7 @@ static void receive_packet(node_t *n, vpn_packet_t *packet)
        ifdebug(TRAFFIC) logger(LOG_DEBUG, _("Received packet of %d bytes from %s (%s)"),
                           packet->len, n->name, n->hostname);
 
-       route_incoming(n, packet);
+       route(n, packet);
 }
 
 static void receive_udppacket(node_t *n, vpn_packet_t *inpkt)
@@ -242,8 +242,7 @@ static void send_udppacket(node_t *n, vpn_packet_t *inpkt)
 
                /* Since packet is on the stack of handle_tap_input(), we have to make a copy of it first. */
 
-               copy = xmalloc(sizeof(vpn_packet_t));
-               memcpy(copy, inpkt, sizeof(vpn_packet_t));
+               *(copy = xmalloc(sizeof(*copy))) = *inpkt;
 
                list_insert_tail(n->queue, copy);
 
@@ -344,14 +343,14 @@ void send_packet(const node_t *n, vpn_packet_t *packet)
 
        cp();
 
-       ifdebug(TRAFFIC) logger(LOG_ERR, _("Sending packet of %d bytes to %s (%s)"),
-                          packet->len, n->name, n->hostname);
-
        if(n == myself) {
-               ifdebug(TRAFFIC) logger(LOG_NOTICE, _("Packet is looping back to us!"));
+               write_packet(packet);
                return;
        }
 
+       ifdebug(TRAFFIC) logger(LOG_ERR, _("Sending packet of %d bytes to %s (%s)"),
+                          packet->len, n->name, n->hostname);
+
        if(!n->status.reachable) {
                ifdebug(TRAFFIC) logger(LOG_INFO, _("Node %s (%s) is not reachable"),
                                   n->name, n->hostname);
index 10f2ca0..4e4a008 100644 (file)
@@ -17,7 +17,7 @@
     along with this program; if not, write to the Free Software
     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 
-    $Id: net_socket.c,v 1.1.2.34 2003/10/06 14:41:45 guus Exp $
+    $Id: net_socket.c,v 1.1.2.35 2003/12/12 19:52:25 guus Exp $
 */
 
 #include "system.h"
@@ -255,8 +255,7 @@ begin:
                goto begin;
        }
 
-       memcpy(&c->address, c->outgoing->aip->ai_addr,
-                  c->outgoing->aip->ai_addrlen);
+       memcpy(&c->address, c->outgoing->aip->ai_addr, c->outgoing->aip->ai_addrlen);
        c->outgoing->aip = c->outgoing->aip->ai_next;
 
        if(c->hostname)
index e0297b9..76cdd49 100644 (file)
@@ -17,7 +17,7 @@
     along with this program; if not, write to the Free Software
     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 
-    $Id: protocol_subnet.c,v 1.1.4.17 2003/11/17 15:30:18 guus Exp $
+    $Id: protocol_subnet.c,v 1.1.4.18 2003/12/12 19:52:25 guus Exp $
 */
 
 #include "system.h"
 
 bool send_add_subnet(connection_t *c, const subnet_t *subnet)
 {
-       bool x;
-       char *netstr;
+       char netstr[MAXNETSTR];
 
        cp();
 
-       x = send_request(c, "%d %lx %s %s", ADD_SUBNET, random(),
-                                        subnet->owner->name, netstr = net2str(subnet));
-
-       free(netstr);
+       if(!net2str(netstr, sizeof netstr, subnet))
+               return false;
 
-       return x;
+       return send_request(c, "%d %lx %s %s", ADD_SUBNET, random(), subnet->owner->name, netstr);
 }
 
 bool add_subnet_h(connection_t *c)
@@ -53,7 +50,7 @@ bool add_subnet_h(connection_t *c)
        char subnetstr[MAX_STRING_SIZE];
        char name[MAX_STRING_SIZE];
        node_t *owner;
-       subnet_t *s;
+       subnet_t s = {0}, *new;
 
        cp();
 
@@ -73,9 +70,7 @@ bool add_subnet_h(connection_t *c)
 
        /* Check if subnet string is valid */
 
-       s = str2net(subnetstr);
-
-       if(!s) {
+       if(!str2net(&s, subnetstr)) {
                logger(LOG_ERR, _("Got bad %s from %s (%s): %s"), "ADD_SUBNET", c->name,
                           c->hostname, _("invalid subnet string"));
                return false;
@@ -99,18 +94,16 @@ bool add_subnet_h(connection_t *c)
 
        /* Check if we already know this subnet */
 
-       if(lookup_subnet(owner, s)) {
-               free_subnet(s);
+       if(lookup_subnet(owner, &s))
                return true;
-       }
 
        /* If we don't know this subnet, but we are the owner, retaliate with a DEL_SUBNET */
 
        if(owner == myself) {
                ifdebug(PROTOCOL) logger(LOG_WARNING, _("Got %s from %s (%s) for ourself"),
                                   "ADD_SUBNET", c->name, c->hostname);
-               s->owner = myself;
-               send_del_subnet(c, s);
+               s.owner = myself;
+               send_del_subnet(c, &s);
                return true;
        }
 
@@ -124,7 +117,7 @@ bool add_subnet_h(connection_t *c)
                        if(!get_config_subnet(cfg, &allowed))
                                return false;
 
-                       if(!subnet_compare(s, allowed))
+                       if(!subnet_compare(&s, allowed))
                                break;
 
                        free_subnet(allowed);
@@ -138,7 +131,8 @@ bool add_subnet_h(connection_t *c)
 
        /* If everything is correct, add the subnet to the list of the owner */
 
-       subnet_add(owner, s);
+       *(new = new_subnet()) = s;
+       subnet_add(owner, new);
 
        /* Tell the rest */
 
@@ -150,18 +144,14 @@ bool add_subnet_h(connection_t *c)
 
 bool send_del_subnet(connection_t *c, const subnet_t *s)
 {
-       bool x;
-       char *netstr;
+       char netstr[MAXNETSTR];
 
        cp();
 
-       netstr = net2str(s);
-
-       x = send_request(c, "%d %lx %s %s", DEL_SUBNET, random(), s->owner->name, netstr);
-
-       free(netstr);
+       if(!net2str(netstr, sizeof netstr, s))
+               return false;
 
-       return x;
+       return send_request(c, "%d %lx %s %s", DEL_SUBNET, random(), s->owner->name, netstr);
 }
 
 bool del_subnet_h(connection_t *c)
@@ -169,7 +159,7 @@ bool del_subnet_h(connection_t *c)
        char subnetstr[MAX_STRING_SIZE];
        char name[MAX_STRING_SIZE];
        node_t *owner;
-       subnet_t *s, *find;
+       subnet_t s = {0}, *find;
 
        cp();
 
@@ -202,9 +192,7 @@ bool del_subnet_h(connection_t *c)
 
        /* Check if subnet string is valid */
 
-       s = str2net(subnetstr);
-
-       if(!s) {
+       if(!str2net(&s, subnetstr)) {
                logger(LOG_ERR, _("Got bad %s from %s (%s): %s"), "DEL_SUBNET", c->name,
                           c->hostname, _("invalid subnet string"));
                return false;
@@ -215,11 +203,9 @@ bool del_subnet_h(connection_t *c)
 
        /* If everything is correct, delete the subnet from the list of the owner */
 
-       s->owner = owner;
-
-       find = lookup_subnet(owner, s);
+       s.owner = owner;
 
-       free_subnet(s);
+       find = lookup_subnet(owner, &s);
 
        if(!find) {
                ifdebug(PROTOCOL) logger(LOG_WARNING, _("Got %s from %s (%s) for %s which does not appear in his subnet tree"),
index b586157..6d391cd 100644 (file)
@@ -17,7 +17,7 @@
     along with this program; if not, write to the Free Software
     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 
-    $Id: route.c,v 1.1.2.69 2003/12/08 12:00:40 guus Exp $
+    $Id: route.c,v 1.1.2.70 2003/12/12 19:52:25 guus Exp $
 */
 
 #include "system.h"
@@ -40,7 +40,6 @@
 
 #include "avl_tree.h"
 #include "connection.h"
-#include "device.h"
 #include "ethernet.h"
 #include "ipv4.h"
 #include "ipv6.h"
@@ -54,6 +53,7 @@
 rmode_t routing_mode = RMODE_ROUTER;
 bool priorityinheritance = false;
 int macexpire = 600;
+int multicastexpire = 375;
 bool overwrite_mac = false;
 mac_t mymac = {{0xFE, 0xFD, 0, 0, 0, 0}};
 
@@ -81,7 +81,7 @@ static uint16_t inet_checksum(void *data, int len, uint16_t prevsum)
        }
        
        if(len)
-               checksum += *(unsigned char *)p;
+               checksum += *(uint8_t *)p;
 
        while(checksum >> 16)
                checksum = (checksum & 0xFFFF) + (checksum >> 16);
@@ -103,6 +103,14 @@ static bool ratelimit(int frequency) {
 
        return false;
 }
+
+static bool checklength(node_t *source, vpn_packet_t *packet, length_t length) {
+       if(packet->len < length) {
+               ifdebug(TRAFFIC) logger(LOG_WARNING, _("Got too short packet from %s (%s)"), source->name, source->hostname);
+               return false;
+       } else
+               return true;
+}
        
 static void learn_mac(mac_t *address)
 {
@@ -116,14 +124,15 @@ static void learn_mac(mac_t *address)
 
        /* If we don't know this MAC address yet, store it */
 
-       if(!subnet || subnet->owner != myself) {
+       if(!subnet) {
                ifdebug(TRAFFIC) logger(LOG_INFO, _("Learned new MAC address %hx:%hx:%hx:%hx:%hx:%hx"),
                                   address->x[0], address->x[1], address->x[2], address->x[3],
                                   address->x[4], address->x[5]);
 
                subnet = new_subnet();
                subnet->type = SUBNET_MAC;
-               memcpy(&subnet->net.mac.address, address, sizeof(mac_t));
+               subnet->expires = now + macexpire;
+               subnet->net.mac.address = *address;
                subnet_add(myself, subnet);
 
                /* And tell all other tinc daemons it's our MAC */
@@ -135,10 +144,11 @@ static void learn_mac(mac_t *address)
                }
        }
 
-       subnet->net.mac.lastseen = now;
+       if(subnet->expires)
+               subnet->expires = now + macexpire;
 }
 
-void age_mac(void)
+void age_subnets(void)
 {
        subnet_t *s;
        connection_t *c;
@@ -149,11 +159,12 @@ void age_mac(void)
        for(node = myself->subnet_tree->head; node; node = next) {
                next = node->next;
                s = node->data;
-               if(s->type == SUBNET_MAC && s->net.mac.lastseen && s->net.mac.lastseen + macexpire < now) {
-                       ifdebug(TRAFFIC) logger(LOG_INFO, _("MAC address %hx:%hx:%hx:%hx:%hx:%hx expired"),
-                                          s->net.mac.address.x[0], s->net.mac.address.x[1],
-                                          s->net.mac.address.x[2], s->net.mac.address.x[3],
-                                          s->net.mac.address.x[4], s->net.mac.address.x[5]);
+               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;
@@ -166,7 +177,7 @@ void age_mac(void)
        }
 }
 
-static node_t *route_mac(vpn_packet_t *packet)
+static void route_mac(node_t *source, vpn_packet_t *packet)
 {
        subnet_t *subnet;
 
@@ -174,24 +185,32 @@ static node_t *route_mac(vpn_packet_t *packet)
 
        /* Learn source address */
 
-       learn_mac((mac_t *)(&packet->data[6]));
+       if(source == myself)
+               learn_mac((mac_t *)(&packet->data[6]));
 
        /* Lookup destination address */
 
        subnet = lookup_subnet_mac((mac_t *)(&packet->data[0]));
 
-       if(subnet)
-               return subnet->owner;
-       else
-               return NULL;
+       if(!subnet) {
+               broadcast_packet(source, packet);
+               return;
+       }
+
+       if(subnet->owner == source) {
+               ifdebug(TRAFFIC) logger(LOG_WARNING, _("Packet looping back to %s (%s)!"), source->name, source->hostname);
+               return;
+       }
+
+       send_packet(subnet->owner, packet);
 }
 
 /* RFC 792 */
 
-static void route_ipv4_unreachable(vpn_packet_t *packet, uint8_t code)
+static void route_ipv4_unreachable(node_t *source, vpn_packet_t *packet, uint8_t code)
 {
-       struct ip ip;
-       struct icmp icmp;
+       struct ip ip = {0};
+       struct icmp icmp = {0};
        
        struct in_addr ip_src;
        struct in_addr ip_dst;
@@ -205,15 +224,14 @@ static void route_ipv4_unreachable(vpn_packet_t *packet, uint8_t code)
        /* Copy headers from packet into properly aligned structs on the stack */
 
        memcpy(&ip, packet->data + ether_size, ip_size);
-       memcpy(&icmp, packet->data + ether_size + ip_size, icmp_size);
 
        /* Remember original source and destination */
-               
-       memcpy(&ip_src, &ip.ip_src, sizeof(ip_src));
-       memcpy(&ip_dst, &ip.ip_dst, sizeof(ip_dst));
+       
+       ip_src = ip.ip_src;
+       ip_dst = ip.ip_dst;
 
        oldlen = packet->len - ether_size;
-       
+
        if(oldlen >= IP_MSS - ip_size - icmp_size)
                oldlen = IP_MSS - ip_size - icmp_size;
        
@@ -232,8 +250,8 @@ static void route_ipv4_unreachable(vpn_packet_t *packet, uint8_t code)
        ip.ip_ttl = 255;
        ip.ip_p = IPPROTO_ICMP;
        ip.ip_sum = 0;
-       memcpy(&ip.ip_src, &ip_dst, sizeof(ip_src));
-       memcpy(&ip.ip_dst, &ip_src, sizeof(ip_dst));
+       ip.ip_src = ip_dst;
+       ip.ip_dst = ip_src;
 
        ip.ip_sum = inet_checksum(&ip, ip_size, ~0);
        
@@ -253,41 +271,66 @@ static void route_ipv4_unreachable(vpn_packet_t *packet, uint8_t code)
        
        packet->len = ether_size + ip_size + icmp_size + oldlen;
        
-       write_packet(packet);
+       send_packet(source, packet);
 }
 
-static node_t *route_ipv4(vpn_packet_t *packet)
+static void route_ipv4_unicast(node_t *source, vpn_packet_t *packet)
 {
        subnet_t *subnet;
 
        cp();
 
-       if(priorityinheritance)
-               packet->priority = packet->data[15];
-
        subnet = lookup_subnet_ipv4((ipv4_t *) &packet->data[30]);
 
        if(!subnet) {
-               ifdebug(TRAFFIC) logger(LOG_WARNING, _("Cannot route packet: unknown IPv4 destination address %d.%d.%d.%d"),
-                                  packet->data[30], packet->data[31], packet->data[32],
-                                  packet->data[33]);
-
-               route_ipv4_unreachable(packet, ICMP_NET_UNKNOWN);
-               return NULL;
+               ifdebug(TRAFFIC) logger(LOG_WARNING, _("Cannot route packet from %s (%s): unknown IPv4 destination address %d.%d.%d.%d"),
+                               source->name, source->hostname,
+                               packet->data[30],
+                               packet->data[31],
+                               packet->data[32],
+                               packet->data[33]);
+
+               route_ipv4_unreachable(source, packet, ICMP_NET_UNKNOWN);
+               return;
        }
        
+       if(subnet->owner == source) {
+               ifdebug(TRAFFIC) logger(LOG_WARNING, _("Packet looping back to %s (%s)!"), source->name, source->hostname);
+               return;
+       }
+
        if(!subnet->owner->status.reachable)
-               route_ipv4_unreachable(packet, ICMP_NET_UNREACH);
+               route_ipv4_unreachable(source, packet, ICMP_NET_UNREACH);
+
+       if(priorityinheritance)
+               packet->priority = packet->data[15];
 
-       return subnet->owner;
+       send_packet(subnet->owner, packet);
+}
+
+static void route_ipv4(node_t *source, vpn_packet_t *packet)
+{
+       cp();
+
+       if(!checklength(source, packet, ether_size + ip_size))
+               return;
+
+#if 0
+       if(packet->data[30] & 0xf0 == 0xe0) {
+               route_ipv4_multicast(source, packet);
+               return;
+       }
+#endif
+
+       route_ipv4_unicast(source, packet);
 }
 
 /* RFC 2463 */
 
-static void route_ipv6_unreachable(vpn_packet_t *packet, uint8_t code)
+static void route_ipv6_unreachable(node_t *source, vpn_packet_t *packet, uint8_t code)
 {
        struct ip6_hdr ip6;
-       struct icmp6_hdr icmp6;
+       struct icmp6_hdr icmp6 = {0};
        uint16_t checksum;      
 
        struct {
@@ -305,14 +348,13 @@ static void route_ipv6_unreachable(vpn_packet_t *packet, uint8_t code)
        /* Copy headers from packet to structs on the stack */
 
        memcpy(&ip6, packet->data + ether_size, ip6_size);
-       memcpy(&icmp6, packet->data + ether_size + ip6_size, icmp6_size);
 
        /* Remember original source and destination */
-               
-       memcpy(&pseudo.ip6_src, &ip6.ip6_dst, sizeof(ip6.ip6_src));
-       memcpy(&pseudo.ip6_dst, &ip6.ip6_src, sizeof(ip6.ip6_dst));
+       
+       pseudo.ip6_src = ip6.ip6_dst;
+       pseudo.ip6_dst = ip6.ip6_src;
 
-       pseudo.length = ntohs(ip6.ip6_plen) + ip6_size;
+       pseudo.length = packet->len - ether_size;
        
        if(pseudo.length >= IP_MSS - ip6_size - icmp6_size)
                pseudo.length = IP_MSS - ip6_size - icmp6_size;
@@ -327,8 +369,8 @@ static void route_ipv6_unreachable(vpn_packet_t *packet, uint8_t code)
        ip6.ip6_plen = htons(icmp6_size + pseudo.length);
        ip6.ip6_nxt = IPPROTO_ICMPV6;
        ip6.ip6_hlim = 255;
-       memcpy(&ip6.ip6_src, &pseudo.ip6_src, sizeof(ip6.ip6_src));
-       memcpy(&ip6.ip6_dst, &pseudo.ip6_dst, sizeof(ip6.ip6_dst));
+       ip6.ip6_src = pseudo.ip6_src;
+       ip6.ip6_dst = pseudo.ip6_dst;
 
        /* Fill in ICMP header */
        
@@ -356,10 +398,10 @@ static void route_ipv6_unreachable(vpn_packet_t *packet, uint8_t code)
        
        packet->len = ether_size + ip6_size + ntohl(pseudo.length);
        
-       write_packet(packet);
+       send_packet(source, packet);
 }
 
-static node_t *route_ipv6(vpn_packet_t *packet)
+static void route_ipv6_unicast(node_t *source, vpn_packet_t *packet)
 {
        subnet_t *subnet;
 
@@ -368,29 +410,62 @@ static node_t *route_ipv6(vpn_packet_t *packet)
        subnet = lookup_subnet_ipv6((ipv6_t *) &packet->data[38]);
 
        if(!subnet) {
-               ifdebug(TRAFFIC) logger(LOG_WARNING, _("Cannot route packet: unknown IPv6 destination address %hx:%hx:%hx:%hx:%hx:%hx:%hx:%hx"),
-                                  ntohs(*(uint16_t *) &packet->data[38]),
-                                  ntohs(*(uint16_t *) &packet->data[40]),
-                                  ntohs(*(uint16_t *) &packet->data[42]),
-                                  ntohs(*(uint16_t *) &packet->data[44]),
-                                  ntohs(*(uint16_t *) &packet->data[46]),
-                                  ntohs(*(uint16_t *) &packet->data[48]),
-                                  ntohs(*(uint16_t *) &packet->data[50]),
-                                  ntohs(*(uint16_t *) &packet->data[52]));
-               route_ipv6_unreachable(packet, ICMP6_DST_UNREACH_ADDR);
-
-               return NULL;
+               ifdebug(TRAFFIC) logger(LOG_WARNING, _("Cannot route packet from %s (%s): unknown IPv6 destination address %hx:%hx:%hx:%hx:%hx:%hx:%hx:%hx"),
+                               source->name, source->hostname,
+                               ntohs(*(uint16_t *) &packet->data[38]),
+                               ntohs(*(uint16_t *) &packet->data[40]),
+                               ntohs(*(uint16_t *) &packet->data[42]),
+                               ntohs(*(uint16_t *) &packet->data[44]),
+                               ntohs(*(uint16_t *) &packet->data[46]),
+                               ntohs(*(uint16_t *) &packet->data[48]),
+                               ntohs(*(uint16_t *) &packet->data[50]),
+                               ntohs(*(uint16_t *) &packet->data[52]));
+
+               route_ipv6_unreachable(source, packet, ICMP6_DST_UNREACH_ADDR);
+               return;
+       }
+
+       if(subnet->owner == source) {
+               ifdebug(TRAFFIC) logger(LOG_WARNING, _("Packet looping back to %s (%s)!"), source->name, source->hostname);
+               return;
        }
 
        if(!subnet->owner->status.reachable)
-               route_ipv6_unreachable(packet, ICMP6_DST_UNREACH_NOROUTE);
+               route_ipv6_unreachable(source, packet, ICMP6_DST_UNREACH_NOROUTE);
        
-       return subnet->owner;
+       send_packet(subnet->owner, packet);
+}
+
+#ifdef ENABLE_MULTICAST
+static void route_ipv6_multicast(node_t *source, vpn_packet_t *packet)
+{
+       avl_node_t *node;
+       subnet_t *subnet, search = {0};
+
+       cp();
+
+       search.type = SUBNET_IPV6;
+       search.net.ipv6.address = *(ipv6_t *)(packet->data + ether_size + ip6_size + icmp6_size);
+       search.net.ipv6.prefixlength = 128;
+       search.owner = NULL;
+
+       ifdebug(TRAFFIC) logger(LOG_INFO, _("Multicasting packet of %d bytes from %s (%s)"), packet->len, source->name, source->hostname);
+
+       for(node = avl_search_closest_smaller_node(myself->subnet_tree, &search); node; node = node->next) {
+               subnet = node->data;
+               
+               if(subnet->type != SUBNET_IPV6 || memcmp(&subnet->net.ipv6.address, packet->data + ether_size + ip6_size + icmp6_size, sizeof(ipv6_t)))
+                       break;
+               
+               if(subnet->owner != source)
+                       send_packet(subnet->owner, packet);
+       }
 }
+#endif
 
 /* RFC 2461 */
 
-static void route_neighborsol(vpn_packet_t *packet)
+static void route_neighborsol(node_t *source, vpn_packet_t *packet)
 {
        struct ip6_hdr ip6;
        struct nd_neighbor_solicit ns;
@@ -407,6 +482,14 @@ static void route_neighborsol(vpn_packet_t *packet)
 
        cp();
 
+       if(!checklength(source, packet, ether_size + ip6_size + ns_size + opt_size + ETH_ALEN))
+               return;
+       
+       if(source != myself) {
+               ifdebug(TRAFFIC) logger(LOG_WARNING, _("Got neighbor solicitation request from %s (%s) while in router mode!"), source->name, source->hostname);
+               return;
+       }
+
        /* Copy headers from packet to structs on the stack */
 
        memcpy(&ip6, packet->data + ether_size, ip6_size);
@@ -428,8 +511,8 @@ static void route_neighborsol(vpn_packet_t *packet)
 
        /* Create pseudo header */
 
-       memcpy(&pseudo.ip6_src, &ip6.ip6_src, sizeof(ip6.ip6_src));
-       memcpy(&pseudo.ip6_dst, &ip6.ip6_dst, sizeof(ip6.ip6_dst));
+       pseudo.ip6_src = ip6.ip6_src;
+       pseudo.ip6_dst = ip6.ip6_dst;
        pseudo.length = htonl(ns_size + opt_size + ETH_ALEN);
        pseudo.next = htonl(IPPROTO_ICMPV6);
 
@@ -473,8 +556,8 @@ static void route_neighborsol(vpn_packet_t *packet)
        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(&ip6.ip6_dst, &ip6.ip6_src, sizeof(ip6.ip6_dst));        /* ... */
-       memcpy(&ip6.ip6_src, &ns.nd_ns_target, sizeof(ip6.ip6_src));    /* swap destination and source protocol address */
+       ip6.ip6_dst = ip6.ip6_src;                      /* swap destination and source protocoll address */
+       ip6.ip6_src = ns.nd_ns_target;
 
        memcpy(packet->data + ether_size + ip6_size + ns_size + opt_size, packet->data + ETH_ALEN, ETH_ALEN);   /* add fake source hard addr */
 
@@ -485,8 +568,8 @@ static void route_neighborsol(vpn_packet_t *packet)
 
        /* Create pseudo header */
 
-       memcpy(&pseudo.ip6_src, &ip6.ip6_src, sizeof(ip6.ip6_src));
-       memcpy(&pseudo.ip6_dst, &ip6.ip6_dst, sizeof(ip6.ip6_dst));
+       pseudo.ip6_src = ip6.ip6_src;
+       pseudo.ip6_dst = ip6.ip6_dst;
        pseudo.length = htonl(ns_size + opt_size + ETH_ALEN);
        pseudo.next = htonl(IPPROTO_ICMPV6);
 
@@ -505,12 +588,135 @@ static void route_neighborsol(vpn_packet_t *packet)
        memcpy(packet->data + ether_size + ip6_size, &ns, ns_size);
        memcpy(packet->data + ether_size + ip6_size + ns_size, &opt, opt_size);
 
-       write_packet(packet);
+       send_packet(source, packet);
+}
+
+/* RFC 2710 */
+
+#ifdef ENABLE_MULTICAST
+static void route_membershipreport(node_t *source, vpn_packet_t *packet)
+{
+       struct ip6_hdr ip6;
+       struct icmp6_hdr icmp6;
+       subnet_t *subnet, search = {0};
+       uint16_t checksum;
+
+       struct {
+               struct in6_addr ip6_src;        /* source address */
+               struct in6_addr ip6_dst;        /* destination address */
+               uint32_t length;
+               uint32_t next;
+       } pseudo;
+
+       cp();
+
+       if(!checklength(source, packet, ether_size + ip6_size + icmp6_size + sizeof(ipv6_t)))
+               return;
+       
+       if(source != myself) {
+               ifdebug(TRAFFIC) logger(LOG_WARNING, _("Got membership report from %s (%s) while in router mode!"), source->name, source->hostname);
+               return;
+       }
+
+       /* Copy headers from packet to structs on the stack */
+
+       memcpy(&ip6, packet->data + ether_size, ip6_size);
+       memcpy(&icmp6, packet->data + ether_size + ip6_size + 8, icmp6_size);
+
+       /* Create pseudo header */
+
+       pseudo.ip6_src = ip6.ip6_src;
+       pseudo.ip6_dst = ip6.ip6_dst;
+       pseudo.length = htonl(icmp6_size + sizeof(ipv6_t));
+       pseudo.next = htonl(IPPROTO_ICMPV6);
+
+       /* Generate checksum */
+
+       checksum = inet_checksum(&pseudo, sizeof(pseudo), ~0);
+       checksum = inet_checksum(&icmp6, icmp6_size, checksum);
+       checksum = inet_checksum(packet->data + ether_size + ip6_size + 8 + icmp6_size, sizeof(ipv6_t), checksum);
+
+       if(checksum) {
+               ifdebug(TRAFFIC) logger(LOG_WARNING, _("Cannot route packet: checksum error for membership report"));
+               return;
+       }
+
+       /* Check if the IPv6 address exists on the VPN */
+
+       search.type = SUBNET_IPV6;
+       search.net.ipv6.address = *(ipv6_t *)(packet->data + ether_size + ip6_size + 8 + icmp6_size);
+       search.net.ipv6.prefixlength = 128;
+       search.owner = myself;
+
+       subnet = avl_search(myself->subnet_tree, &search);
+
+       if(!subnet) {
+               avl_node_t *node;
+               connection_t *c;
+
+               ifdebug(TRAFFIC) logger(LOG_WARNING, _("Learned new IPv6 multicast address %hx:%hx:%hx:%hx:%hx:%hx:%hx:%hx"),
+                               ntohs(*(uint16_t *) &packet->data[70]),
+                               ntohs(*(uint16_t *) &packet->data[72]),
+                               ntohs(*(uint16_t *) &packet->data[74]),
+                               ntohs(*(uint16_t *) &packet->data[76]),
+                               ntohs(*(uint16_t *) &packet->data[78]),
+                               ntohs(*(uint16_t *) &packet->data[80]),
+                               ntohs(*(uint16_t *) &packet->data[82]),
+                               ntohs(*(uint16_t *) &packet->data[84]));
+
+               subnet = new_subnet();
+               subnet->type = SUBNET_IPV6;
+               subnet->net.ipv6.address = *(ipv6_t *)(packet->data + ether_size + ip6_size + 8 + icmp6_size);
+               subnet->net.ipv6.prefixlength = 128;
+               subnet->expires = now + multicastexpire;
+               subnet_add(myself, subnet);
+
+               /* And tell all other tinc daemons it's ours */
+
+               for(node = connection_tree->head; node; node = node->next) {
+                       c = node->data;
+                       if(c->status.active)
+                               send_add_subnet(c, subnet);
+               }
+       }
+
+       if(subnet->expires)
+               subnet->expires = now + multicastexpire;
+}
+#endif
+
+static void route_ipv6(node_t *source, vpn_packet_t *packet)
+{
+       cp();
+
+       if(!checklength(source, packet, ether_size + ip6_size))
+               return;
+
+       if(packet->data[20] == IPPROTO_ICMPV6 && checklength(source, packet, ether_size + ip6_size + icmp6_size) && packet->data[54] == ND_NEIGHBOR_SOLICIT) {
+               route_neighborsol(source, packet);
+               return;
+       }
+
+#ifdef ENABLE_MULTICAST 
+       if(packet->data[20] == IPPROTO_HOPOPTS && checklength(source, packet, ether_size + ip6_size + 8)
+                       && packet->data[54] == IPPROTO_ICMPV6 && checklength(source, packet, ether_size + ip6_size + 8 + icmp6_size)
+                       && packet->data[62] == ICMP6_MEMBERSHIP_REPORT) {
+               route_membershipreport(source, packet);
+               return;
+       }
+       
+       if(packet->data[38] == 0xff && packet->data[39] & 0x0c) {
+               route_ipv6_multicast(source, packet);
+               return;
+       }
+#endif
+
+       route_ipv6_unicast(source, packet);
 }
 
 /* RFC 826 */
 
-static void route_arp(vpn_packet_t *packet)
+static void route_arp(node_t *source, vpn_packet_t *packet)
 {
        struct ether_arp arp;
        subnet_t *subnet;
@@ -518,6 +724,14 @@ static void route_arp(vpn_packet_t *packet)
 
        cp();
 
+       if(!checklength(source, packet, ether_size + arp_size))
+               return;
+
+       if(source != myself) {
+               ifdebug(TRAFFIC) logger(LOG_WARNING, _("Got ARP request from %s (%s) while in router mode!"), source->name, source->hostname);
+               return;
+       }
+
        /* First, snatch the source address from the ARP packet */
 
        if(overwrite_mac)
@@ -566,150 +780,48 @@ static void route_arp(vpn_packet_t *packet)
 
        memcpy(packet->data + ether_size, &arp, arp_size);
 
-       write_packet(packet);
+       send_packet(source, packet);
 }
 
-void route_outgoing(vpn_packet_t *packet)
+void route(node_t *source, vpn_packet_t *packet)
 {
-       uint16_t type;
-       node_t *n = NULL;
-
        cp();
 
-       if(packet->len < ether_size) {
-               ifdebug(TRAFFIC) logger(LOG_WARNING, _("Read too short packet"));
-               return;
-       }
-
-       /* FIXME: multicast? */
-
-       switch (routing_mode) {
-               case RMODE_ROUTER:
-                       type = ntohs(*((uint16_t *)(&packet->data[12])));
-                       switch (type) {
-                               case ETH_P_IP:
-                                       if(packet->len < ether_size + ip_size) {
-                                               ifdebug(TRAFFIC) logger(LOG_WARNING, _("Read too short packet"));
-                                               return;
-                                       }
-
-                                       n = route_ipv4(packet);
-                                       break;
-
-                               case ETH_P_IPV6:
-                                       if(packet->len < ether_size + ip6_size) {
-                                               ifdebug(TRAFFIC) logger(LOG_WARNING, _("Read too short packet"));
-                                               return;
-                                       }
-
-                                       if(packet->data[20] == IPPROTO_ICMPV6 && packet->len >= ether_size + ip6_size + ns_size && packet->data[54] == ND_NEIGHBOR_SOLICIT) {
-                                               route_neighborsol(packet);
-                                               return;
-                                       }
-                                       n = route_ipv6(packet);
-                                       break;
-
-                               case ETH_P_ARP:
-                                       if(packet->len < ether_size + arp_size) {
-                                               ifdebug(TRAFFIC) logger(LOG_WARNING, _("Read too short packet"));
-                                               return;
-                                       }
-
-                                       route_arp(packet);
-                                       return;
-
-                               default:
-                                       ifdebug(TRAFFIC) logger(LOG_WARNING, _("Cannot route packet: unknown type %hx"), type);
-                                       return;
-                       }
-                       if(n)
-                               send_packet(n, packet);
-                       break;
-
-               case RMODE_SWITCH:
-                       n = route_mac(packet);
-                       if(n)
-                               send_packet(n, packet);
-                       else
-                               broadcast_packet(myself, packet);
-                       break;
-
-               case RMODE_HUB:
-                       broadcast_packet(myself, packet);
-                       break;
-       }
-}
-
-void route_incoming(node_t *source, vpn_packet_t *packet)
-{
-       if(packet->len < ether_size) {
-               ifdebug(TRAFFIC) logger(LOG_WARNING, _("Read too short packet"));
+       if(!checklength(source, packet, ether_size))
                return;
-       }
 
        switch (routing_mode) {
                case RMODE_ROUTER:
                        {
-                               node_t *n = NULL;
                                uint16_t type;
 
                                type = ntohs(*((uint16_t *)(&packet->data[12])));
                                switch (type) {
-                                       case ETH_P_IP:
-                                               if(packet->len < ether_size + ip_size) {
-                                                       ifdebug(TRAFFIC) logger(LOG_WARNING, _("Read too short packet"));
-                                                       return;
-                                               }
+                                       case ETH_P_ARP:
+                                               route_arp(source, packet);
+                                               break;
 
-                                               n = route_ipv4(packet);
+                                       case ETH_P_IP:
+                                               route_ipv4(source, packet);
                                                break;
 
                                        case ETH_P_IPV6:
-                                               if(packet->len < ether_size + ip6_size) {
-                                                       ifdebug(TRAFFIC) logger(LOG_WARNING, _("Read too short packet"));
-                                                       return;
-                                               }
-
-                                               n = route_ipv6(packet);
+                                               route_ipv6(source, packet);
                                                break;
 
                                        default:
-                                               n = myself;
+                                               ifdebug(TRAFFIC) logger(LOG_WARNING, _("Cannot route packet from %s (%s): unknown type %hx"), source->name, source->hostname, type);
                                                break;
                                }
-
-                               if(n) {
-                                       if(n == myself) {
-                                               if(overwrite_mac)
-                                                       memcpy(packet->data, mymac.x, ETH_ALEN);
-                                               write_packet(packet);
-                                       } else
-                                               send_packet(n, packet);
-                               }
                        }
                        break;
 
                case RMODE_SWITCH:
-                       {
-                               subnet_t *subnet;
-
-                               subnet = lookup_subnet_mac((mac_t *)(&packet->data[0]));
-
-                               if(subnet) {
-                                       if(subnet->owner == myself)
-                                               write_packet(packet);
-                                       else
-                                               send_packet(subnet->owner, packet);
-                               } else {
-                                       broadcast_packet(source, packet);
-                                       write_packet(packet);
-                               }
-                       }
+                       route_mac(source, packet);
                        break;
 
                case RMODE_HUB:
-                       broadcast_packet(source, packet);       /* Spread it on */
-                       write_packet(packet);
+                       broadcast_packet(source, packet);
                        break;
        }
 }
index 6d1c034..a26411a 100644 (file)
@@ -17,7 +17,7 @@
     along with this program; if not, write to the Free Software
     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 
-    $Id: route.h,v 1.1.2.13 2003/07/22 20:55:20 guus Exp $
+    $Id: route.h,v 1.1.2.14 2003/12/12 19:52:25 guus Exp $
 */
 
 #ifndef __TINC_ROUTE_H__
@@ -39,8 +39,7 @@ extern int macexpire;
 
 extern mac_t mymac;
 
-extern void age_mac(void);
-extern void route_incoming(struct node_t *, struct vpn_packet_t *);
-extern void route_outgoing(struct vpn_packet_t *);
+extern void age_subnets(void);
+extern void route(struct node_t *, struct vpn_packet_t *);
 
 #endif                                                 /* __TINC_ROUTE_H__ */
index ae8d029..d5eca58 100644 (file)
@@ -17,7 +17,7 @@
     along with this program; if not, write to the Free Software
     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 
-    $Id: subnet.c,v 1.1.2.51 2003/11/17 15:30:18 guus Exp $
+    $Id: subnet.c,v 1.1.2.52 2003/12/12 19:52:25 guus Exp $
 */
 
 #include "system.h"
@@ -177,16 +177,13 @@ void subnet_del(node_t *n, subnet_t *subnet)
 
 /* Ascii representation of subnets */
 
-subnet_t *str2net(const char *subnetstr)
+bool str2net(subnet_t *subnet, const char *subnetstr)
 {
        int i, l;
-       subnet_t *subnet;
        uint16_t x[8];
 
        cp();
 
-       subnet = new_subnet();
-
        if(sscanf(subnetstr, "%hu.%hu.%hu.%hu/%d",
                          &x[0], &x[1], &x[2], &x[3], &l) == 5) {
                subnet->type = SUBNET_IPV4;
@@ -195,7 +192,7 @@ subnet_t *str2net(const char *subnetstr)
                for(i = 0; i < 4; i++)
                        subnet->net.ipv4.address.x[i] = x[i];
 
-               return subnet;
+               return true;
        }
 
        if(sscanf(subnetstr, "%hx:%hx:%hx:%hx:%hx:%hx:%hx:%hx/%d",
@@ -207,7 +204,7 @@ subnet_t *str2net(const char *subnetstr)
                for(i = 0; i < 8; i++)
                        subnet->net.ipv6.address.x[i] = htons(x[i]);
 
-               return subnet;
+               return true;
        }
 
        if(sscanf(subnetstr, "%hu.%hu.%hu.%hu", &x[0], &x[1], &x[2], &x[3]) == 4) {
@@ -217,7 +214,7 @@ subnet_t *str2net(const char *subnetstr)
                for(i = 0; i < 4; i++)
                        subnet->net.ipv4.address.x[i] = x[i];
 
-               return subnet;
+               return true;
        }
 
        if(sscanf(subnetstr, "%hx:%hx:%hx:%hx:%hx:%hx:%hx:%hx",
@@ -228,7 +225,7 @@ subnet_t *str2net(const char *subnetstr)
                for(i = 0; i < 8; i++)
                        subnet->net.ipv6.address.x[i] = htons(x[i]);
 
-               return subnet;
+               return true;
        }
 
        if(sscanf(subnetstr, "%hx:%hx:%hx:%hx:%hx:%hx",
@@ -238,23 +235,19 @@ subnet_t *str2net(const char *subnetstr)
                for(i = 0; i < 6; i++)
                        subnet->net.mac.address.x[i] = x[i];
 
-               return subnet;
+               return true;
        }
 
-       free(subnet);
-
-       return NULL;
+       return false;
 }
 
-char *net2str(const subnet_t *subnet)
+bool net2str(char *netstr, int len, const subnet_t *subnet)
 {
-       char *netstr;
-
        cp();
 
        switch (subnet->type) {
                case SUBNET_MAC:
-                       asprintf(&netstr, "%hx:%hx:%hx:%hx:%hx:%hx",
+                       snprintf(netstr, len, "%hx:%hx:%hx:%hx:%hx:%hx",
                                         subnet->net.mac.address.x[0],
                                         subnet->net.mac.address.x[1],
                                         subnet->net.mac.address.x[2],
@@ -263,7 +256,7 @@ char *net2str(const subnet_t *subnet)
                        break;
 
                case SUBNET_IPV4:
-                       asprintf(&netstr, "%hu.%hu.%hu.%hu/%d",
+                       snprintf(netstr, len, "%hu.%hu.%hu.%hu/%d",
                                         subnet->net.ipv4.address.x[0],
                                         subnet->net.ipv4.address.x[1],
                                         subnet->net.ipv4.address.x[2],
@@ -271,7 +264,7 @@ char *net2str(const subnet_t *subnet)
                        break;
 
                case SUBNET_IPV6:
-                       asprintf(&netstr, "%hx:%hx:%hx:%hx:%hx:%hx:%hx:%hx/%d",
+                       snprintf(netstr, len, "%hx:%hx:%hx:%hx:%hx:%hx:%hx:%hx/%d",
                                         ntohs(subnet->net.ipv6.address.x[0]),
                                         ntohs(subnet->net.ipv6.address.x[1]),
                                         ntohs(subnet->net.ipv6.address.x[2]),
@@ -394,7 +387,7 @@ subnet_t *lookup_subnet_ipv6(const ipv6_t *address)
 
 void dump_subnets(void)
 {
-       char *netstr;
+       char netstr[MAXNETSTR];
        subnet_t *subnet;
        avl_node_t *node;
 
@@ -404,9 +397,9 @@ void dump_subnets(void)
 
        for(node = subnet_tree->head; node; node = node->next) {
                subnet = node->data;
-               netstr = net2str(subnet);
+               if(!net2str(netstr, sizeof netstr, subnet))
+                       continue;
                logger(LOG_DEBUG, _(" %s owner %s"), netstr, subnet->owner->name);
-               free(netstr);
        }
 
        logger(LOG_DEBUG, _("End of subnet list."));
index c055eda..d82bfa3 100644 (file)
@@ -17,7 +17,7 @@
     along with this program; if not, write to the Free Software
     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 
-    $Id: subnet.h,v 1.1.2.26 2003/11/17 15:30:18 guus Exp $
+    $Id: subnet.h,v 1.1.2.27 2003/12/12 19:52:25 guus Exp $
 */
 
 #ifndef __TINC_SUBNET_H__
@@ -34,7 +34,6 @@ typedef enum subnet_type_t {
 
 typedef struct subnet_mac_t {
        mac_t address;
-       time_t lastseen;
 } subnet_mac_t;
 
 typedef struct subnet_ipv4_t {
@@ -53,6 +52,7 @@ typedef struct subnet_t {
        struct node_t *owner;           /* the owner of this subnet */
 
        subnet_type_t type;             /* subnet type (IPv4? IPv6? MAC? something even weirder?) */
+       time_t expires;                 /* expiry time */
 
        /* And now for the actual subnet: */
 
@@ -63,6 +63,8 @@ typedef struct subnet_t {
        } net;
 } subnet_t;
 
+#define MAXNETSTR 64
+
 extern int subnet_compare(const struct subnet_t *, const struct subnet_t *);
 extern subnet_t *new_subnet(void) __attribute__ ((__malloc__));
 extern void free_subnet(subnet_t *);
@@ -72,8 +74,8 @@ extern avl_tree_t *new_subnet_tree(void) __attribute__ ((__malloc__));
 extern void free_subnet_tree(avl_tree_t *);
 extern void subnet_add(struct node_t *, subnet_t *);
 extern void subnet_del(struct node_t *, subnet_t *);
-extern char *net2str(const subnet_t *);
-extern subnet_t *str2net(const char *);
+extern bool net2str(char *, int, const subnet_t *);
+extern bool str2net(subnet_t *, const char *);
 extern subnet_t *lookup_subnet(const struct node_t *, const subnet_t *);
 extern subnet_t *lookup_subnet_mac(const mac_t *);
 extern subnet_t *lookup_subnet_ipv4(const ipv4_t *);