Make broadcast addresses configurable.
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.
This commit is contained in:
parent
b54fde6747
commit
46a5aa0d67
5 changed files with 58 additions and 38 deletions
|
@ -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)
|
||||
|
|
|
@ -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");
|
||||
|
|
58
src/route.c
58
src/route.c
|
@ -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;
|
||||
}
|
||||
|
|
12
src/subnet.c
12
src/subnet.c
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue