Make broadcast addresses configurable.
authorEtienne Dechamps <etienne@edechamps.fr>
Sun, 29 Jun 2014 12:18:25 +0000 (13:18 +0100)
committerEtienne Dechamps <etienne@edechamps.fr>
Sun, 29 Jun 2014 15:48:57 +0000 (16:48 +0100)
This adds a new option, BroadcastSubnet, that allows the user to
declare broadcast subnets, i.e. subnets which are considered broadcast
addresses by the tinc routing layer. Previously only the global IPv4
and IPv6 broadcast addresses were supported by virtue of being
hardcoded.

This is useful when using tinc in router mode with Ethernet virtual
devices, as it can be used to provide broadcast support for a local
broadcast address (e.g. 10.42.255.255) instead of just the global
address (255.255.255.255).

This is implemented by removing hardcoded broadcast addresses and
introducing "broadcast subnets", which are subnets with a NULL owner.
By default, behavior is unchanged; this is accomplished by adding
the global broadcast addresses for Ethernet, IPv4 and IPv6 at start
time.

doc/tinc.conf.5.in
src/net.c
src/net_setup.c
src/route.c
src/subnet.c

index 01c7480216381efd0b51477ea466ea170c5a68c1..9566afa6bf34fa17f260e1e75b61ccb0bcb91329 100644 (file)
@@ -155,6 +155,13 @@ Broadcast packets are sent directly to all nodes that can be reached directly.
 Broadcast packets received from other nodes are never forwarded.
 If the IndirectData option is also set, broadcast packets will only be sent to nodes which we have a meta connection to.
 .El
+.It Va BroadcastSubnet Li = Ar address Ns Op Li / Ns Ar prefixlength
+Declares a broadcast subnet. Any packet with a destination address falling into such a subnet will be routed as a broadcast (provided all nodes have it declared).
+This is most useful to declare subnet broadcast addresses (e.g. 10.42.255.255), otherwise
+.Nm tinc
+won't know what to do with them.
+.Pp
+Note that global broadcast addresses (MAC ff:ff:ff:ff:ff:ff, IPv4 255.255.255.255), as well as IPv6 multicast space (ff00::/8) are always considered broadcast addresses and don't need to be declared.
 .It Va ConnectTo Li = Ar name
 Specifies which other tinc daemon to connect to on startup.
 Multiple
