Do not fragment packets smaller than RFC defined minimum MTUs.
[tinc] / src / route.c
index 2da781e..5117e92 100644 (file)
@@ -48,6 +48,7 @@ static const size_t ip6_size = sizeof(struct ip6_hdr);
 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 */
 
@@ -104,7 +105,7 @@ static void learn_mac(mac_t *address) {
        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 */
 
@@ -117,6 +118,7 @@ static void learn_mac(mac_t *address) {
                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 */
@@ -314,10 +316,10 @@ static void route_ipv4_unicast(node_t *source, vpn_packet_t *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, 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);
@@ -457,9 +459,9 @@ static void route_ipv6_unicast(node_t *source, vpn_packet_t *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;
        }
@@ -704,7 +706,7 @@ static void route_mac(node_t *source, vpn_packet_t *packet) {
        /* 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);
@@ -723,7 +725,7 @@ static void route_mac(node_t *source, vpn_packet_t *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);
@@ -731,7 +733,7 @@ static void route_mac(node_t *source, vpn_packet_t *packet) {
                                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;