From 7c7b68dbe02874324e4fcda9c13b9e8d9a8192cf Mon Sep 17 00:00:00 2001 From: David Gibson Date: Fri, 4 Nov 2022 14:10:35 +1100 Subject: [PATCH] Use typing to reduce chances of IPv4 endianness errors We recently corrected some errors handling the endianness of IPv4 addresses. These are very easy errors to make since although we mostly store them in network endianness, we sometimes need to manipulate them in host endianness. To reduce the chances of making such mistakes again, change to always using a (struct in_addr) instead of a bare in_addr_t or uint32_t to store network endian addresses. This makes it harder to accidentally do arithmetic or comparisons on such addresses as if they were host endian. We introduce a number of IN4_IS_ADDR_*() helpers to make it easier to directly work with struct in_addr values. This has the additional benefit of making the IPv4 and IPv6 paths more visually similar. Signed-off-by: David Gibson Signed-off-by: Stefano Brivio --- checksum.c | 7 ++++--- checksum.h | 3 ++- conf.c | 55 ++++++++++++++++++++++++++++-------------------------- dhcp.c | 11 +++++++---- icmp.c | 3 +-- passt.c | 2 +- passt.h | 12 ++++++------ tap.c | 18 +++++++++--------- tap.h | 8 ++++---- tcp.c | 48 +++++++++++++++++++++++------------------------ tcp.h | 2 +- udp.c | 30 ++++++++++++++--------------- udp.h | 2 +- util.h | 12 ++++++++++-- 14 files changed, 113 insertions(+), 100 deletions(-) diff --git a/checksum.c b/checksum.c index c59869c..29769d9 100644 --- a/checksum.c +++ b/checksum.c @@ -133,7 +133,8 @@ void csum_ip4_header(struct iphdr *ip4h) * @payload: ICMPv4 packet payload * @len: Length of @payload (not including UDP) */ -void csum_udp4(struct udphdr *udp4hr, in_addr_t saddr, in_addr_t daddr, +void csum_udp4(struct udphdr *udp4hr, + struct in_addr saddr, struct in_addr daddr, const void *payload, size_t len) { /* UDP checksums are optional, so don't bother */ @@ -142,8 +143,8 @@ void csum_udp4(struct udphdr *udp4hr, in_addr_t saddr, in_addr_t daddr, if (UDP4_REAL_CHECKSUMS) { /* UNTESTED: if we did want real UDPv4 checksums, this * is roughly what we'd need */ - uint32_t psum = csum_fold(htonl(saddr)) - + csum_fold(htonl(daddr)) + uint32_t psum = csum_fold(saddr.s_addr) + + csum_fold(daddr.s_addr) + htons(len + sizeof(*udp4hr)) + htons(IPPROTO_UDP); /* Add in partial checksum for the UDP header alone */ diff --git a/checksum.h b/checksum.h index b87b0d6..c6b6fb4 100644 --- a/checksum.h +++ b/checksum.h @@ -14,7 +14,8 @@ uint32_t sum_16b(const void *buf, size_t len); uint16_t csum_fold(uint32_t sum); uint16_t csum_unaligned(const void *buf, size_t len, uint32_t init); void csum_ip4_header(struct iphdr *ip4h); -void csum_udp4(struct udphdr *udp4hr, in_addr_t saddr, in_addr_t daddr, +void csum_udp4(struct udphdr *udp4hr, + struct in_addr saddr, struct in_addr daddr, const void *payload, size_t len); void csum_icmp4(struct icmphdr *ih, const void *payload, size_t len); void csum_udp6(struct udphdr *udp6hr, diff --git a/conf.c b/conf.c index 3bf7301..f5099a7 100644 --- a/conf.c +++ b/conf.c @@ -358,12 +358,12 @@ static void get_dns(struct ctx *c) int dns4_set, dns6_set, dnss_set, dns_set, fd; struct in6_addr *dns6 = &c->ip6.dns[0]; struct fqdn *s = c->dns_search; - uint32_t *dns4 = &c->ip4.dns[0]; + struct in_addr *dns4 = &c->ip4.dns[0]; struct lineread resolvconf; int line_len; char *line, *p, *end; - dns4_set = !c->ifi4 || !!*dns4; + dns4_set = !c->ifi4 || !IN4_IS_ADDR_UNSPECIFIED(dns4); dns6_set = !c->ifi6 || !IN6_IS_ADDR_UNSPECIFIED(dns6); dnss_set = !!*s->n || c->no_dns_search; dns_set = (dns4_set && dns6_set) || c->no_dns; @@ -389,15 +389,15 @@ static void get_dns(struct ctx *c) dns4 - &c->ip4.dns[0] < ARRAY_SIZE(c->ip4.dns) - 1 && inet_pton(AF_INET, p + 1, dns4)) { /* We can only access local addresses via the gw redirect */ - if (IPV4_IS_LOOPBACK(ntohl(*dns4))) { + if (IN4_IS_ADDR_LOOPBACK(dns4)) { if (c->no_map_gw) { - *dns4 = 0; + dns4->s_addr = htonl(INADDR_ANY); continue; } *dns4 = c->ip4.gw; } dns4++; - *dns4 = 0; + dns4->s_addr = htonl(INADDR_ANY); } if (!dns6_set && @@ -566,18 +566,19 @@ static unsigned int conf_ip4(unsigned int ifi, return 0; } - if (!ip4->gw) + if (IN4_IS_ADDR_UNSPECIFIED(&ip4->gw)) nl_route(0, ifi, AF_INET, &ip4->gw); - if (!ip4->addr) + if (IN4_IS_ADDR_UNSPECIFIED(&ip4->addr)) nl_addr(0, ifi, AF_INET, &ip4->addr, &ip4->prefix_len, NULL); if (!ip4->prefix_len) { - if (IN_CLASSA(ntohl(ip4->addr))) + in_addr_t addr = ntohl(ip4->addr.s_addr); + if (IN_CLASSA(addr)) ip4->prefix_len = (32 - IN_CLASSA_NSHIFT); - else if (IN_CLASSB(ntohl(ip4->addr))) + else if (IN_CLASSB(addr)) ip4->prefix_len = (32 - IN_CLASSB_NSHIFT); - else if (IN_CLASSC(ntohl(ip4->addr))) + else if (IN_CLASSC(addr)) ip4->prefix_len = (32 - IN_CLASSC_NSHIFT); else ip4->prefix_len = 32; @@ -588,7 +589,9 @@ static unsigned int conf_ip4(unsigned int ifi, if (MAC_IS_ZERO(mac)) nl_link(0, ifi, mac, 0, 0); - if (!ip4->gw || !ip4->addr || MAC_IS_ZERO(mac)) + if (IN4_IS_ADDR_UNSPECIFIED(&ip4->gw) || + IN4_IS_ADDR_UNSPECIFIED(&ip4->addr) || + MAC_IS_ZERO(mac)) return 0; return ifi; @@ -850,7 +853,7 @@ static void conf_print(const struct ctx *c) inet_ntop(AF_INET, &c->ip4.gw, buf4, sizeof(buf4))); } - for (i = 0; c->ip4.dns[i]; i++) { + for (i = 0; !IN4_IS_ADDR_UNSPECIFIED(&c->ip4.dns[i]); i++) { if (!i) info("DNS:"); inet_ntop(AF_INET, &c->ip4.dns[i], buf4, sizeof(buf4)); @@ -1088,7 +1091,7 @@ void conf(struct ctx *c, int argc, char **argv) char *runas = NULL, *logfile = NULL; struct in6_addr *dns6 = c->ip6.dns; struct fqdn *dnss = c->dns_search; - uint32_t *dns4 = c->ip4.dns; + struct in_addr *dns4 = c->ip4.dns; const char *optstring; unsigned int ifi = 0; int name, ret, b, i; @@ -1186,11 +1189,11 @@ void conf(struct ctx *c, int argc, char **argv) !IN6_IS_ADDR_LOOPBACK(&c->ip6.dns_fwd)) break; - if (c->ip4.dns_fwd == htonl(INADDR_ANY) && + if (IN4_IS_ADDR_UNSPECIFIED(&c->ip4.dns_fwd) && inet_pton(AF_INET, optarg, &c->ip4.dns_fwd) && - c->ip4.dns_fwd != htonl(INADDR_ANY) && - c->ip4.dns_fwd != htonl(INADDR_BROADCAST) && - !IPV4_IS_LOOPBACK(ntohl(c->ip4.dns_fwd))) + !IN4_IS_ADDR_UNSPECIFIED(&c->ip4.dns_fwd) && + !IN4_IS_ADDR_BROADCAST(&c->ip4.dns_fwd) && + !IN4_IS_ADDR_LOOPBACK(&c->ip4.dns_fwd)) break; err("Invalid DNS forwarding address: %s", optarg); @@ -1384,12 +1387,12 @@ void conf(struct ctx *c, int argc, char **argv) !IN6_IS_ADDR_MULTICAST(&c->ip6.addr)) break; - if (c->ip4.addr == htonl(INADDR_ANY) && + if (IN4_IS_ADDR_UNSPECIFIED(&c->ip4.addr) && inet_pton(AF_INET, optarg, &c->ip4.addr) && - c->ip4.addr != htonl(INADDR_ANY) && - c->ip4.addr != htonl(INADDR_BROADCAST) && - !IPV4_IS_LOOPBACK(ntohl(c->ip4.addr)) && - !IN_MULTICAST(ntohl(c->ip4.addr))) + !IN4_IS_ADDR_UNSPECIFIED(&c->ip4.addr) && + !IN4_IS_ADDR_BROADCAST(&c->ip4.addr) && + !IN4_IS_ADDR_LOOPBACK(&c->ip4.addr) && + !IN4_IS_ADDR_MULTICAST(&c->ip4.addr)) break; err("Invalid address: %s", optarg); @@ -1420,11 +1423,11 @@ void conf(struct ctx *c, int argc, char **argv) !IN6_IS_ADDR_LOOPBACK(&c->ip6.gw)) break; - if (c->ip4.gw == htonl(INADDR_ANY) && + if (IN4_IS_ADDR_UNSPECIFIED(&c->ip4.gw) && inet_pton(AF_INET, optarg, &c->ip4.gw) && - c->ip4.gw != htonl(INADDR_ANY) && - c->ip4.gw != htonl(INADDR_BROADCAST) && - !IPV4_IS_LOOPBACK(ntohl(c->ip4.gw))) + !IN4_IS_ADDR_UNSPECIFIED(&c->ip4.gw) && + !IN4_IS_ADDR_BROADCAST(&c->ip4.gw) && + !IN4_IS_ADDR_LOOPBACK(&c->ip4.gw)) break; err("Invalid gateway address: %s", optarg); diff --git a/dhcp.c b/dhcp.c index 076e9b6..0c6f712 100644 --- a/dhcp.c +++ b/dhcp.c @@ -107,7 +107,7 @@ struct msg { uint16_t secs; uint16_t flags; uint32_t ciaddr; - uint32_t yiaddr; + struct in_addr yiaddr; uint32_t siaddr; uint32_t giaddr; uint8_t chaddr[16]; @@ -343,7 +343,8 @@ int dhcp(const struct ctx *c, const struct pool *p) /* If the gateway is not on the assigned subnet, send an option 121 * (Classless Static Routing) adding a dummy route to it. */ - if ((c->ip4.addr & mask.s_addr) != (c->ip4.gw & mask.s_addr)) { + if ((c->ip4.addr.s_addr & mask.s_addr) + != (c->ip4.gw.s_addr & mask.s_addr)) { /* a.b.c.d/32:0.0.0.0, 0:a.b.c.d */ opts[121].slen = 14; opts[121].s[0] = 32; @@ -357,8 +358,10 @@ int dhcp(const struct ctx *c, const struct pool *p) opts[26].s[1] = c->mtu % 256; } - for (i = 0, opts[6].slen = 0; !c->no_dhcp_dns && c->ip4.dns[i]; i++) { - ((uint32_t *)opts[6].s)[i] = c->ip4.dns[i]; + for (i = 0, opts[6].slen = 0; + !c->no_dhcp_dns && !IN4_IS_ADDR_UNSPECIFIED(&c->ip4.dns[i]); + i++) { + ((struct in_addr *)opts[6].s)[i] = c->ip4.dns[i]; opts[6].slen += sizeof(uint32_t); } diff --git a/icmp.c b/icmp.c index d388815..b842fa8 100644 --- a/icmp.c +++ b/icmp.c @@ -130,8 +130,7 @@ void icmp_sock_handler(const struct ctx *c, union epoll_ref ref, debug("ICMP: echo %s to tap, ID: %i, seq: %i", (ih->type == ICMP_ECHO) ? "request" : "reply", id, seq); - tap_icmp4_send(c, sr4->sin_addr.s_addr, tap_ip4_daddr(c), - buf, n); + tap_icmp4_send(c, sr4->sin_addr, tap_ip4_daddr(c), buf, n); } } diff --git a/passt.c b/passt.c index 34cd832..fd703de 100644 --- a/passt.c +++ b/passt.c @@ -136,7 +136,7 @@ static void timer_init(struct ctx *c, const struct timespec *now) * @ip_da: Pointer to IPv4 destination address, NULL if unchanged */ void proto_update_l2_buf(const unsigned char *eth_d, const unsigned char *eth_s, - const uint32_t *ip_da) + const struct in_addr *ip_da) { tcp_update_l2_buf(eth_d, eth_s, ip_da); udp_update_l2_buf(eth_d, eth_s, ip_da); diff --git a/passt.h b/passt.h index 4cf6078..1a8d74b 100644 --- a/passt.h +++ b/passt.h @@ -105,12 +105,12 @@ enum passt_modes { * @dns_fwd: Address forwarded (UDP) to first IPv4 DNS, network order */ struct ip4_ctx { - uint32_t addr; - uint32_t addr_seen; + struct in_addr addr; + struct in_addr addr_seen; int prefix_len; - uint32_t gw; - uint32_t dns[MAXNS + 1]; - uint32_t dns_fwd; + struct in_addr gw; + struct in_addr dns[MAXNS + 1]; + struct in_addr dns_fwd; }; /** @@ -248,6 +248,6 @@ struct ctx { }; void proto_update_l2_buf(const unsigned char *eth_d, const unsigned char *eth_s, - const uint32_t *ip_da); + const struct in_addr *ip_da); #endif /* PASST_H */ diff --git a/tap.c b/tap.c index 0a3ccce..84e93c2 100644 --- a/tap.c +++ b/tap.c @@ -92,7 +92,7 @@ int tap_send(const struct ctx *c, const void *data, size_t len) * * Returns: IPv4 address, network order */ -in_addr_t tap_ip4_daddr(const struct ctx *c) +struct in_addr tap_ip4_daddr(const struct ctx *c) { return c->ip4.addr_seen; } @@ -141,7 +141,7 @@ static void *tap_push_l2h(const struct ctx *c, void *buf, uint16_t proto) * * Return: pointer at which to write the packet's payload */ -static void *tap_push_ip4h(char *buf, in_addr_t src, in_addr_t dst, +static void *tap_push_ip4h(char *buf, struct in_addr src, struct in_addr dst, size_t len, uint8_t proto) { struct iphdr *ip4h = (struct iphdr *)buf; @@ -154,8 +154,8 @@ static void *tap_push_ip4h(char *buf, in_addr_t src, in_addr_t dst, ip4h->frag_off = 0; ip4h->ttl = 255; ip4h->protocol = proto; - ip4h->saddr = src; - ip4h->daddr = dst; + ip4h->saddr = src.s_addr; + ip4h->daddr = dst.s_addr; csum_ip4_header(ip4h); return ip4h + 1; } @@ -170,8 +170,8 @@ static void *tap_push_ip4h(char *buf, in_addr_t src, in_addr_t dst, * @in: UDP payload contents (not including UDP header) * @len: UDP payload length (not including UDP header) */ -void tap_udp4_send(const struct ctx *c, in_addr_t src, in_port_t sport, - in_addr_t dst, in_port_t dport, +void tap_udp4_send(const struct ctx *c, struct in_addr src, in_port_t sport, + struct in_addr dst, in_port_t dport, const void *in, size_t len) { size_t udplen = len + sizeof(struct udphdr); @@ -199,7 +199,7 @@ void tap_udp4_send(const struct ctx *c, in_addr_t src, in_port_t sport, * @in: ICMP packet, including ICMP header * @len: ICMP packet length, including ICMP header */ -void tap_icmp4_send(const struct ctx *c, in_addr_t src, in_addr_t dst, +void tap_icmp4_send(const struct ctx *c, struct in_addr src, struct in_addr dst, void *in, size_t len) { char buf[USHRT_MAX]; @@ -448,8 +448,8 @@ resume: l4_len = l3_len - hlen; - if (iph->saddr && c->ip4.addr_seen != iph->saddr) { - c->ip4.addr_seen = iph->saddr; + if (iph->saddr && c->ip4.addr_seen.s_addr != iph->saddr) { + c->ip4.addr_seen.s_addr = iph->saddr; proto_update_l2_buf(NULL, NULL, &c->ip4.addr_seen); } diff --git a/tap.h b/tap.h index 743bc58..674ab5c 100644 --- a/tap.h +++ b/tap.h @@ -6,11 +6,11 @@ #ifndef TAP_H #define TAP_H -in_addr_t tap_ip4_daddr(const struct ctx *c); -void tap_udp4_send(const struct ctx *c, in_addr_t src, in_port_t sport, - in_addr_t dst, in_port_t dport, +struct in_addr tap_ip4_daddr(const struct ctx *c); +void tap_udp4_send(const struct ctx *c, struct in_addr src, in_port_t sport, + struct in_addr dst, in_port_t dport, const void *in, size_t len); -void tap_icmp4_send(const struct ctx *c, in_addr_t src, in_addr_t dst, +void tap_icmp4_send(const struct ctx *c, struct in_addr src, struct in_addr dst, void *in, size_t len); const struct in6_addr *tap_ip6_daddr(const struct ctx *c, const struct in6_addr *src); diff --git a/tcp.c b/tcp.c index e6979a9..7405ba9 100644 --- a/tcp.c +++ b/tcp.c @@ -1107,7 +1107,7 @@ static void tcp_update_check_tcp6(struct tcp6_l2_buf_t *buf) * @ip_da: Pointer to IPv4 destination address, NULL if unchanged */ void tcp_update_l2_buf(const unsigned char *eth_d, const unsigned char *eth_s, - const uint32_t *ip_da) + const struct in_addr *ip_da) { int i; @@ -1134,16 +1134,16 @@ void tcp_update_l2_buf(const unsigned char *eth_d, const unsigned char *eth_s, } if (ip_da) { - b4f->iph.daddr = b4->iph.daddr = *ip_da; + b4f->iph.daddr = b4->iph.daddr = ip_da->s_addr; if (!i) { b4f->iph.saddr = b4->iph.saddr = 0; b4f->iph.tot_len = b4->iph.tot_len = 0; b4f->iph.check = b4->iph.check = 0; b4f->psum = b4->psum = sum_16b(&b4->iph, 20); - b4->tsum = ((*ip_da >> 16) & 0xffff) + - (*ip_da & 0xffff) + - htons(IPPROTO_TCP); + b4->tsum = ((ip_da->s_addr >> 16) & 0xffff) + + (ip_da->s_addr & 0xffff) + + htons(IPPROTO_TCP); b4f->tsum = b4->tsum; } else { b4f->psum = b4->psum = tcp4_l2_buf[0].psum; @@ -1701,7 +1701,7 @@ do { \ ip_len = plen + sizeof(struct iphdr) + sizeof(struct tcphdr); b->iph.tot_len = htons(ip_len); b->iph.saddr = conn->a.a4.a.s_addr; - b->iph.daddr = c->ip4.addr_seen; + b->iph.daddr = c->ip4.addr_seen.s_addr; if (check) b->iph.check = *check; @@ -2048,7 +2048,7 @@ static uint32_t tcp_seq_init(const struct ctx *c, int af, const void *addr, } __attribute__((__packed__)) in = { .src = *(struct in_addr *)addr, .srcport = srcport, - .dst = { c->ip4.addr }, + .dst = c->ip4.addr, .dstport = dstport, }; @@ -2176,10 +2176,10 @@ static void tcp_conn_from_tap(struct ctx *c, int af, const void *addr, return; if (!c->no_map_gw) { - if (af == AF_INET && addr4.sin_addr.s_addr == c->ip4.gw) - addr4.sin_addr.s_addr = htonl(INADDR_LOOPBACK); + if (af == AF_INET && IN4_ARE_ADDR_EQUAL(addr, &c->ip4.gw)) + addr4.sin_addr.s_addr = htonl(INADDR_LOOPBACK); if (af == AF_INET6 && IN6_ARE_ADDR_EQUAL(addr, &c->ip6.gw)) - addr6.sin6_addr = in6addr_loopback; + addr6.sin6_addr = in6addr_loopback; } if (af == AF_INET6 && IN6_IS_ADDR_LINKLOCAL(&addr6.sin6_addr)) { @@ -2899,30 +2899,28 @@ static void tcp_conn_from_sock(struct ctx *c, union epoll_ref ref, tcp_hash_insert(c, conn, AF_INET6, &sa6.sin6_addr); } else { struct sockaddr_in sa4; - in_addr_t s_addr; memcpy(&sa4, &sa, sizeof(sa4)); - s_addr = ntohl(sa4.sin_addr.s_addr); memset(&conn->a.a4.zero, 0, sizeof(conn->a.a4.zero)); memset(&conn->a.a4.one, 0xff, sizeof(conn->a.a4.one)); - if (IPV4_IS_LOOPBACK(s_addr) || s_addr == INADDR_ANY || - htonl(s_addr) == c->ip4.addr_seen) - s_addr = ntohl(c->ip4.gw); + if (IN4_IS_ADDR_LOOPBACK(&sa4.sin_addr) || + IN4_IS_ADDR_UNSPECIFIED(&sa4.sin_addr) || + IN4_ARE_ADDR_EQUAL(&sa4.sin_addr, &c->ip4.addr_seen)) + sa4.sin_addr = c->ip4.gw; - s_addr = htonl(s_addr); - memcpy(&conn->a.a4.a, &s_addr, sizeof(conn->a.a4.a)); + conn->a.a4.a = sa4.sin_addr; conn->sock_port = ntohs(sa4.sin_port); conn->tap_port = ref.r.p.tcp.tcp.index; - conn->seq_to_tap = tcp_seq_init(c, AF_INET, &s_addr, + conn->seq_to_tap = tcp_seq_init(c, AF_INET, &sa4.sin_addr, conn->sock_port, conn->tap_port, now); - tcp_hash_insert(c, conn, AF_INET, &s_addr); + tcp_hash_insert(c, conn, AF_INET, &sa4.sin_addr); } conn->seq_ack_from_tap = conn->seq_to_tap + 1; @@ -3081,7 +3079,7 @@ void tcp_sock_handler(struct ctx *c, union epoll_ref ref, uint32_t events, * @ifname: Name of interface to bind to, NULL if not configured * @port: Port, host order */ -static void tcp_sock_init4(const struct ctx *c, int ns, const in_addr_t *addr, +static void tcp_sock_init4(const struct ctx *c, int ns, const struct in_addr *addr, const char *ifname, in_port_t port) { union tcp_epoll_ref tref = { .tcp.listen = 1, .tcp.outbound = ns }; @@ -3089,14 +3087,13 @@ static void tcp_sock_init4(const struct ctx *c, int ns, const in_addr_t *addr, int s; if (c->mode == MODE_PASTA) { - spliced = !addr || - ntohl(*addr) == INADDR_ANY || - IPV4_IS_LOOPBACK(ntohl(*addr)); + spliced = !addr || IN4_IS_ADDR_UNSPECIFIED(addr) || + IN4_IS_ADDR_LOOPBACK(addr); if (!addr) addr = &c->ip4.addr; - tap = !ns && !IPV4_IS_LOOPBACK(ntohl(*addr)); + tap = !ns && !IN4_IS_ADDR_LOOPBACK(addr); } if (ns) @@ -3117,9 +3114,10 @@ static void tcp_sock_init4(const struct ctx *c, int ns, const in_addr_t *addr, } if (spliced) { + struct in_addr loopback = { htonl(INADDR_LOOPBACK) }; tref.tcp.splice = 1; - addr = &(uint32_t){ htonl(INADDR_LOOPBACK) }; + addr = &loopback; s = sock_l4(c, AF_INET, IPPROTO_TCP, addr, ifname, port, tref.u32); diff --git a/tcp.h b/tcp.h index 72e7815..3fabb5a 100644 --- a/tcp.h +++ b/tcp.h @@ -28,7 +28,7 @@ void tcp_defer_handler(struct ctx *c); void tcp_sock_set_bufsize(const struct ctx *c, int s); void tcp_update_l2_buf(const unsigned char *eth_d, const unsigned char *eth_s, - const uint32_t *ip_da); + const struct in_addr *ip_da); /** * union tcp_epoll_ref - epoll reference portion for TCP connections diff --git a/udp.c b/udp.c index 7ce533d..fca418d 100644 --- a/udp.c +++ b/udp.c @@ -298,7 +298,7 @@ static void udp_update_check4(struct udp4_l2_buf_t *buf) * @ip_da: Pointer to IPv4 destination address, NULL if unchanged */ void udp_update_l2_buf(const unsigned char *eth_d, const unsigned char *eth_s, - const uint32_t *ip_da) + const struct in_addr *ip_da) { int i; @@ -317,7 +317,7 @@ void udp_update_l2_buf(const unsigned char *eth_d, const unsigned char *eth_s, } if (ip_da) { - b4->iph.daddr = *ip_da; + b4->iph.daddr = ip_da->s_addr; if (!i) { b4->iph.saddr = 0; b4->iph.tot_len = 0; @@ -671,30 +671,30 @@ static void udp_sock_fill_data_v4(const struct ctx *c, int n, struct udp4_l2_buf_t *b = &udp4_l2_buf[n]; size_t ip_len, buf_len; in_port_t src_port; - in_addr_t src; ip_len = udp4_l2_mh_sock[n].msg_len + sizeof(b->iph) + sizeof(b->uh); b->iph.tot_len = htons(ip_len); - src = ntohl(b->s_in.sin_addr.s_addr); src_port = ntohs(b->s_in.sin_port); - if (IPV4_IS_LOOPBACK(src) || - src == INADDR_ANY || src == ntohl(c->ip4.addr_seen)) { - b->iph.saddr = c->ip4.gw; + if (IN4_IS_ADDR_LOOPBACK(&b->s_in.sin_addr) || + IN4_IS_ADDR_UNSPECIFIED(&b->s_in.sin_addr)|| + IN4_ARE_ADDR_EQUAL(&b->s_in.sin_addr, &c->ip4.addr_seen)) { + b->iph.saddr = c->ip4.gw.s_addr; udp_tap_map[V4][src_port].ts = now->tv_sec; udp_tap_map[V4][src_port].flags |= PORT_LOCAL; - if (b->s_in.sin_addr.s_addr == c->ip4.addr_seen) + if (IN4_ARE_ADDR_EQUAL(&b->s_in.sin_addr.s_addr, &c->ip4.addr_seen)) udp_tap_map[V4][src_port].flags &= ~PORT_LOOPBACK; else udp_tap_map[V4][src_port].flags |= PORT_LOOPBACK; bitmap_set(udp_act[V4][UDP_ACT_TAP], src_port); - } else if (c->ip4.dns_fwd && - src == htonl(c->ip4.dns[0]) && src_port == 53) { - b->iph.saddr = c->ip4.dns_fwd; + } else if (!IN4_IS_ADDR_UNSPECIFIED(&c->ip4.dns_fwd) && + IN4_ARE_ADDR_EQUAL(&b->s_in.sin_addr, &c->ip4.dns[0]) && + src_port == 53) { + b->iph.saddr = c->ip4.dns_fwd.s_addr; } else { b->iph.saddr = b->s_in.sin_addr.s_addr; } @@ -1016,15 +1016,15 @@ int udp_tap_handler(struct ctx *c, int af, const void *addr, udp_tap_map[V4][src].ts = now->tv_sec; - if (s_in.sin_addr.s_addr == c->ip4.gw && !c->no_map_gw) { + if (IN4_ARE_ADDR_EQUAL(&s_in.sin_addr, &c->ip4.gw) && !c->no_map_gw) { if (!(udp_tap_map[V4][dst].flags & PORT_LOCAL) || (udp_tap_map[V4][dst].flags & PORT_LOOPBACK)) s_in.sin_addr.s_addr = htonl(INADDR_LOOPBACK); else - s_in.sin_addr.s_addr = c->ip4.addr_seen; - } else if (s_in.sin_addr.s_addr == c->ip4.dns_fwd && + s_in.sin_addr = c->ip4.addr_seen; + } else if (IN4_ARE_ADDR_EQUAL(&s_in.sin_addr, &c->ip4.dns_fwd) && ntohs(s_in.sin_port) == 53) { - s_in.sin_addr.s_addr = c->ip4.dns[0]; + s_in.sin_addr = c->ip4.dns[0]; } } else { s_in6 = (struct sockaddr_in6) { diff --git a/udp.h b/udp.h index b4ee8b7..2ac8610 100644 --- a/udp.h +++ b/udp.h @@ -17,7 +17,7 @@ void udp_sock_init(const struct ctx *c, int ns, sa_family_t af, int udp_init(struct ctx *c); void udp_timer(struct ctx *c, const struct timespec *ts); void udp_update_l2_buf(const unsigned char *eth_d, const unsigned char *eth_s, - const uint32_t *ip_da); + const struct in_addr *ip_da); /** * union udp_epoll_ref - epoll reference portion for TCP connections diff --git a/util.h b/util.h index c498a80..2d4e1ff 100644 --- a/util.h +++ b/util.h @@ -69,8 +69,16 @@ #define MAC_ZERO ((uint8_t [ETH_ALEN]){ 0 }) #define MAC_IS_ZERO(addr) (!memcmp((addr), MAC_ZERO, ETH_ALEN)) -#define IPV4_IS_LOOPBACK(addr) \ - ((addr) >> IN_CLASSA_NSHIFT == IN_LOOPBACKNET) +#define IN4_IS_ADDR_UNSPECIFIED(a) \ + ((a)->s_addr == htonl(INADDR_ANY)) +#define IN4_IS_ADDR_BROADCAST(a) \ + ((a)->s_addr == htonl(INADDR_BROADCAST)) +#define IN4_IS_ADDR_LOOPBACK(a) \ + (ntohl((a)->s_addr) >> IN_CLASSA_NSHIFT == IN_LOOPBACKNET) +#define IN4_IS_ADDR_MULTICAST(a) \ + (IN_MULTICAST(ntohl((a)->s_addr))) +#define IN4_ARE_ADDR_EQUAL(a, b) \ + (((struct in_addr *)(a))->s_addr == ((struct in_addr *)b)->s_addr) #define NS_FN_STACK_SIZE (RLIMIT_STACK_VAL * 1024 / 8) #define NS_CALL(fn, arg) \