From dd581730e54b934f80d5b6a820136707dc71c664 Mon Sep 17 00:00:00 2001 From: Stefano Brivio Date: Sun, 26 Sep 2021 23:38:22 +0200 Subject: tap: Completely de-serialise input message batches Until now, messages would be passed to protocol handlers in a single batch only if they happened to be dequeued in a row. Packets interleaved between different connections would result in multiple calls to the same protocol handler for a single connection. Instead, keep track of incoming packet descriptors, arrange them in sequences, and call protocol handlers only as we completely sorted input messages in batches. Signed-off-by: Stefano Brivio --- icmp.c | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) (limited to 'icmp.c') diff --git a/icmp.c b/icmp.c index 49fdf91..51848c2 100644 --- a/icmp.c +++ b/icmp.c @@ -141,23 +141,26 @@ void icmp_sock_handler(struct ctx *c, union epoll_ref ref, uint32_t events, * Return: count of consumed packets (always 1, even if malformed) */ int icmp_tap_handler(struct ctx *c, int af, void *addr, - struct tap_msg *msg, int count, struct timespec *now) + struct tap_l4_msg *msg, int count, struct timespec *now) { (void)count; if (af == AF_INET) { - struct icmphdr *ih = (struct icmphdr *)msg[0].l4h; union icmp_epoll_ref iref = { .v6 = 0 }; struct sockaddr_in sa = { .sin_family = AF_INET, .sin_addr = { .s_addr = INADDR_ANY }, - .sin_port = ih->un.echo.id, }; + struct icmphdr *ih; int id, s; + ih = (struct icmphdr *)(pkt_buf + msg[0].pkt_buf_offset); + if (msg[0].l4_len < sizeof(*ih) || ih->type != ICMP_ECHO) return 1; + sa.sin_port = ih->un.echo.id; + iref.id = id = ntohs(ih->un.echo.id); if ((s = icmp_id_map[V4][id].sock) <= 0) { @@ -171,22 +174,25 @@ int icmp_tap_handler(struct ctx *c, int af, void *addr, bitmap_set(icmp_act[V4], id); sa.sin_addr = *(struct in_addr *)addr; - sendto(s, msg[0].l4h, msg[0].l4_len, MSG_NOSIGNAL, + sendto(s, ih, msg[0].l4_len, MSG_NOSIGNAL, (struct sockaddr *)&sa, sizeof(sa)); } else if (af == AF_INET6) { - struct icmp6hdr *ih = (struct icmp6hdr *)msg[0].l4h; union icmp_epoll_ref iref = { .v6 = 1 }; struct sockaddr_in6 sa = { .sin6_family = AF_INET6, .sin6_addr = IN6ADDR_ANY_INIT, - .sin6_port = ih->icmp6_identifier, }; + struct icmp6hdr *ih; int id, s; + ih = (struct icmp6hdr *)(pkt_buf + msg[0].pkt_buf_offset); + if (msg[0].l4_len < sizeof(*ih) || (ih->icmp6_type != 128 && ih->icmp6_type != 129)) return 1; + sa.sin6_port = ih->icmp6_identifier; + iref.id = id = ntohs(ih->icmp6_identifier); if ((s = icmp_id_map[V6][id].sock) <= 0) { s = sock_l4(c, AF_INET6, IPPROTO_ICMPV6, id, 0, @@ -200,7 +206,7 @@ int icmp_tap_handler(struct ctx *c, int af, void *addr, bitmap_set(icmp_act[V6], id); sa.sin6_addr = *(struct in6_addr *)addr; - sendto(s, msg[0].l4h, msg[0].l4_len, MSG_NOSIGNAL, + sendto(s, ih, msg[0].l4_len, MSG_NOSIGNAL, (struct sockaddr *)&sa, sizeof(sa)); } -- cgit v1.2.3