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 <david@gibson.dropbear.id.au>
Signed-off-by: Stefano Brivio <sbrivio@redhat.com>
This commit is contained in:
David Gibson 2022-11-04 14:10:35 +11:00 committed by Stefano Brivio
parent dd3470d9a9
commit 7c7b68dbe0
14 changed files with 113 additions and 100 deletions

View file

@ -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 */

View file

@ -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,

55
conf.c
View file

@ -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);

11
dhcp.c
View file

@ -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);
}

3
icmp.c
View file

@ -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);
}
}

View file

@ -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);

12
passt.h
View file

@ -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 */

18
tap.c
View file

@ -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);
}

8
tap.h
View file

@ -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);

48
tcp.c
View file

@ -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);

2
tcp.h
View file

@ -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

30
udp.c
View file

@ -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) {

2
udp.h
View file

@ -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

12
util.h
View file

@ -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) \