aboutgitcodebugslistschat
diff options
context:
space:
mode:
-rw-r--r--icmp.c18
-rw-r--r--icmp.h4
-rw-r--r--tap.c5
3 files changed, 22 insertions, 5 deletions
diff --git a/icmp.c b/icmp.c
index 57d954a..49fdf91 100644
--- a/icmp.c
+++ b/icmp.c
@@ -87,10 +87,17 @@ void icmp_sock_handler(struct ctx *c, union epoll_ref ref, uint32_t events,
struct sockaddr_in6 *sr6 = (struct sockaddr_in6 *)&sr;
struct icmp6hdr *ih = (struct icmp6hdr *)buf;
+ id = ntohs(ih->icmp6_identifier);
+
+ /* If bind() fails e.g. because of a broken SELinux policy, this
+ * might happen. Fix up the identifier to match the sent one.
+ */
+ if (id != ref.icmp.id)
+ ih->icmp6_identifier = htons(ref.icmp.id);
+
/* In PASTA mode, we'll get any reply we send, discard them. */
if (c->mode == MODE_PASTA) {
seq = ntohs(ih->icmp6_sequence);
- id = ntohs(ih->icmp6_identifier);
if (icmp_id_map[V6][id].seq == seq)
return;
@@ -103,9 +110,12 @@ void icmp_sock_handler(struct ctx *c, union epoll_ref ref, uint32_t events,
struct sockaddr_in *sr4 = (struct sockaddr_in *)&sr;
struct icmphdr *ih = (struct icmphdr *)buf;
+ id = ntohs(ih->un.echo.id);
+ if (id != ref.icmp.id)
+ ih->un.echo.id = htons(ref.icmp.id);
+
if (c->mode == MODE_PASTA) {
seq = ntohs(ih->un.echo.sequence);
- id = ntohs(ih->un.echo.id);
if (icmp_id_map[V4][id].seq == seq)
return;
@@ -148,7 +158,7 @@ int icmp_tap_handler(struct ctx *c, int af, void *addr,
if (msg[0].l4_len < sizeof(*ih) || ih->type != ICMP_ECHO)
return 1;
- id = ntohs(ih->un.echo.id);
+ iref.id = id = ntohs(ih->un.echo.id);
if ((s = icmp_id_map[V4][id].sock) <= 0) {
s = sock_l4(c, AF_INET, IPPROTO_ICMP, id, 0, iref.u32);
@@ -177,7 +187,7 @@ int icmp_tap_handler(struct ctx *c, int af, void *addr,
(ih->icmp6_type != 128 && ih->icmp6_type != 129))
return 1;
- id = ntohs(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,
iref.u32);
diff --git a/icmp.h b/icmp.h
index 12547b7..27f0a5c 100644
--- a/icmp.h
+++ b/icmp.h
@@ -15,10 +15,12 @@ void icmp_timer(struct ctx *c, struct timespec *ts);
* union icmp_epoll_ref - epoll reference portion for ICMP tracking
* @v6: Set for IPv6 sockets or connections
* @u32: Opaque u32 value of reference
+ * @id: Associated echo identifier, needed if bind() fails
*/
union icmp_epoll_ref {
struct {
- uint32_t v6:1;
+ uint32_t v6:1,
+ id:16;
};
uint32_t u32;
};
diff --git a/tap.c b/tap.c
index e31a419..68d3633 100644
--- a/tap.c
+++ b/tap.c
@@ -134,6 +134,11 @@ void tap_ip_send(struct ctx *c, struct in6_addr *src, uint8_t proto,
struct udphdr *uh = (struct udphdr *)(iph + 1);
uh->check = 0;
+ } else if (iph->protocol == IPPROTO_ICMP) {
+ struct icmphdr *ih = (struct icmphdr *)(iph + 1);
+
+ ih->checksum = 0;
+ ih->checksum = csum_unaligned(ih, len, 0);
}
tap_send(c, buf, len + sizeof(*iph) + sizeof(*eh), 1);