Description

Firewall filters containing match conditions with Layer 4 header elements, such as TCP/UDP ports, may unintentionally drop IP packets when they are fragmented.

Firewall filters containing match conditions with Layer 3 header elements only, such as source/destination IP address, CoS, protocol field or any other field contained in the IP header, are not impacted by fragmentation.

This article shows some typical use cases and describes possible mitigation techniques.

Symptoms

  • Moderate to high packet loss occurring in the network.
  • TCP sessions being frequently dropped for no apparent reasons.
  • IPsec-based applications having difficulties.
  • Firewall logs showing lots of dropped frames, for instance:
Time of Log: 2021-03-05 11:10:11 GMT, Filter: pfe, Filter action: discard, Name of interface: ae55.751, Name of protocol: UDP, Packet Length: 1448, Source address: 10.238.14.250, Destination address: 10.151.121.24

Solution

  • IP Fragmentation and Reassembly is the mechanism defined by  RFC791 , used to transmit large IP packets through a Layer 2 network, when their size exceeds the Maximum Transmission Unit (MTU) allowed to be carried within that network. For instance, when the router needs to transmit a 4000 byte long packet via a standard Ethernet interface, having MTU of 1500 bytes, the payload of the IP packet needs to be segmented into 3 independent fragments, each of them having a copy of the original IP header of 20 bytes, with fragmentation fields changing from fragment to fragment (the only common part is fragment identification, which uniquely identifies the fragmented packet and provides a means for the packet to be reassembled at its destination): 
  • Fragment 0, payload_size = 1480 bytes, total_length = 1500 bytes, fragment_offset = 0, more_fragments = 1, identification = 9111  
  • Fragment 1, payload_size = 1480 bytes, total_length = 1500 bytes, fragment_offset = 185, more_fragments = 1, identification = 9111
  • Fragment 2, payload_size = 980 bytes, total_length = 1000 bytes, fragment_offset = 370, more_fragments = 0 identification = 9111
The packets are reassembled on the destination host. There is no reassembly taking place on any intermediate hop between the source and the destination. Some router vendors have proprietary features in place allowing the user to force reassembly of the packets on the intermediate routers, though.

Fragmentation is applied on the complete IP payload, which includes Layer 4 headers as well. Since both TCP and UDP source and destination ports occupy the first 4 bytes of the Layer 4 header, they will always fall within the first IP fragment (0) only, while other fragments won't have that information. Therefore, if a fragmented IP packet is handled by a firewall filter matching on TCP or UDP ports, the filter will actually affect the first fragment only. Any successive fragments will skip the filter term where TCP/UDP ports are handled. For instance, if the firewall filter below is used as input filter on a router interface:

[edit firewall family inet]
filter protect-intranet {
    term intranet-8080 {
        from {
            source-address {
                198.51.100.8/29;
                198.51.100.16/29;
            }
            protocol tcp;
            destination-port 8080;
        }
        then accept;
    }
    term drop-the-rest {
        then discard;
    }
}

TCP packets sourced from  198.51.100.9 , using  8080/tcp  as destination port entering that router interface will pass the term  intranet-8080 , if they are not fragmented. Otherwise, if fragmentation occurs only the first fragment, containing TCP source/destination port information will pass the term  intranet-8080 , while all successive fragments not having port information will simply be dropped, because they will not pass the term  intranet-8080  and they will match the next one ( drop-the-rest ), having  discard  as action. Or even funnier - when the payload of the frame contains the number 8080 (hex:  0x1f90 ) in the 3rd and 4th byte of the payload (e.g. if the payload of the fragment begins with:  11 23 1F 90 ) the packet will be allowed, since the filter will recognize this as TCP packet with destination port 8080.

IMPORTANT NOTE  - some other vendors may have different ways of treating fragmented IP packets by packet filters containing Layer 4 information.
Beware of those use cases when dealing with mixed vendor environments!


For example, Cisco Access Control Lists containing TCP/UDP ports, treat fragmented IP packets differently. Instead of dropping fragments bluntly, they let the fragments through as long as the ACL rule matches on Layer 3 headers (i.e. if the source/destination IP address and protocol field within the IP packet matches the ACL rule). See article  Access Control Lists and IP Fragments  on the Cisco website for more details. For instance, the Junos Firewall Filter  protect-intranet  shown above translates to Cisco ACL shown below:

ip access-list extended protect-intranet
 permit tcp 198.51.100.8 0.0.0.7 any eq 8080
 permit 198.51.100.16 0.0.0.7 any eq 8080
 deny ip any any


If a fragmented TCP packet sourced from  198.51.100.9 , using  8080/tcp  as destination port comes into the router interface where the ACL above is defined as input filter, the first fragment will pass the first rule of the ACL, while any subsequent fragments, not having any TCP port information, will still match the first rule, because all those fragments will still have   198.51.100.9  as source IP address and Cisco ACL will let them through.

General Recommendation

IP Fragmentation and Reassembly is a mechanism that is more than 40-years old. Originally standardized by  RFC791 , it was intended for use by the networks of that time, which was not capable of handling large packets. The prescribed minimum MTU of 576 bytes required by IP was required back then as well. Networks have evolved since. Today, networks can easily handle packets as large as 9100 bytes. Some Juniper Networks routers can even handle packets up to 16,000 bytes in length.

On the other hand, to avoid fragmentation, many mechanisms have been developed, such as:

  • Path MTU Discovery (PMTUD) - standardized by RFC1191  (30 years ago!)
  • TCP MSS clamping - setting TCP MSS to a suitably low constant value (e.g. tcp-mss option in Junos BGP configuration)

