static const size_t icmp6_size = sizeof(struct icmp6_hdr);
static const size_t ns_size = sizeof(struct nd_neighbor_solicit);
static const size_t opt_size = sizeof(struct nd_opt_hdr);
+#define max(a, b) ((a) > (b) ? (a) : (b))
/* RFC 1071 */
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);
avl_node_t *node;
connection_t *c;
- subnet = lookup_subnet_mac(address);
+ subnet = lookup_subnet_mac(myself, address);
/* If we don't know this MAC address yet, store it */
subnet->type = SUBNET_MAC;
subnet->expires = now + macexpire;
subnet->net.mac.address = *address;
+ subnet->weight = 10;
subnet_add(myself, subnet);
/* And tell all other tinc daemons it's our MAC */
via = (subnet->owner->via == myself) ? subnet->owner->nexthop : subnet->owner->via;
- if(via && packet->len > via->mtu && via != myself) {
+ if(via && packet->len > max(via->mtu, 590) && via != myself) {
ifdebug(TRAFFIC) logger(LOG_INFO, "Packet for %s (%s) length %d larger than MTU %d", subnet->owner->name, subnet->owner->hostname, packet->len, via->mtu);
if(packet->data[20] & 0x40) {
- packet->len = via->mtu;
+ packet->len = max(via->mtu, 590);
route_ipv4_unreachable(source, packet, ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED);
} else {
fragment_ipv4_packet(via, 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);
}
via = (subnet->owner->via == myself) ? subnet->owner->nexthop : subnet->owner->via;
- if(via && packet->len > via->mtu && via != myself) {
+ if(via && packet->len > max(via->mtu, 1294) && via != myself) {
ifdebug(TRAFFIC) logger(LOG_INFO, "Packet for %s (%s) length %d larger than MTU %d", subnet->owner->name, subnet->owner->hostname, packet->len, via->mtu);
- packet->len = via->mtu;
+ packet->len = max(via->mtu, 1294);
route_ipv6_unreachable(source, packet, ICMP6_PACKET_TOO_BIG, 0);
return;
}
/* Lookup destination address */
memcpy(&dest, &packet->data[0], sizeof dest);
- subnet = lookup_subnet_mac(&dest);
+ subnet = lookup_subnet_mac(NULL, &dest);
if(!subnet) {
broadcast_packet(source, packet);
if(via && packet->len > via->mtu && via != myself) {
ifdebug(TRAFFIC) logger(LOG_INFO, "Packet for %s (%s) length %d larger than MTU %d", subnet->owner->name, subnet->owner->hostname, packet->len, via->mtu);
uint16_t type = packet->data[12] << 8 | packet->data[13];
- if(type == ETH_P_IP) {
+ if(type == ETH_P_IP && packet->len > 590) {
if(packet->data[20] & 0x40) {
packet->len = via->mtu;
route_ipv4_unreachable(source, packet, ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED);
fragment_ipv4_packet(via, packet);
}
return;
- } else if(type == ETH_P_IPV6) {
+ } else if(type == ETH_P_IPV6 && packet->len > 1294) {
packet->len = via->mtu;
route_ipv6_unreachable(source, packet, ICMP6_PACKET_TOO_BIG, 0);
return;
}
}
+ 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);
}