.Pp
This option may not work on all platforms.
-.It Va Broadcast Li = yes | no Po yes Pc Bq experimental
-When disabled, tinc will drop all broadcast and multicast packets, in both router and switch mode.
+.It Va Broadcast Li = no | mst | direct Po mst Pc Bq experimental
+This option selects the way broadcast packets are sent to other daemons.
+NOTE: all nodes in a VPN must use the same
+.Va Broadcast
+mode, otherwise routing loops can form.
+
+.Bl -tag -width indent
+.It no
+Broadcast packets are never sent to other nodes.
+
+.It mst
+Broadcast packets are sent and forwarded via the VPN's Minimum Spanning Tree.
+This ensures broadcast packets reach all nodes.
+
+.It direct
+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 ConnectTo Li = Ar name
Specifies which other tinc daemon to connect to on startup.
This option may not work on all platforms.
@cindex Broadcast
-@item Broadcast = <yes | no> (yes) [experimental]
-When disabled, tinc will drop all broadcast and multicast packets, in both router and switch mode.
+@item Broadcast = <no | mst | direct> (mst) [experimental]
+This option selects the way broadcast packets are sent to other daemons.
+@emph{NOTE: all nodes in a VPN must use the same Broadcast mode, otherwise routing loops can form.}
+
+@table @asis
+@item no
+Broadcast packets are never sent to other nodes.
+
+@item mst
+Broadcast packets are sent and forwarded via the VPN's Minimum Spanning Tree.
+This ensures broadcast packets reach all nodes.
+
+@item direct
+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.
+@end table
@cindex ConnectTo
@item ConnectTo = <@var{name}>
void broadcast_packet(const node_t *from, vpn_packet_t *packet) {
avl_node_t *node;
connection_t *c;
+ node_t *n;
+
+ // Always give ourself a copy of the packet.
+ if(from != myself)
+ send_packet(myself, packet);
+
+ // In TunnelServer mode, do not forward broadcast packets.
+ // The MST might not be valid and create loops.
+ if(tunnelserver || broadcast_mode == BMODE_NONE)
+ return;
ifdebug(TRAFFIC) logger(LOG_INFO, "Broadcasting packet of %d bytes from %s (%s)",
packet->len, from->name, from->hostname);
- if(from != myself) {
- send_packet(myself, packet);
+ switch(broadcast_mode) {
+ // In MST mode, broadcast packets travel via the Minimum Spanning Tree.
+ // This guarantees all nodes receive the broadcast packet, and
+ // usually distributes the sending of broadcast packets over all nodes.
+ case BMODE_MST:
+ for(node = connection_tree->head; node; node = node->next) {
+ c = node->data;
- // In TunnelServer mode, do not forward broadcast packets.
- // The MST might not be valid and create loops.
- if(tunnelserver)
- return;
- }
+ if(c->status.active && c->status.mst && c != from->nexthop->connection)
+ send_packet(c->node, packet);
+ }
+ break;
+
+ // In direct mode, we send copies to each node we know of.
+ // However, this only reaches nodes that can be reached in a single hop.
+ // We don't have enough information to forward broadcast packets in this case.
+ case BMODE_DIRECT:
+ if(from != myself)
+ break;
+
+ for(node = node_udp_tree->head; node; node = node->next) {
+ n = node->data;
- for(node = connection_tree->head; node; node = node->next) {
- c = node->data;
+ if(n->status.reachable && ((n->via == myself && n->nexthop == n) || n->via == n))
+ send_packet(c->node, packet);
+ }
+ break;
- if(c->status.active && c->status.mst && c != from->nexthop->connection)
- send_packet(c->node, packet);
+ default:
+ break;
}
}
get_config_bool(lookup_config(config_tree, "PriorityInheritance"), &priorityinheritance);
get_config_bool(lookup_config(config_tree, "DecrementTTL"), &decrement_ttl);
- get_config_bool(lookup_config(config_tree, "Broadcast"), &broadcast);
+ if(get_config_string(lookup_config(config_tree, "Broadcast"), &mode)) {
+ if(!strcasecmp(mode, "no"))
+ broadcast_mode = BMODE_NONE;
+ else if(!strcasecmp(mode, "yes") || !strcasecmp(mode, "mst"))
+ broadcast_mode = BMODE_MST;
+ else if(!strcasecmp(mode, "direct"))
+ broadcast_mode = BMODE_DIRECT;
+ else {
+ logger(LOG_ERR, "Invalid broadcast mode!");
+ return false;
+ }
+ free(mode);
+ }
#if !defined(SOL_IP) || !defined(IP_TOS)
if(priorityinheritance)
rmode_t routing_mode = RMODE_ROUTER;
fmode_t forwarding_mode = FMODE_INTERNAL;
+bmode_t broadcast_mode = BMODE_MST;
bool decrement_ttl = false;
bool directonly = false;
bool priorityinheritance = false;
int macexpire = 600;
bool overwrite_mac = false;
-bool broadcast = true;
mac_t mymac = {{0xFE, 0xFD, 0, 0, 0, 0}};
/* Sizes of various headers */
if(!checklength(source, packet, ether_size + ip_size))
return;
- if(broadcast && (((packet->data[30] & 0xf0) == 0xe0) || (
+ if(broadcast_mode && (((packet->data[30] & 0xf0) == 0xe0) || (
packet->data[30] == 255 &&
packet->data[31] == 255 &&
packet->data[32] == 255 &&
return;
}
- if(broadcast && packet->data[38] == 255)
+ if(broadcast_mode && packet->data[38] == 255)
broadcast_packet(source, packet);
else
route_ipv6_unicast(source, packet);
subnet = lookup_subnet_mac(NULL, &dest);
if(!subnet) {
- if(broadcast)
- broadcast_packet(source, packet);
+ broadcast_packet(source, packet);
return;
}
FMODE_KERNEL,
} fmode_t;
+typedef enum bmode_t {
+ BMODE_NONE = 0,
+ BMODE_MST,
+ BMODE_DIRECT,
+} bmode_t;
+
extern rmode_t routing_mode;
extern fmode_t forwarding_mode;
+extern bmode_t broadcast_mode;
extern bool decrement_ttl;
extern bool directonly;
extern bool overwrite_mac;
-extern bool broadcast;
extern bool priorityinheritance;
extern int macexpire;