Decrement TTL of incoming packets.
authorGuus Sliepen <guus@tinc-vpn.org>
Mon, 20 Feb 2012 15:34:02 +0000 (16:34 +0100)
committerGuus Sliepen <guus@tinc-vpn.org>
Mon, 20 Feb 2012 15:34:02 +0000 (16:34 +0100)
Tinc will now, by default, decrement the TTL field of incoming IPv4 and IPv6
packets, before forwarding them to the virtual network device or to another
node. Packets with a TTL value of zero will be dropped, and an ICMP Time
Exceeded message will be sent back.

This behaviour can be disabled using the DecrementTTL option.

doc/tinc.conf.5.in
doc/tinc.texi
src/net_setup.c
src/route.c
src/route.h

index 746d820f2c20c1ad45ff241c3596447f9d66fded..8d8e6f1b5f19c218061d8a2ff834d45dcff3099c 100644 (file)
@@ -168,6 +168,14 @@ If you don't specify a host with
 won't try to connect to other daemons at all,
 and will instead just listen for incoming connections.
 
 won't try to connect to other daemons at all,
 and will instead just listen for incoming connections.
 
+.It Va DecrementTTL Li = yes | no Po yes Pc
+When enabled,
+.Nm tinc
+will decrement the Time To Live field in IPv4 packets, or the Hop Limit field in IPv6 packets,
+before forwarding a received packet to the virtual network device or to another node,
+and will drop packets that have a TTL value of zero,
+in which case it will send an ICMP Time Exceeded packet back.
+
 .It Va Device Li = Ar device Po Pa /dev/tap0 , Pa /dev/net/tun No or other depending on platform Pc
 The virtual network device to use.
 .Nm tinc
 .It Va Device Li = Ar device Po Pa /dev/tap0 , Pa /dev/net/tun No or other depending on platform Pc
 The virtual network device to use.
 .Nm tinc
index 3bb4407604c46be144621b352f18990343b25cf9..4b985dcd77e4240608b56b87f5128bde037e7f82 100644 (file)
@@ -785,6 +785,13 @@ If you don't specify a host with ConnectTo,
 tinc won't try to connect to other daemons at all,
 and will instead just listen for incoming connections.
 
 tinc won't try to connect to other daemons at all,
 and will instead just listen for incoming connections.
 
+@cindex DecrementTTL
+@item DecrementTTL = <yes | no> (yes)
+When enabled, tinc will decrement the Time To Live field in IPv4 packets, or the Hop Limit field in IPv6 packets,
+before forwarding a received packet to the virtual network device or to another node,
+and will drop packets that have a TTL value of zero,
+in which case it will send an ICMP Time Exceeded packet back.
+
 @cindex Device
 @item Device = <@var{device}> (@file{/dev/tap0}, @file{/dev/net/tun} or other depending on platform)
 The virtual network device to use.
 @cindex Device
 @item Device = <@var{device}> (@file{/dev/tap0}, @file{/dev/net/tun} or other depending on platform)
 The virtual network device to use.