index b6ddc57193649f5e30a2e49e1ac47711347b803c..8fe3c516c14d08646ffad222a4bce8edb116c5e0 100644 (file)
--- a/src/net.c
+++ b/src/net.c
@@ -347,11 +347,14 @@ int reload_configuration(void) {
 
        if(strictsubnets) {
                for splay_each(subnet_t, subnet, subnet_tree)
-                       subnet->expires = 1;
+                       if (subnet->owner)
+                               subnet->expires = 1;
 
                load_all_subnets();
 
                for splay_each(subnet_t, subnet, subnet_tree) {
+                       if (!subnet->owner)
+                               continue;
                        if(subnet->expires == 1) {
                                send_del_subnet(everyone, subnet);
                                if(subnet->owner->status.reachable)
index 0a97e03ff55284c4c48f5c6f0a33b0d82cea1038..0f8d31a6d68bebb3b844cc04f91841dc092793f9 100644 (file)
@@ -586,6 +586,20 @@ bool setup_myself_reloadable(void) {
                free(bmode);
        }
 
+       const char* const DEFAULT_BROADCAST_SUBNETS[] = { "ff:ff:ff:ff:ff:ff", "255.255.255.255", "ff00::/8" };
+       for (size_t i = 0; i < sizeof(DEFAULT_BROADCAST_SUBNETS) / sizeof(*DEFAULT_BROADCAST_SUBNETS); i++) {
+               subnet_t *s = new_subnet();
+               if (!str2net(s, DEFAULT_BROADCAST_SUBNETS[i]))
+                       abort();
+               subnet_add(NULL, s);
+       }
+       for (config_t* cfg = lookup_config(config_tree, "BroadcastSubnet"); cfg; cfg = lookup_config_next(config_tree, cfg)) {
+               subnet_t *s;
+               if (!get_config_subnet(cfg, &s))
+                       continue;
+               subnet_add(NULL, s);
+       }
+
 #if !defined(SOL_IP) || !defined(IP_TOS)
        if(priorityinheritance)
                logger(DEBUG_ALWAYS, LOG_WARNING, "%s not supported on this platform", "PriorityInheritance");
index 00ba4c05b19a7a33f5ed978270ed3b24f99b8a7a..43d26972a6465af91f8d868c4dd0805b5c0aece7 100644 (file)
@@ -371,7 +371,10 @@ static void fragment_ipv4_packet(node_t *dest, vpn_packet_t *packet, length_t et
        }
 }
 
-static void route_ipv4_unicast(node_t *source, vpn_packet_t *packet) {
+static void route_ipv4(node_t *source, vpn_packet_t *packet) {
+       if(!checklength(source, packet, ether_size + ip_size))
+               return;
+
        subnet_t *subnet;
        node_t *via;
        ipv4_t dest;
@@ -391,6 +394,11 @@ static void route_ipv4_unicast(node_t *source, vpn_packet_t *packet) {
                return;
        }
 
+       if (!subnet->owner) {
+               broadcast_packet(source, packet);
+               return;
+       }
+
        if(subnet->owner == source) {
                logger(DEBUG_TRAFFIC, LOG_WARNING, "Packet looping back to %s (%s)!", source->name, source->hostname);
                return;
@@ -432,20 +440,6 @@ static void route_ipv4_unicast(node_t *source, vpn_packet_t *packet) {
        send_packet(subnet->owner, packet);
 }
 
-static void route_ipv4(node_t *source, vpn_packet_t *packet) {
-       if(!checklength(source, packet, ether_size + ip_size))
-               return;
-
-       if(broadcast_mode && (((packet->data[30] & 0xf0) == 0xe0) || (
-                       packet->data[30] == 255 &&
-                       packet->data[31] == 255 &&
-                       packet->data[32] == 255 &&
-                       packet->data[33] == 255)))
-               broadcast_packet(source, packet);
-       else
-               route_ipv4_unicast(source, packet);
-}
-
 /* RFC 2463 */
 
 static void route_ipv6_unreachable(node_t *source, vpn_packet_t *packet, length_t ether_size, uint8_t type, uint8_t code) {
@@ -526,7 +520,17 @@ static void route_ipv6_unreachable(node_t *source, vpn_packet_t *packet, length_
        send_packet(source, packet);
 }
 
-static void route_ipv6_unicast(node_t *source, vpn_packet_t *packet) {
+static void route_neighborsol(node_t *source, vpn_packet_t *packet);
+
+static void route_ipv6(node_t *source, vpn_packet_t *packet) {
+       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;
+       }
+
        subnet_t *subnet;
        node_t *via;
        ipv6_t dest;
@@ -550,6 +554,11 @@ static void route_ipv6_unicast(node_t *source, vpn_packet_t *packet) {
                return;
        }
 
+       if (!subnet->owner) {
+               broadcast_packet(source, packet);
+               return;
+       }
+
        if(subnet->owner == source) {
                logger(DEBUG_TRAFFIC, LOG_WARNING, "Packet looping back to %s (%s)!", source->name, source->hostname);
                return;
@@ -724,21 +733,6 @@ static void route_neighborsol(node_t *source, vpn_packet_t *packet) {
        send_packet(source, packet);
 }
 
-static void route_ipv6(node_t *source, vpn_packet_t *packet) {
-       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;
-       }
-
-       if(broadcast_mode && packet->data[38] == 255)
-               broadcast_packet(source, packet);
-       else
-               route_ipv6_unicast(source, packet);
-}
-
 /* RFC 826 */
 
 static void route_arp(node_t *source, vpn_packet_t *packet) {
@@ -822,7 +816,7 @@ static void route_mac(node_t *source, vpn_packet_t *packet) {
        memcpy(&dest, &packet->data[0], sizeof dest);
        subnet = lookup_subnet_mac(NULL, &dest);
 
-       if(!subnet) {
+       if(!subnet || !subnet->owner) {
                broadcast_packet(source, packet);
                return;
        }
index 7ff8f7aab518d27372fd74436eb5198546e72aa2..23160e52509f72977fe8e85c157edceeec1ac460 100644 (file)
@@ -92,13 +92,15 @@ void subnet_add(node_t *n, subnet_t *subnet) {
        subnet->owner = n;
 
        splay_insert(subnet_tree, subnet);
-       splay_insert(n->subnet_tree, subnet);
+       if (n)
+               splay_insert(n->subnet_tree, subnet);
 
        subnet_cache_flush();
 }
 
 void subnet_del(node_t *n, subnet_t *subnet) {
-       splay_delete(n->subnet_tree, subnet);
+       if (n)
+               splay_delete(n->subnet_tree, subnet);
        splay_delete(subnet_tree, subnet);
 
        subnet_cache_flush();
@@ -126,7 +128,7 @@ subnet_t *lookup_subnet_mac(const node_t *owner, const mac_t *address) {
 
                if(!memcmp(address, &p->net.mac.address, sizeof *address)) {
                        r = p;
-                       if(p->owner->status.reachable)
+                       if(!p->owner || p->owner->status.reachable)
                                break;
                }
        }
@@ -155,7 +157,7 @@ subnet_t *lookup_subnet_ipv4(const ipv4_t *address) {
 
                if(!maskcmp(address, &p->net.ipv4.address, p->net.ipv4.prefixlength)) {
                        r = p;
-                       if(p->owner->status.reachable)
+                       if(!p->owner || p->owner->status.reachable)
                                break;
                }
        }
@@ -184,7 +186,7 @@ subnet_t *lookup_subnet_ipv6(const ipv6_t *address) {
 
                if(!maskcmp(address, &p->net.ipv6.address, p->net.ipv6.prefixlength)) {
                        r = p;
-                       if(p->owner->status.reachable)
+                       if(!p->owner || p->owner->status.reachable)
                                break;
                }
        }