Finally, the operational experience of many large operators revealed that IP fragmentation introduces severe fragility and security risks to various network applications. One of the oldest vulnerabilities of fragmentation are described in RFC1858 , which documents some fragmentation-related attacks.

Aside from security issues, fragmentation impacts other network mechanisms, such as Equal Cost Multi Path (ECMP), Link Aggregation Groups (IEEE 802.3ad LAGs), load balancing, stateless firewalls, etc. Most of those problems have recently been documented in RFC8900 . Therefore, the networks should ideally be designed to avoid fragmentation at all costs. MTU sizes in the network should be set to the same, consistent value throughout the network. The core layer of the network should make use of jumbo frames if possible. PMTUD or TCP MSS clamping should be in place for all end-to-end applications. When IP filters or firewalls are in place within the network, care must be taken not to block ICMP traffic; and if there is a need to filter ICMP traffic, ensure that ICMP Destination Unreachable / Fragmentation Needed  packets (ICMP Type=3, Code=4) are allowed to flow unblocked through the network.

Operational Solutions

 

Quick Fix

If your network applications strongly rely on IP fragmentation or you are dealing with legacy networks not capable of handling PMTUD properly, IP fragmentation will occur on a regular basis. In this case, firewall filters containing Layer 4 headers (e.g. TCP/UDP ports) should be designed to ensure proper handling of fragments not containing TCP/UDP port information. For example, for firewall filter protect-intranet shown in the example above, a quick fix would be to allow any non-zero fragments having the same source/destination IP addresses, regardless of TCP/UDP port information. This leads to the following configuration:


[edit firewall family inet]
filter protect-intranet {
    term intranet-8080 {
        from {
            source-address {
                198.51.100.8/29;
                198.51.100.16/29;
            }
            protocol tcp;
            destination-port 8080;
        }
        then accept;
    }
    term non-zero-fragments {
        from {
            source-address {
                198.51.100.8/29;
                198.51.100.16/29;
            }
            protocol tcp;
            is-fragment;     # Matches fragments with non-zero offset

        }
        then accept;
    }

    term drop-the-rest {
        then discard;
    }
}
 

RFC1858 - Tiny Attack Mitigation

While the filter above provides a viable solution, it may still expose the networks to the Tiny Fragment Attack, described in  RFC1858 , where two mitigation options are proposed. The so-called indirect method, still in use by many vendors today, blocks any fragments having offset value of 1 and IP protocol field of TCP.  RFC1858  provides a reasoning for this as follows:

" RFC791  demands that an IP stack must be capable of passing an 8 byte IP data payload without further fragmentation (fragments sit on 8 byte boundaries). Since an IP header can be up to 60 bytes long (including options), this means that the minimum MTU on a link should be 68 bytes. A typical IP header is only 20 bytes long and can therefore carry 48 bytes of data. No one in the real world should EVER be generating a TCP packet with FO=1, as it would require both that a previous system fragmenting IP data down to the 8 byte minimum and a 60 byte IP header".

Having the above in mind, this leads to the following configuration (Note: RFC791  defines Fragment Offset as a 12-bit field, representing the offset in the payload where the fragment starts, multiplied by 8; hence, the maximum value is 8191, allowing addressing offsets up to the maximum length of the IP packet, being 65535 bytes):
 

[edit firewall family inet]
filter protect-intranet {
    term intranet-8080 {                 # Matches non-fragmented packets and fragments with FO=0
        from {
            source-address {
                198.51.100.8/29;
                198.51.100.16/29;
            }
            protocol tcp;
            destination-port 8080;       # This information is contained in fragment zero, so we are fine
        }
        then accept;
    }
    term non-zero-fragments {
        from {
            source-address {
                198.51.100.8/29;
                198.51.100.16/29;
            }
            protocol tcp;
            fragment-offset 2-8191;      # FO=1 is dropped, only FO>1 and up are accepted

        }
        then accept;
    }

    term drop-the-rest {
        then discard;
    }
}
 

RFC3128  - Addendum for Tiny Attack Mitigation

RFC3128  provides an additional mitigation measure for Tiny Fragment Attacks, originally described in  RFC1858 . If the first fragment doesn't contain the full TCP header the packet should be dropped as well. The minimum size of the TCP header is 20 bytes. Added to the IP header length of 20 bytes, this gives the total minimum length of a TCP packet being 40 bytes. Any TCP packet having smaller size is apparently illegal. This gives the filter as follows:

[edit firewall family inet]
filter protect-intranet {
    term deny-tiny-fragments {
        from {
            packet-length [ 0-39 ];
            first-fragment;
            protocol tcp;
        }
        then discard;
    }

    term intranet-8080 {                 # Matches non-fragmented packets and fragments with FO=0
        from {
            source-address {
                198.51.100.8/29;
                198.51.100.16/29;
            }
            protocol tcp;
            destination-port 8080;       # This information is contained in fragment zero, so we are fine
        }
        then accept;
    }
    term non-zero-fragments {
        from {
            source-address {
                198.51.100.8/29;
                198.51.100.16/29;
            }
            protocol tcp;
            fragment-offset 2-8191;      # FO=1 is dropped, only FO>1 and up are accepted

        }
        then accept;
    }

    term drop-the-rest {
        then discard;
    }
}

Modification History

2021-06-14: Article rewritten to provide more clarity and reference to the latest best operational practices. 

Related Information