Clamp MSS of IPv4 SYN packets.
[tinc] / src / route.c
index 5117e92..8297731 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);
 }