diff --git a/tap.c b/tap.c index e323529..a6a73d3 100644 --- a/tap.c +++ b/tap.c @@ -62,6 +62,7 @@ static PACKET_POOL_NOINIT(pool_tap4, TAP_MSGS, pkt_buf); static PACKET_POOL_NOINIT(pool_tap6, TAP_MSGS, pkt_buf); #define TAP_SEQS 128 /* Different L4 tuples in one batch */ +#define FRAGMENT_MSG_RATE 10 /* # seconds between fragment warnings */ /** * tap_send() - Send frame, with qemu socket header if needed @@ -543,6 +544,32 @@ static void tap_packet_debug(const struct iphdr *iph, } } +/** + * tap4_is_fragment() - Determine if a packet is an IP fragment + * @iph: IPv4 header (length already validated) + * @now: Current timestamp + * + * Return: true if iph is an IP fragment, false otherwise + */ +static bool tap4_is_fragment(const struct iphdr *iph, + const struct timespec *now) +{ + if (ntohs(iph->frag_off) & ~IP_DF) { + /* Ratelimit messages */ + static time_t last_message; + static unsigned num_dropped; + + num_dropped++; + if (now->tv_sec - last_message > FRAGMENT_MSG_RATE) { + warn("Can't process IPv4 fragments (%lu dropped)", num_dropped); + last_message = now->tv_sec; + num_dropped = 0; + } + return true; + } + return false; +} + /** * tap4_handler() - IPv4 and ARP packet handler for tap file descriptor * @c: Execution context @@ -591,6 +618,10 @@ resume: hlen > l3_len) continue; + /* We don't handle IP fragments, drop them */ + if (tap4_is_fragment(iph, now)) + continue; + l4_len = l3_len - hlen; if (iph->saddr && c->ip4.addr_seen.s_addr != iph->saddr) {