diff --git a/doc/tinc.conf.5.in b/doc/tinc.conf.5.in index 6f8db9c0..797ca522 100644 --- a/doc/tinc.conf.5.in +++ b/doc/tinc.conf.5.in @@ -199,6 +199,26 @@ Tinc will expect packets read from the virtual network device to start with an Ethernet header. .El +.It Va Forwarding Li = off | internal | kernel Pq internal +This option selects the way indirect packets are forwarded. +.Bl -tag -width indent + +.It off +Incoming packets that are not meant for the local node, +but which should be forwarded to another node, are dropped. + +.It internal +Incoming packets that are meant for another node are forwarded by tinc internally. + +.Pp +This is the default mode, and unless you really know you need another forwarding mode, don't change it. + +.It kernel +Incoming packets are always sent to the TUN/TAP device, even if the packets are not for the local node. +This is less efficient, but allows the kernel to apply its routing and firewall rules on them, +and can also help debugging. +.El + .It Va GraphDumpFile Li = Ar filename Bq experimental If this option is present, .Nm tinc diff --git a/doc/tinc.texi b/doc/tinc.texi index 5d0bf31f..091b5e7a 100644 --- a/doc/tinc.texi +++ b/doc/tinc.texi @@ -818,6 +818,26 @@ Tinc will expect packets read from the virtual network device to start with an Ethernet header. @end table +@cindex Forwarding +@item Forwarding = (internal) +This option selects the way indirect packets are forwarded. + +@table @asis +@item off +Incoming packets that are not meant for the local node, +but which should be forwarded to another node, are dropped. + +@item internal +Incoming packets that are meant for another node are forwarded by tinc internally. + +This is the default mode, and unless you really know you need another forwarding mode, don't change it. + +@item kernel +Incoming packets are always sent to the TUN/TAP device, even if the packets are not for the local node. +This is less efficient, but allows the kernel to apply its routing and firewall rules on them, +and can also help debugging. +@end table + @cindex GraphDumpFile @item GraphDumpFile = <@var{filename}> [experimental] If this option is present, diff --git a/src/net_setup.c b/src/net_setup.c index cb606caa..6e51b2e2 100644 --- a/src/net_setup.c +++ b/src/net_setup.c @@ -355,8 +355,21 @@ bool setup_myself(void) { return false; } free(mode); - } else - routing_mode = RMODE_ROUTER; + } + + if(get_config_string(lookup_config(config_tree, "Forwarding"), &mode)) { + if(!strcasecmp(mode, "off")) + routing_mode = FMODE_OFF; + else if(!strcasecmp(mode, "internal")) + routing_mode = FMODE_INTERNAL; + else if(!strcasecmp(mode, "kernel")) + routing_mode = FMODE_KERNEL; + else { + logger(LOG_ERR, "Invalid forwarding mode!"); + return false; + } + free(mode); + } choice = true; get_config_bool(lookup_config(myself->connection->config_tree, "PMTUDiscovery"), &choice); diff --git a/src/route.c b/src/route.c index 6c381ccf..1f91db97 100644 --- a/src/route.c +++ b/src/route.c @@ -33,6 +33,7 @@ #include "utils.h" rmode_t routing_mode = RMODE_ROUTER; +fmode_t forwarding_mode = FMODE_INTERNAL; bool priorityinheritance = false; int macexpire = 600; bool overwrite_mac = false; @@ -383,7 +384,10 @@ static void route_ipv4_unicast(node_t *source, vpn_packet_t *packet) { } if(!subnet->owner->status.reachable) - route_ipv4_unreachable(source, packet, ICMP_DEST_UNREACH, ICMP_NET_UNREACH); + return route_ipv4_unreachable(source, packet, ICMP_DEST_UNREACH, ICMP_NET_UNREACH); + + if(forwarding_mode == FMODE_OFF && source != myself && subnet->owner != myself) + return route_ipv4_unreachable(source, packet, ICMP_DEST_UNREACH, ICMP_NET_ANO); if(priorityinheritance) packet->priority = packet->data[15]; @@ -531,7 +535,10 @@ static void route_ipv6_unicast(node_t *source, vpn_packet_t *packet) { } if(!subnet->owner->status.reachable) - route_ipv6_unreachable(source, packet, ICMP6_DST_UNREACH, ICMP6_DST_UNREACH_NOROUTE); + return route_ipv6_unreachable(source, packet, ICMP6_DST_UNREACH, ICMP6_DST_UNREACH_NOROUTE); + + if(forwarding_mode == FMODE_OFF && source != myself && subnet->owner != myself) + return route_ipv6_unreachable(source, packet, ICMP6_DST_UNREACH, ICMP6_DST_UNREACH_ADMIN); via = (subnet->owner->via == myself) ? subnet->owner->nexthop : subnet->owner->via; @@ -796,6 +803,9 @@ static void route_mac(node_t *source, vpn_packet_t *packet) { return; } + if(forwarding_mode == FMODE_OFF && source != myself && subnet->owner != myself) + return; + // Handle packets larger than PMTU node_t *via = (subnet->owner->via == myself) ? subnet->owner->nexthop : subnet->owner->via; @@ -824,6 +834,11 @@ static void route_mac(node_t *source, vpn_packet_t *packet) { } void route(node_t *source, vpn_packet_t *packet) { + if(forwarding_mode == FMODE_KERNEL) { + send_packet(myself, packet); + return; + } + if(!checklength(source, packet, ether_size)) return; diff --git a/src/route.h b/src/route.h index 1fcc6be7..aa25dcf5 100644 --- a/src/route.h +++ b/src/route.h @@ -30,7 +30,14 @@ typedef enum rmode_t { RMODE_ROUTER, } rmode_t; +typedef enum fmode_t { + FMODE_OFF = 0, + FMODE_INTERNAL, + FMODE_KERNEL, +} fmode_t; + extern rmode_t routing_mode; +extern fmode_t forwarding_mode; extern bool overwrite_mac; extern bool priorityinheritance; extern int macexpire;