index e9a063a50577d90a8b438d11017ba7ba4aee7125..2301c83a25a2badc884b153ea5c3792f8a1e4a98 100644 (file)
@@ -398,6 +398,8 @@ static bool setup_myself(void) {
 
        get_config_bool(lookup_config(config_tree, "PriorityInheritance"), &priorityinheritance);
 
 
        get_config_bool(lookup_config(config_tree, "PriorityInheritance"), &priorityinheritance);
 
+       get_config_bool(lookup_config(config_tree, "DecrementTTL"), &decrement_ttl);
+
 #if !defined(SOL_IP) || !defined(IP_TOS)
        if(priorityinheritance)
                logger(LOG_WARNING, "%s not supported on this platform", "PriorityInheritance");
 #if !defined(SOL_IP) || !defined(IP_TOS)
        if(priorityinheritance)
                logger(LOG_WARNING, "%s not supported on this platform", "PriorityInheritance");
index e3bcf3bb09ffc302cc135167212c18019fa1abdd..9e9f9d041997752d52f6adb0e724a3a5618a3983 100644 (file)
@@ -34,6 +34,7 @@
 
 rmode_t routing_mode = RMODE_ROUTER;
 fmode_t forwarding_mode = FMODE_INTERNAL;
 
 rmode_t routing_mode = RMODE_ROUTER;
 fmode_t forwarding_mode = FMODE_INTERNAL;
+bool decrement_ttl = true;
 bool directonly = false;
 bool priorityinheritance = false;
 int macexpire = 600;
 bool directonly = false;
 bool priorityinheritance = false;
 int macexpire = 600;
@@ -846,6 +847,50 @@ static void route_mac(node_t *source, vpn_packet_t *packet) {
        send_packet(subnet->owner, packet);
 }
 
        send_packet(subnet->owner, packet);
 }
 
+static bool do_decrement_ttl(node_t *source, vpn_packet_t *packet) {
+       uint16_t type = packet->data[12] << 8 | packet->data[13];
+
+       switch (type) {
+               case ETH_P_IP:
+                       if(!checklength(source, packet, 14 + 32))
+                               return false;
+
+                       if(packet->data[22] < 1) {
+                               route_ipv4_unreachable(source, packet, ICMP_TIME_EXCEEDED, ICMP_EXC_TTL);
+                               return false;
+                       }
+
+                       uint16_t old = packet->data[22] << 8 | packet->data[23];
+                       packet->data[22]--;
+                       uint16_t new = packet->data[22] << 8 | packet->data[23];
+
+                       uint32_t checksum = packet->data[24] << 8 | packet->data[25];
+                       checksum += old + (~new & 0xFFFF);
+                       while(checksum >> 16)
+                               checksum = (checksum & 0xFFFF) + (checksum >> 16);
+                       packet->data[24] = checksum >> 8;
+                       packet->data[25] = checksum & 0xff;
+
+                       return true;
+
+               case ETH_P_IPV6:
+                       if(!checklength(source, packet, 14 + 40))
+                               return false;
+
+                       if(packet->data[21] < 1) {
+                               route_ipv6_unreachable(source, packet, ICMP6_TIME_EXCEEDED, ICMP6_TIME_EXCEED_TRANSIT);
+                               return false;
+                       }
+
+                       packet->data[21]--;
+
+                       return true;
+
+               default:
+                       return true;
+       }
+}
+
 void route(node_t *source, vpn_packet_t *packet) {
        if(forwarding_mode == FMODE_KERNEL && source != myself) {
                send_packet(myself, packet);
 void route(node_t *source, vpn_packet_t *packet) {
        if(forwarding_mode == FMODE_KERNEL && source != myself) {
                send_packet(myself, packet);
@@ -855,6 +900,10 @@ void route(node_t *source, vpn_packet_t *packet) {
        if(!checklength(source, packet, ether_size))
                return;
 
        if(!checklength(source, packet, ether_size))
                return;
 
+       if(decrement_ttl && source != myself)
+               if(!do_decrement_ttl(source, packet))
+                       return;
+
        switch (routing_mode) {
                case RMODE_ROUTER:
                        {
        switch (routing_mode) {
                case RMODE_ROUTER:
                        {
index 49431f2051e2b2fda0240c24f4eb6b015cd87cf3..3585cef4718827fc9055342f2291079a0a962a7d 100644 (file)
@@ -38,6 +38,7 @@ typedef enum fmode_t {
 
 extern rmode_t routing_mode;
 extern fmode_t forwarding_mode;
 
 extern rmode_t routing_mode;
 extern fmode_t forwarding_mode;
+extern bool decrement_ttl;
 extern bool directonly;
 extern bool overwrite_mac;
 extern bool priorityinheritance;
 extern bool directonly;
 extern bool overwrite_mac;
 extern bool priorityinheritance;