Clamp MSS of IPv4 SYN packets.
authorGuus Sliepen <guus@tinc-vpn.org>
Fri, 15 Jan 2010 12:42:37 +0000 (13:42 +0100)
committerGuus Sliepen <guus@tinc-vpn.org>
Fri, 15 Jan 2010 12:42:37 +0000 (13:42 +0100)
Some ISPs block the ICMP Fragmentation Needed packets that tinc sends.  We
clamp the MSS of IPv4 SYN packets to prevent hosts behind those ISPs from
sending too large packets.

src/route.c

index 5117e92f4f41ca6dbf8554e086fe8de4ebfd2a64..829773180c87ab6d549e26b3d3e1577ed1c2499d 100644 (file)
@@ -93,6 +93,53 @@ static bool checklength(node_t *source, vpn_packet_t *packet, length_t length) {
                return true;
 }
 
+void clamp_mss(node_t *source, node_t *via, vpn_packet_t *packet) {
+       int i;
+       int len = ((packet->data[46] >> 4) - 5) * 4;
+
+       for(int i = 0; i < len;) {
+               if(packet->data[54 + i] == 0)
+                       break;
+
+               if(packet->data[54 + i] == 1) {
+                       i++;
+                       continue;
+               }
+
+               if(i > len - 2 || i > len - packet->data[55 + i])
+                       break;
+
+               if(packet->data[54 + i] != 2) {
+                       if(packet->data[55 + i] < 2)
+                               break;
+                       i += packet->data[55 + i];
+                       continue;
+               }
+
+               if(packet->data[55] != 4)
+                       break;
+
+               uint16_t oldmss = packet->data[56 + i] << 8 | packet->data[57 + i];
+               uint16_t newmss = via->mtu - 54;
+               uint16_t csum = packet->data[50] << 8 | packet->data[51];
+
+               if(oldmss <= newmss)
+                       break;
+               
+               ifdebug(TRAFFIC) logger(LOG_INFO, "Clamping MSS of packet from %s to %s to %d", source->name, via->name, newmss);
+
+               packet->data[56 + i] = newmss >> 8;
+               packet->data[57 + i] = newmss & 0xff;
+               csum ^= 0xffff;
+               csum -= oldmss;
+               csum += newmss;
+               csum ^= 0xffff;
+               packet->data[50] = csum >> 8;
+               packet->data[51] = csum & 0xff;
+               break;
+       }
+}
+
 static void swap_mac_addresses(vpn_packet_t *packet) {
        mac_t tmp;
        memcpy(&tmp, &packet->data[0], sizeof tmp);
@@ -328,6 +375,9 @@ static void route_ipv4_unicast(node_t *source, vpn_packet_t *packet) {
                return;
        }
 
+       if(via && via != myself && packet->data[23] == 6 && packet->len >= 58 && (packet->data[46] >> 4) > 5)
+               clamp_mss(source, via, packet);
        send_packet(subnet->owner, packet);
 }
 
@@ -740,6 +790,9 @@ static void route_mac(node_t *source, vpn_packet_t *packet) {
                }
        }
 
+       if(via && via != myself && (packet->data[12] << 8 | packet->data[13]) == ETH_P_IP && packet->len >= 58 && packet->data[23] == 6 && (packet->data[46] >> 4) > 5)
+               clamp_mss(source, via, packet);
        send_packet(subnet->owner, packet);
 }