diff options
author | Stefano Brivio <sbrivio@redhat.com> | 2021-09-26 23:38:22 +0200 |
---|---|---|
committer | Stefano Brivio <sbrivio@redhat.com> | 2021-09-27 01:28:02 +0200 |
commit | dd581730e54b934f80d5b6a820136707dc71c664 (patch) | |
tree | c58b140d407f4b308e1fc1d21703b444ea34cabd /icmp.c | |
parent | dfc451319034f594037822b3193a30fa5715175f (diff) | |
download | passt-dd581730e54b934f80d5b6a820136707dc71c664.tar passt-dd581730e54b934f80d5b6a820136707dc71c664.tar.gz passt-dd581730e54b934f80d5b6a820136707dc71c664.tar.bz2 passt-dd581730e54b934f80d5b6a820136707dc71c664.tar.lz passt-dd581730e54b934f80d5b6a820136707dc71c664.tar.xz passt-dd581730e54b934f80d5b6a820136707dc71c664.tar.zst passt-dd581730e54b934f80d5b6a820136707dc71c664.zip |
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 <sbrivio@redhat.com>
Diffstat (limited to 'icmp.c')
-rw-r--r-- | icmp.c | 20 |
1 files changed, 13 insertions, 7 deletions
@@ -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)); } |