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 746d820..8d8e6f1 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.
 
+.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
index 3bb4407..4b985dc 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.
 
+@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.
index e9a063a..2301c83 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, "DecrementTTL"), &decrement_ttl);
+
 #if !defined(SOL_IP) || !defined(IP_TOS)
        if(priorityinheritance)
                logger(LOG_WARNING, "%s not supported on this platform", "PriorityInheritance");
index e3bcf3b..9e9f9d0 100644 (file)
@@ -34,6 +34,7 @@
 
 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;
@@ -846,6 +847,50 @@ static void route_mac(node_t *source, vpn_packet_t *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);
@@ -855,6 +900,10 @@ void route(node_t *source, vpn_packet_t *packet) {
        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:
                        {
index 49431f2..3585cef 100644 (file)
@@ -38,6 +38,7 @@ typedef enum fmode_t {
 
 extern rmode_t routing_mode;
 extern fmode_t forwarding_mode;
+extern bool decrement_ttl;
 extern bool directonly;
 extern bool overwrite_mac;
 extern bool priorityinheritance;