public inbox for passt-dev@passt.top
 help / color / mirror / code / Atom feed
From: David Gibson <david@gibson.dropbear.id.au>
To: passt-dev@passt.top
Subject: [PATCH 7/7] Make substructures for IPv4 and IPv6 specific context information
Date: Fri, 22 Jul 2022 15:31:18 +1000	[thread overview]
Message-ID: <20220722053118.1067459-8-david@gibson.dropbear.id.au> (raw)
In-Reply-To: <20220722053118.1067459-1-david@gibson.dropbear.id.au>

[-- Attachment #1: Type: text/plain, Size: 36325 bytes --]

The context structure contains a batch of fields specific to IPv4 and to
IPv6 connectivity.  Split those out into a sub-structure.

This allows the conf_ip4() and conf_ip6() functions, which take the
entire context but touch very little of it, to be given more specific
parameters, making it clearer what it affects without stepping through the
code.

Signed-off-by: David Gibson <david(a)gibson.dropbear.id.au>
---
 arp.c    |   2 +-
 conf.c   | 184 ++++++++++++++++++++++++++++---------------------------
 dhcp.c   |  22 +++----
 dhcpv6.c |  18 +++---
 ndp.c    |  16 ++---
 passt.c  |   2 +-
 passt.h  |  68 ++++++++++++--------
 pasta.c  |  10 +--
 tap.c    |  22 +++----
 tcp.c    |  34 +++++-----
 udp.c    |  62 +++++++++----------
 util.c   |   4 +-
 12 files changed, 232 insertions(+), 212 deletions(-)

diff --git a/arp.c b/arp.c
index e8f21b5..0ad97af 100644
--- a/arp.c
+++ b/arp.c
@@ -66,7 +66,7 @@ int arp(const struct ctx *c, const struct pool *p)
 		return 1;
 
 	/* Don't resolve our own address, either. */
-	if (!memcmp(am->tip, &c->addr4, sizeof(am->tip)))
+	if (!memcmp(am->tip, &c->ip4.addr, sizeof(am->tip)))
 		return 1;
 
 	ah->ar_op = htons(ARPOP_REPLY);
diff --git a/conf.c b/conf.c
index 2a4ef23..f46b195 100644
--- a/conf.c
+++ b/conf.c
@@ -404,9 +404,9 @@ overlap:
 static void get_dns(struct ctx *c)
 {
 	int dns4_set, dns6_set, dnss_set, dns_set, fd;
-	struct in6_addr *dns6 = &c->dns6[0];
+	struct in6_addr *dns6 = &c->ip6.dns[0];
 	struct fqdn *s = c->dns_search;
-	uint32_t *dns4 = &c->dns4[0];
+	uint32_t *dns4 = &c->ip4.dns[0];
 	struct lineread resolvconf;
 	int line_len;
 	char *line, *p, *end;
@@ -434,7 +434,7 @@ static void get_dns(struct ctx *c)
 				*end = 0;
 
 			if (!dns4_set &&
-			    dns4 - &c->dns4[0] < ARRAY_SIZE(c->dns4) - 1 &&
+			    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 (ntohl(*dns4) >> IN_CLASSA_NSHIFT == IN_LOOPBACKNET) {
@@ -442,14 +442,14 @@ static void get_dns(struct ctx *c)
 						*dns4 = 0;
 						continue;
 					}
-					*dns4 = c->gw4;
+					*dns4 = c->ip4.gw;
 				}
 				dns4++;
 				*dns4 = 0;
 			}
 
 			if (!dns6_set &&
-			    dns6 - &c->dns6[0] < ARRAY_SIZE(c->dns6) - 1 &&
+			    dns6 - &c->ip6.dns[0] < ARRAY_SIZE(c->ip6.dns) - 1 &&
 			    inet_pton(AF_INET6, p + 1, dns6)) {
 				/* We can only access local addresses via the gw redirect */
 				if (IN6_IS_ADDR_LOOPBACK(dns6)) {
@@ -457,7 +457,7 @@ static void get_dns(struct ctx *c)
 						memset(dns6, 0, sizeof(*dns6));
 						continue;
 					}
-					memcpy(dns6, &c->gw6, sizeof(*dns6));
+					memcpy(dns6, &c->ip6.gw, sizeof(*dns6));
 				}
 				dns6++;
 				memset(dns6, 0, sizeof(*dns6));
@@ -485,7 +485,7 @@ static void get_dns(struct ctx *c)
 	close(fd);
 
 out:
-	if (!dns_set && dns4 == c->dns4 && dns6 == c->dns6)
+	if (!dns_set && dns4 == c->ip4.dns && dns6 == c->ip6.dns)
 		warn("Couldn't get any nameserver address");
 }
 
@@ -612,12 +612,14 @@ static int conf_ns_opt(struct ctx *c,
 
 /**
  * conf_ip4() - Verify or detect IPv4 support, get relevant addresses
- * @c:		Execution context
  * @ifi:	Host interface to attempt (0 to determine one)
+ * @ip4:	IPv4 context (will be written)
+ * @mac:	MAC address to use (written if unset)
  *
  * Return:	Interface index for IPv4, or 0 on failure.
  */
-static unsigned int conf_ip4(struct ctx *c, unsigned int ifi)
+static unsigned int conf_ip4(unsigned int ifi,
+			     struct ip4_ctx *ip4, unsigned char *mac)
 {
 	if (!ifi)
 		ifi = nl_get_ext_if(AF_INET);
@@ -627,33 +629,33 @@ static unsigned int conf_ip4(struct ctx *c, unsigned int ifi)
 		return 0;
 	}
 
-	if (!c->gw4)
-		nl_route(0, ifi, AF_INET, &c->gw4);
+	if (!ip4->gw)
+		nl_route(0, ifi, AF_INET, &ip4->gw);
 
-	if (!c->addr4) {
+	if (!ip4->addr) {
 		int mask_len = 0;
 
-		nl_addr(0, ifi, AF_INET, &c->addr4, &mask_len, NULL);
-		c->mask4 = htonl(0xffffffff << (32 - mask_len));
+		nl_addr(0, ifi, AF_INET, &ip4->addr, &mask_len, NULL);
+		ip4->mask = htonl(0xffffffff << (32 - mask_len));
 	}
 
-	if (!c->mask4) {
-		if (IN_CLASSA(ntohl(c->addr4)))
-			c->mask4 = htonl(IN_CLASSA_NET);
-		else if (IN_CLASSB(ntohl(c->addr4)))
-			c->mask4 = htonl(IN_CLASSB_NET);
-		else if (IN_CLASSC(ntohl(c->addr4)))
-			c->mask4 = htonl(IN_CLASSC_NET);
+	if (!ip4->mask) {
+		if (IN_CLASSA(ntohl(ip4->addr)))
+			ip4->mask = htonl(IN_CLASSA_NET);
+		else if (IN_CLASSB(ntohl(ip4->addr)))
+			ip4->mask = htonl(IN_CLASSB_NET);
+		else if (IN_CLASSC(ntohl(ip4->addr)))
+			ip4->mask = htonl(IN_CLASSC_NET);
 		else
-			c->mask4 = 0xffffffff;
+			ip4->mask = 0xffffffff;
 	}
 
-	memcpy(&c->addr4_seen, &c->addr4, sizeof(c->addr4_seen));
+	memcpy(&ip4->addr_seen, &ip4->addr, sizeof(ip4->addr_seen));
 
-	if (MAC_IS_ZERO(c->mac))
-		nl_link(0, ifi, c->mac, 0, 0);
+	if (MAC_IS_ZERO(mac))
+		nl_link(0, ifi, mac, 0, 0);
 
-	if (!c->gw4 || !c->addr4 || MAC_IS_ZERO(c->mac))
+	if (!ip4->gw || !ip4->addr || MAC_IS_ZERO(mac))
 		return 0;
 
 	return ifi;
@@ -661,12 +663,14 @@ static unsigned int conf_ip4(struct ctx *c, unsigned int ifi)
 
 /**
  * conf_ip6() - Verify or detect IPv6 support, get relevant addresses
- * @c:		Execution context
  * @ifi:	Host interface to attempt (0 to determine one)
+ * @ip6:	IPv6 context (will be written)
+ * @mac:	MAC address to use (written if unset)
  *
  * Return:	Interface index for IPv6, or 0 on failure.
  */
-static unsigned int conf_ip6(struct ctx *c, unsigned int ifi)
+static unsigned int conf_ip6(unsigned int ifi,
+			     struct ip6_ctx *ip6, unsigned char *mac)
 {
 	int prefix_len = 0;
 
@@ -678,23 +682,23 @@ static unsigned int conf_ip6(struct ctx *c, unsigned int ifi)
 		return 0;
 	}
 
-	if (IN6_IS_ADDR_UNSPECIFIED(&c->gw6))
-		nl_route(0, ifi, AF_INET6, &c->gw6);
+	if (IN6_IS_ADDR_UNSPECIFIED(&ip6->gw))
+		nl_route(0, ifi, AF_INET6, &ip6->gw);
 
 	nl_addr(0, ifi, AF_INET6,
-		IN6_IS_ADDR_UNSPECIFIED(&c->addr6) ? &c->addr6 : NULL,
-		&prefix_len, &c->addr6_ll);
+		IN6_IS_ADDR_UNSPECIFIED(&ip6->addr) ? &ip6->addr : NULL,
+		&prefix_len, &ip6->addr_ll);
 
-	memcpy(&c->addr6_seen, &c->addr6, sizeof(c->addr6));
-	memcpy(&c->addr6_ll_seen, &c->addr6_ll, sizeof(c->addr6_ll));
+	memcpy(&ip6->addr_seen, &ip6->addr, sizeof(ip6->addr));
+	memcpy(&ip6->addr_ll_seen, &ip6->addr_ll, sizeof(ip6->addr_ll));
 
-	if (MAC_IS_ZERO(c->mac))
-		nl_link(0, ifi, c->mac, 0, 0);
+	if (MAC_IS_ZERO(mac))
+		nl_link(0, ifi, mac, 0, 0);
 
-	if (IN6_IS_ADDR_UNSPECIFIED(&c->gw6) ||
-	    IN6_IS_ADDR_UNSPECIFIED(&c->addr6) ||
-	    IN6_IS_ADDR_UNSPECIFIED(&c->addr6_ll) ||
-	    MAC_IS_ZERO(c->mac))
+	if (IN6_IS_ADDR_UNSPECIFIED(&ip6->gw) ||
+	    IN6_IS_ADDR_UNSPECIFIED(&ip6->addr) ||
+	    IN6_IS_ADDR_UNSPECIFIED(&ip6->addr_ll) ||
+	    MAC_IS_ZERO(mac))
 		return 0;
 
 	return ifi;
@@ -899,17 +903,17 @@ static void conf_print(const struct ctx *c)
 		if (!c->no_dhcp) {
 			info("DHCP:");
 			info("    assign: %s",
-			     inet_ntop(AF_INET, &c->addr4, buf4, sizeof(buf4)));
+			     inet_ntop(AF_INET, &c->ip4.addr, buf4, sizeof(buf4)));
 			info("    mask: %s",
-			     inet_ntop(AF_INET, &c->mask4, buf4, sizeof(buf4)));
+			     inet_ntop(AF_INET, &c->ip4.mask, buf4, sizeof(buf4)));
 			info("    router: %s",
-			     inet_ntop(AF_INET, &c->gw4,   buf4, sizeof(buf4)));
+			     inet_ntop(AF_INET, &c->ip4.gw,   buf4, sizeof(buf4)));
 		}
 
-		for (i = 0; c->dns4[i]; i++) {
+		for (i = 0; c->ip4.dns[i]; i++) {
 			if (!i)
 				info("DNS:");
-			inet_ntop(AF_INET, &c->dns4[i], buf4, sizeof(buf4));
+			inet_ntop(AF_INET, &c->ip4.dns[i], buf4, sizeof(buf4));
 			info("    %s", buf4);
 		}
 
@@ -933,17 +937,17 @@ static void conf_print(const struct ctx *c)
 			goto dns6;
 
 		info("    assign: %s",
-		     inet_ntop(AF_INET6, &c->addr6, buf6, sizeof(buf6)));
+		     inet_ntop(AF_INET6, &c->ip6.addr, buf6, sizeof(buf6)));
 		info("    router: %s",
-		     inet_ntop(AF_INET6, &c->gw6,   buf6, sizeof(buf6)));
+		     inet_ntop(AF_INET6, &c->ip6.gw,   buf6, sizeof(buf6)));
 		info("    our link-local: %s",
-		     inet_ntop(AF_INET6, &c->addr6_ll, buf6, sizeof(buf6)));
+		     inet_ntop(AF_INET6, &c->ip6.addr_ll, buf6, sizeof(buf6)));
 
 dns6:
-		for (i = 0; !IN6_IS_ADDR_UNSPECIFIED(&c->dns6[i]); i++) {
+		for (i = 0; !IN6_IS_ADDR_UNSPECIFIED(&c->ip6.dns[i]); i++) {
 			if (!i)
 				info("DNS:");
-			inet_ntop(AF_INET6, &c->dns6[i], buf6, sizeof(buf6));
+			inet_ntop(AF_INET6, &c->ip6.dns[i], buf6, sizeof(buf6));
 			info("    %s", buf6);
 		}
 
@@ -1065,9 +1069,9 @@ void conf(struct ctx *c, int argc, char **argv)
 	enum conf_port_type tcp_tap = 0, tcp_init = 0;
 	enum conf_port_type udp_tap = 0, udp_init = 0;
 	struct fqdn *dnss = c->dns_search;
-	struct in6_addr *dns6 = c->dns6;
+	struct in6_addr *dns6 = c->ip6.dns;
 	int name, ret, mask, b, i;
-	uint32_t *dns4 = c->dns4;
+	uint32_t *dns4 = c->ip4.dns;
 	bool v4_only = false, v6_only = false;
 	unsigned int ifi = 0;
 
@@ -1167,17 +1171,17 @@ void conf(struct ctx *c, int argc, char **argv)
 			c->no_dhcp_dns_search = 1;
 			break;
 		case 9:
-			if (IN6_IS_ADDR_UNSPECIFIED(&c->dns6_fwd)	&&
-			    inet_pton(AF_INET6, optarg, &c->dns6_fwd)	&&
-			    !IN6_IS_ADDR_UNSPECIFIED(&c->dns6_fwd)	&&
-			    !IN6_IS_ADDR_LOOPBACK(&c->dns6_fwd))
+			if (IN6_IS_ADDR_UNSPECIFIED(&c->ip6.dns_fwd)	&&
+			    inet_pton(AF_INET6, optarg, &c->ip6.dns_fwd) &&
+			    !IN6_IS_ADDR_UNSPECIFIED(&c->ip6.dns_fwd)	&&
+			    !IN6_IS_ADDR_LOOPBACK(&c->ip6.dns_fwd))
 				break;
 
-			if (c->dns4_fwd == INADDR_ANY			&&
-			    inet_pton(AF_INET, optarg, &c->dns4_fwd)	&&
-			    c->dns4_fwd != INADDR_ANY			&&
-			    c->dns4_fwd != INADDR_BROADCAST		&&
-			    c->dns4_fwd != INADDR_LOOPBACK)
+			if (c->ip4.dns_fwd == INADDR_ANY		&&
+			    inet_pton(AF_INET, optarg, &c->ip4.dns_fwd)	&&
+			    c->ip4.dns_fwd != INADDR_ANY		&&
+			    c->ip4.dns_fwd != INADDR_BROADCAST		&&
+			    c->ip4.dns_fwd != INADDR_LOOPBACK)
 				break;
 
 			err("Invalid DNS forwarding address: %s", optarg);
@@ -1334,34 +1338,34 @@ void conf(struct ctx *c, int argc, char **argv)
 			}
 			break;
 		case 'a':
-			if (IN6_IS_ADDR_UNSPECIFIED(&c->addr6)		&&
-			    inet_pton(AF_INET6, optarg, &c->addr6)	&&
-			    !IN6_IS_ADDR_UNSPECIFIED(&c->addr6)		&&
-			    !IN6_IS_ADDR_LOOPBACK(&c->addr6)		&&
-			    !IN6_IS_ADDR_V4MAPPED(&c->addr6)		&&
-			    !IN6_IS_ADDR_V4COMPAT(&c->addr6)		&&
-			    !IN6_IS_ADDR_MULTICAST(&c->addr6))
+			if (IN6_IS_ADDR_UNSPECIFIED(&c->ip6.addr)	&&
+			    inet_pton(AF_INET6, optarg, &c->ip6.addr)	&&
+			    !IN6_IS_ADDR_UNSPECIFIED(&c->ip6.addr)	&&
+			    !IN6_IS_ADDR_LOOPBACK(&c->ip6.addr)		&&
+			    !IN6_IS_ADDR_V4MAPPED(&c->ip6.addr)		&&
+			    !IN6_IS_ADDR_V4COMPAT(&c->ip6.addr)		&&
+			    !IN6_IS_ADDR_MULTICAST(&c->ip6.addr))
 				break;
 
-			if (c->addr4 == INADDR_ANY			&&
-			    inet_pton(AF_INET, optarg, &c->addr4)	&&
-			    c->addr4 != INADDR_ANY			&&
-			    c->addr4 != INADDR_BROADCAST		&&
-			    c->addr4 != INADDR_LOOPBACK			&&
-			    !IN_MULTICAST(c->addr4))
+			if (c->ip4.addr == INADDR_ANY			&&
+			    inet_pton(AF_INET, optarg, &c->ip4.addr)	&&
+			    c->ip4.addr != INADDR_ANY			&&
+			    c->ip4.addr != INADDR_BROADCAST		&&
+			    c->ip4.addr != INADDR_LOOPBACK		&&
+			    !IN_MULTICAST(c->ip4.addr))
 				break;
 
 			err("Invalid address: %s", optarg);
 			usage(argv[0]);
 			break;
 		case 'n':
-			if (inet_pton(AF_INET, optarg, &c->mask4))
+			if (inet_pton(AF_INET, optarg, &c->ip4.mask))
 				break;
 
 			errno = 0;
 			mask = strtol(optarg, NULL, 0);
 			if (mask > 0 && mask <= 32 && !errno) {
-				c->mask4 = htonl(0xffffffff << (32 - mask));
+				c->ip4.mask = htonl(0xffffffff << (32 - mask));
 				break;
 			}
 
@@ -1380,17 +1384,17 @@ void conf(struct ctx *c, int argc, char **argv)
 			}
 			break;
 		case 'g':
-			if (IN6_IS_ADDR_UNSPECIFIED(&c->gw6)		&&
-			    inet_pton(AF_INET6, optarg, &c->gw6)	&&
-			    !IN6_IS_ADDR_UNSPECIFIED(&c->gw6)		&&
-			    !IN6_IS_ADDR_LOOPBACK(&c->gw6))
+			if (IN6_IS_ADDR_UNSPECIFIED(&c->ip6.gw)		&&
+			    inet_pton(AF_INET6, optarg, &c->ip6.gw)	&&
+			    !IN6_IS_ADDR_UNSPECIFIED(&c->ip6.gw)	&&
+			    !IN6_IS_ADDR_LOOPBACK(&c->ip6.gw))
 				break;
 
-			if (c->gw4 == INADDR_ANY			&&
-			    inet_pton(AF_INET, optarg, &c->gw4)		&&
-			    c->gw4 != INADDR_ANY			&&
-			    c->gw4 != INADDR_BROADCAST			&&
-			    c->gw4 != INADDR_LOOPBACK)
+			if (c->ip4.gw == INADDR_ANY			&&
+			    inet_pton(AF_INET, optarg, &c->ip4.gw)	&&
+			    c->ip4.gw != INADDR_ANY			&&
+			    c->ip4.gw != INADDR_BROADCAST		&&
+			    c->ip4.gw != INADDR_LOOPBACK)
 				break;
 
 			err("Invalid gateway address: %s", optarg);
@@ -1410,7 +1414,7 @@ void conf(struct ctx *c, int argc, char **argv)
 			break;
 		case 'D':
 			if (c->no_dns ||
-			    (!optarg && (dns4 - c->dns4 || dns6 - c->dns6))) {
+			    (!optarg && (dns4 - c->ip4.dns || dns6 - c->ip6.dns))) {
 				err("Empty and non-empty DNS options given");
 				usage(argv[0]);
 			}
@@ -1420,13 +1424,13 @@ void conf(struct ctx *c, int argc, char **argv)
 				break;
 			}
 
-			if (dns4 - &c->dns4[0] < ARRAY_SIZE(c->dns4) &&
+			if (dns4 - &c->ip4.dns[0] < ARRAY_SIZE(c->ip4.dns) &&
 			    inet_pton(AF_INET, optarg, dns4)) {
 				dns4++;
 				break;
 			}
 
-			if (dns6 - &c->dns6[0] < ARRAY_SIZE(c->dns6) &&
+			if (dns6 - &c->ip6.dns[0] < ARRAY_SIZE(c->ip6.dns) &&
 			    inet_pton(AF_INET6, optarg, dns6)) {
 				dns6++;
 				break;
@@ -1511,9 +1515,9 @@ void conf(struct ctx *c, int argc, char **argv)
 		usage(argv[0]);
 	}
 	if (!v6_only)
-		c->ifi4 = conf_ip4(c, ifi);
+		c->ifi4 = conf_ip4(ifi, &c->ip4, c->mac);
 	if (!v4_only)
-		c->ifi6 = conf_ip6(c, ifi);
+		c->ifi6 = conf_ip6(ifi, &c->ip6, c->mac);
 	if (!c->ifi4 && !c->ifi6) {
 		err("External interface not usable");
 		exit(EXIT_FAILURE);
diff --git a/dhcp.c b/dhcp.c
index 32dee56..7ad1319 100644
--- a/dhcp.c
+++ b/dhcp.c
@@ -332,20 +332,20 @@ int dhcp(const struct ctx *c, const struct pool *p)
 	     m->chaddr[0], m->chaddr[1], m->chaddr[2],
 	     m->chaddr[3], m->chaddr[4], m->chaddr[5]);
 
-	m->yiaddr = c->addr4;
-	memcpy(opts[1].s,  &c->mask4, sizeof(c->mask4));
-	memcpy(opts[3].s,  &c->gw4,   sizeof(c->gw4));
-	memcpy(opts[54].s, &c->gw4,   sizeof(c->gw4));
+	m->yiaddr = c->ip4.addr;
+	memcpy(opts[1].s,  &c->ip4.mask, sizeof(c->ip4.mask));
+	memcpy(opts[3].s,  &c->ip4.gw,   sizeof(c->ip4.gw));
+	memcpy(opts[54].s, &c->ip4.gw,   sizeof(c->ip4.gw));
 
 	/* If the gateway is not on the assigned subnet, send an option 121
 	 * (Classless Static Routing) adding a dummy route to it.
 	 */
-	if ((c->addr4 & c->mask4) != (c->gw4 & c->mask4)) {
+	if ((c->ip4.addr & c->ip4.mask) != (c->ip4.gw & c->ip4.mask)) {
 		/* a.b.c.d/32:0.0.0.0, 0:a.b.c.d */
 		opts[121].slen = 14;
 		opts[121].s[0] = 32;
-		memcpy(opts[121].s + 1,  &c->gw4, sizeof(c->gw4));
-		memcpy(opts[121].s + 10, &c->gw4, sizeof(c->gw4));
+		memcpy(opts[121].s + 1,  &c->ip4.gw, sizeof(c->ip4.gw));
+		memcpy(opts[121].s + 10, &c->ip4.gw, sizeof(c->ip4.gw));
 	}
 
 	if (c->mtu != -1) {
@@ -354,8 +354,8 @@ 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->dns4[i]; i++) {
-		((uint32_t *)opts[6].s)[i] = c->dns4[i];
+	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];
 		opts[6].slen += sizeof(uint32_t);
 	}
 
@@ -368,8 +368,8 @@ int dhcp(const struct ctx *c, const struct pool *p)
 	uh->dest = htons(68);
 
 	iph->tot_len = htons(len += sizeof(*iph));
-	iph->daddr = c->addr4;
-	iph->saddr = c->gw4;
+	iph->daddr = c->ip4.addr;
+	iph->saddr = c->ip4.gw;
 	iph->check = 0;
 	iph->check = csum_unaligned(iph, (intptr_t)(iph->ihl * 4), 0);
 
diff --git a/dhcpv6.c b/dhcpv6.c
index 4124a3e..fbae88d 100644
--- a/dhcpv6.c
+++ b/dhcpv6.c
@@ -390,7 +390,7 @@ static size_t dhcpv6_dns_fill(const struct ctx *c, char *buf, int offset)
 	if (c->no_dhcp_dns)
 		goto search;
 
-	for (i = 0; !IN6_IS_ADDR_UNSPECIFIED(&c->dns6[i]); i++) {
+	for (i = 0; !IN6_IS_ADDR_UNSPECIFIED(&c->ip6.dns[i]); i++) {
 		if (!i) {
 			srv = (struct opt_dns_servers *)(buf + offset);
 			offset += sizeof(struct opt_hdr);
@@ -398,7 +398,7 @@ static size_t dhcpv6_dns_fill(const struct ctx *c, char *buf, int offset)
 			srv->hdr.l = 0;
 		}
 
-		memcpy(&srv->addr[i], &c->dns6[i], sizeof(srv->addr[i]));
+		memcpy(&srv->addr[i], &c->ip6.dns[i], sizeof(srv->addr[i]));
 		srv->hdr.l += sizeof(srv->addr[i]);
 		offset += sizeof(srv->addr[i]);
 	}
@@ -473,12 +473,12 @@ int dhcpv6(struct ctx *c, const struct pool *p,
 	if (mlen + sizeof(*uh) != ntohs(uh->len) || mlen < sizeof(*mh))
 		return -1;
 
-	c->addr6_ll_seen = *saddr;
+	c->ip6.addr_ll_seen = *saddr;
 
-	if (IN6_IS_ADDR_LINKLOCAL(&c->gw6))
-		src = &c->gw6;
+	if (IN6_IS_ADDR_LINKLOCAL(&c->ip6.gw))
+		src = &c->ip6.gw;
 	else
-		src = &c->addr6_ll;
+		src = &c->ip6.addr_ll;
 
 	mh = packet_get(p, 0, sizeof(*uh), sizeof(*mh), NULL);
 	if (!mh)
@@ -508,7 +508,7 @@ int dhcpv6(struct ctx *c, const struct pool *p,
 		if (mh->type == TYPE_CONFIRM && server_id)
 			return -1;
 
-		if ((bad_ia = dhcpv6_ia_notonlink(p, &c->addr6))) {
+		if ((bad_ia = dhcpv6_ia_notonlink(p, &c->ip6.addr))) {
 			info("DHCPv6: received CONFIRM with inappropriate IA,"
 			     " sending NotOnLink status in REPLY");
 
@@ -580,7 +580,7 @@ int dhcpv6(struct ctx *c, const struct pool *p,
 	resp.hdr.xid = mh->xid;
 
 	tap_ip_send(c, src, IPPROTO_UDP, (char *)&resp, n, mh->xid);
-	c->addr6_seen = c->addr6;
+	c->ip6.addr_seen = c->ip6.addr;
 
 	return 1;
 }
@@ -602,5 +602,5 @@ void dhcpv6_init(const struct ctx *c)
 	memcpy(resp.server_id.duid_lladdr,		c->mac, sizeof(c->mac));
 	memcpy(resp_not_on_link.server_id.duid_lladdr,	c->mac, sizeof(c->mac));
 
-	resp.ia_addr.addr	= c->addr6;
+	resp.ia_addr.addr	= c->ip6.addr;
 }
diff --git a/ndp.c b/ndp.c
index 4d13be3..29c4b14 100644
--- a/ndp.c
+++ b/ndp.c
@@ -107,7 +107,7 @@ int ndp(struct ctx *c, const struct icmp6hdr *ih,
 		p += 4;
 		*(uint32_t *)p = htonl(3600);	/* preferred lifetime */
 		p += 8;
-		memcpy(p, &c->addr6, 8);	/* prefix */
+		memcpy(p, &c->ip6.addr, 8);	/* prefix */
 		p += 16;
 
 		if (c->mtu != -1) {
@@ -121,7 +121,7 @@ int ndp(struct ctx *c, const struct icmp6hdr *ih,
 		if (c->no_dhcp_dns)
 			goto dns_done;
 
-		for (n = 0; !IN6_IS_ADDR_UNSPECIFIED(&c->dns6[n]); n++);
+		for (n = 0; !IN6_IS_ADDR_UNSPECIFIED(&c->ip6.dns[n]); n++);
 		if (n) {
 			*p++ = 25;				/* RDNSS */
 			*p++ = 1 + 2 * n;			/* length */
@@ -130,7 +130,7 @@ int ndp(struct ctx *c, const struct icmp6hdr *ih,
 			p += 4;
 
 			for (i = 0; i < n; i++) {
-				memcpy(p, &c->dns6[i], 16);	/* address */
+				memcpy(p, &c->ip6.dns[i], 16);	/* address */
 				p += 16;
 			}
 
@@ -177,15 +177,15 @@ dns_done:
 	len = (uintptr_t)p - (uintptr_t)ihr - sizeof(*ihr);
 
 	if (IN6_IS_ADDR_LINKLOCAL(saddr))
-		c->addr6_ll_seen = *saddr;
+		c->ip6.addr_ll_seen = *saddr;
 	else
-		c->addr6_seen = *saddr;
+		c->ip6.addr_seen = *saddr;
 
 	ip6hr->daddr = *saddr;
-	if (IN6_IS_ADDR_LINKLOCAL(&c->gw6))
-		ip6hr->saddr = c->gw6;
+	if (IN6_IS_ADDR_LINKLOCAL(&c->ip6.gw))
+		ip6hr->saddr = c->ip6.gw;
 	else
-		ip6hr->saddr = c->addr6_ll;
+		ip6hr->saddr = c->ip6.addr_ll;
 
 	ip6hr->payload_len = htons(sizeof(*ihr) + len);
 	ip6hr->hop_limit = IPPROTO_ICMPV6;
diff --git a/passt.c b/passt.c
index 18c3512..686d483 100644
--- a/passt.c
+++ b/passt.c
@@ -363,7 +363,7 @@ int main(int argc, char **argv)
 	if ((!c.no_udp && udp_init(&c)) || (!c.no_tcp && tcp_init(&c)))
 		exit(EXIT_FAILURE);
 
-	proto_update_l2_buf(c.mac_guest, c.mac, &c.addr4);
+	proto_update_l2_buf(c.mac_guest, c.mac, &c.ip4.addr);
 
 	if (c.ifi4 && !c.no_dhcp)
 		dhcp_init();
diff --git a/passt.h b/passt.h
index a8d5992..347e7c1 100644
--- a/passt.h
+++ b/passt.h
@@ -94,6 +94,44 @@ enum passt_modes {
 	MODE_PASTA,
 };
 
+/**
+ * struct ip4_ctx - IPv4 execution context
+ * @addr:		IPv4 address for external, routable interface
+ * @addr_seen:		Latest IPv4 address seen as source from tap
+ * @mask:		IPv4 netmask, network order
+ * @gw:			Default IPv4 gateway, network order
+ * @dns:		IPv4 DNS addresses, zero-terminated, network order
+ * @dns_fwd:		Address forwarded (UDP) to first IPv4 DNS, network order
+ */
+struct ip4_ctx {
+	uint32_t addr;
+	uint32_t addr_seen;
+	uint32_t mask;
+	uint32_t gw;
+	uint32_t dns[MAXNS + 1];
+	uint32_t dns_fwd;
+};
+
+/**
+ * struct ip6_ctx - IPv6 execution context
+ * @addr:		IPv6 address for external, routable interface
+ * @addr_ll:		Link-local IPv6 address on external, routable interface
+ * @addr_seen:		Latest IPv6 global/site address seen as source from tap
+ * @addr_ll_seen:	Latest IPv6 link-local address seen as source from tap
+ * @gw:			Default IPv6 gateway
+ * @dns:		IPv6 DNS addresses, zero-terminated
+ * @dns_fwd:		Address forwarded (UDP) to first IPv6 DNS, network order
+ */
+struct ip6_ctx {
+	struct in6_addr addr;
+	struct in6_addr addr_ll;
+	struct in6_addr addr_seen;
+	struct in6_addr addr_ll_seen;
+	struct in6_addr gw;
+	struct in6_addr dns[MAXNS + 1];
+	struct in6_addr dns_fwd;
+};
+
 /**
  * struct ctx - Execution context
  * @mode:		Operation mode, qemu/UNIX domain socket or namespace/tap
@@ -122,21 +160,10 @@ enum passt_modes {
  * @mac:		Host MAC address
  * @mac_guest:		MAC address of guest or namespace, seen or configured
  * @ifi4:		Index of routable interface for IPv4, 0 if IPv4 disabled
- * @addr4:		IPv4 address for external, routable interface
- * @addr4_seen:		Latest IPv4 address seen as source from tap
- * @mask4:		IPv4 netmask, network order
- * @gw4:		Default IPv4 gateway, network order
- * @dns4:		IPv4 DNS addresses, zero-terminated, network order
- * @dns4_fwd:		Address forwarded (UDP) to first IPv4 DNS, network order
+ * @ip:			IPv4 configuration
  * @dns_search:		DNS search list
  * @ifi6:		Index of routable interface for IPv6, 0 if IPv6 disabled
- * @addr6:		IPv6 address for external, routable interface
- * @addr6_ll:		Link-local IPv6 address on external, routable interface
- * @addr6_seen:		Latest IPv6 global/site address seen as source from tap
- * @addr6_ll_seen:	Latest IPv6 link-local address seen as source from tap
- * @gw6:		Default IPv6 gateway
- * @dns6:		IPv6 DNS addresses, zero-terminated
- * @dns6_fwd:		Address forwarded (UDP) to first IPv6 DNS, network order
+ * @ip6:		IPv6 configuration
  * @pasta_ifn:		Name of namespace interface for pasta
  * @pasta_ifn:		Index of namespace interface for pasta
  * @pasta_conf_ns:	Configure namespace interface after creating it
@@ -192,23 +219,12 @@ struct ctx {
 	unsigned char mac_guest[ETH_ALEN];
 
 	unsigned int ifi4;
-	uint32_t addr4;
-	uint32_t addr4_seen;
-	uint32_t mask4;
-	uint32_t gw4;
-	uint32_t dns4[MAXNS + 1];
-	uint32_t dns4_fwd;
+	struct ip4_ctx ip4;
 
 	struct fqdn dns_search[MAXDNSRCH];
 
 	unsigned int ifi6;
-	struct in6_addr addr6;
-	struct in6_addr addr6_ll;
-	struct in6_addr addr6_seen;
-	struct in6_addr addr6_ll_seen;
-	struct in6_addr gw6;
-	struct in6_addr dns6[MAXNS + 1];
-	struct in6_addr dns6_fwd;
+	struct ip6_ctx ip6;
 
 	char pasta_ifn[IF_NAMESIZE];
 	unsigned int pasta_ifi;
diff --git a/pasta.c b/pasta.c
index 2d7b5a1..5a78065 100644
--- a/pasta.c
+++ b/pasta.c
@@ -196,17 +196,17 @@ void pasta_ns_conf(struct ctx *c)
 		nl_link(1, c->pasta_ifi, c->mac_guest, 1, c->mtu);
 
 		if (c->ifi4) {
-			prefix_len = __builtin_popcount(c->mask4);
-			nl_addr(1, c->pasta_ifi, AF_INET, &c->addr4,
+			prefix_len = __builtin_popcount(c->ip4.mask);
+			nl_addr(1, c->pasta_ifi, AF_INET, &c->ip4.addr,
 				&prefix_len, NULL);
-			nl_route(1, c->pasta_ifi, AF_INET, &c->gw4);
+			nl_route(1, c->pasta_ifi, AF_INET, &c->ip4.gw);
 		}
 
 		if (c->ifi6) {
 			prefix_len = 64;
-			nl_addr(1, c->pasta_ifi, AF_INET6, &c->addr6,
+			nl_addr(1, c->pasta_ifi, AF_INET6, &c->ip6.addr,
 				&prefix_len, NULL);
-			nl_route(1, c->pasta_ifi, AF_INET6, &c->gw6);
+			nl_route(1, c->pasta_ifi, AF_INET6, &c->ip6.gw);
 		}
 	} else {
 		nl_link(1, c->pasta_ifi, c->mac_guest, 0, 0);
diff --git a/tap.c b/tap.c
index 8d552e9..3231da7 100644
--- a/tap.c
+++ b/tap.c
@@ -130,7 +130,7 @@ void tap_ip_send(const struct ctx *c, const struct in6_addr *src, uint8_t proto,
 		iph->frag_off = 0;
 		iph->ttl = 255;
 		iph->protocol = proto;
-		iph->daddr = c->addr4_seen;
+		iph->daddr = c->ip4.addr_seen;
 		memcpy(&iph->saddr, &src->s6_addr[12], 4);
 
 		iph->check = 0;
@@ -165,9 +165,9 @@ void tap_ip_send(const struct ctx *c, const struct in6_addr *src, uint8_t proto,
 
 		ip6h->saddr = *src;
 		if (IN6_IS_ADDR_LINKLOCAL(src))
-			ip6h->daddr = c->addr6_ll_seen;
+			ip6h->daddr = c->ip6.addr_ll_seen;
 		else
-			ip6h->daddr = c->addr6_seen;
+			ip6h->daddr = c->ip6.addr_seen;
 
 		memcpy(data, in, len);
 
@@ -354,9 +354,9 @@ resume:
 
 		l4_len = l3_len - hlen;
 
-		if (iph->saddr && c->addr4_seen != iph->saddr) {
-			c->addr4_seen = iph->saddr;
-			proto_update_l2_buf(NULL, NULL, &c->addr4_seen);
+		if (iph->saddr && c->ip4.addr_seen != iph->saddr) {
+			c->ip4.addr_seen = iph->saddr;
+			proto_update_l2_buf(NULL, NULL, &c->ip4.addr_seen);
 		}
 
 		l4h = packet_get(in, i, sizeof(*eh) + hlen, l4_len, NULL);
@@ -504,13 +504,13 @@ resume:
 			continue;
 
 		if (IN6_IS_ADDR_LINKLOCAL(saddr)) {
-			c->addr6_ll_seen = *saddr;
+			c->ip6.addr_ll_seen = *saddr;
 
-			if (IN6_IS_ADDR_UNSPECIFIED(&c->addr6_seen)) {
-				c->addr6_seen = *saddr;
+			if (IN6_IS_ADDR_UNSPECIFIED(&c->ip6.addr_seen)) {
+				c->ip6.addr_seen = *saddr;
 			}
 		} else {
-			c->addr6_seen = *saddr;
+			c->ip6.addr_seen = *saddr;
 		}
 
 		if (proto == IPPROTO_ICMPV6) {
@@ -545,7 +545,7 @@ resume:
 				continue;
 		}
 
-		*saddr = c->addr6;
+		*saddr = c->ip6.addr;
 
 		if (proto != IPPROTO_TCP && proto != IPPROTO_UDP) {
 			tap_packet_debug(NULL, ip6h, NULL, proto, NULL, 1);
diff --git a/tcp.c b/tcp.c
index 3382dfd..ec8c32e 100644
--- a/tcp.c
+++ b/tcp.c
@@ -1700,9 +1700,9 @@ do {									\
 		b->ip6h.payload_len = htons(plen + sizeof(struct tcphdr));
 		b->ip6h.saddr = conn->a.a6;
 		if (IN6_IS_ADDR_LINKLOCAL(&b->ip6h.saddr))
-			b->ip6h.daddr = c->addr6_ll_seen;
+			b->ip6h.daddr = c->ip6.addr_ll_seen;
 		else
-			b->ip6h.daddr = c->addr6_seen;
+			b->ip6h.daddr = c->ip6.addr_seen;
 
 		memset(b->ip6h.flow_lbl, 0, 3);
 
@@ -1723,7 +1723,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->addr4_seen;
+		b->iph.daddr = c->ip4.addr_seen;
 
 		if (check)
 			b->iph.check = *check;
@@ -2069,7 +2069,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->addr4 },
+			.dst = { c->ip4.addr },
 			.dstport = dstport,
 		};
 
@@ -2083,7 +2083,7 @@ static uint32_t tcp_seq_init(const struct ctx *c, int af, const void *addr,
 		} __attribute__((__packed__)) in = {
 			.src = *(struct in6_addr *)addr,
 			.srcport = srcport,
-			.dst = c->addr6,
+			.dst = c->ip6.addr,
 			.dstport = dstport,
 		};
 
@@ -2197,16 +2197,16 @@ 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->gw4)
+		if (af == AF_INET && addr4.sin_addr.s_addr == c->ip4.gw)
 			addr4.sin_addr.s_addr	= htonl(INADDR_LOOPBACK);
-		if (af == AF_INET6 && IN6_ARE_ADDR_EQUAL(addr, &c->gw6))
+		if (af == AF_INET6 && IN6_ARE_ADDR_EQUAL(addr, &c->ip6.gw))
 			addr6.sin6_addr		= in6addr_loopback;
 	}
 
 	if (af == AF_INET6 && IN6_IS_ADDR_LINKLOCAL(&addr6.sin6_addr)) {
 		struct sockaddr_in6 addr6_ll = {
 			.sin6_family = AF_INET6,
-			.sin6_addr = c->addr6_ll,
+			.sin6_addr = c->ip6.addr_ll,
 			.sin6_scope_id = c->ifi6,
 		};
 		if (bind(s, (struct sockaddr *)&addr6_ll, sizeof(addr6_ll))) {
@@ -2894,14 +2894,14 @@ static void tcp_conn_from_sock(struct ctx *c, union epoll_ref ref,
 		memcpy(&sa6, &sa, sizeof(sa6));
 
 		if (IN6_IS_ADDR_LOOPBACK(&sa6.sin6_addr) ||
-		    IN6_ARE_ADDR_EQUAL(&sa6.sin6_addr, &c->addr6_seen) ||
-		    IN6_ARE_ADDR_EQUAL(&sa6.sin6_addr, &c->addr6)) {
+		    IN6_ARE_ADDR_EQUAL(&sa6.sin6_addr, &c->ip6.addr_seen) ||
+		    IN6_ARE_ADDR_EQUAL(&sa6.sin6_addr, &c->ip6.addr)) {
 			struct in6_addr *src;
 
-			if (IN6_IS_ADDR_LINKLOCAL(&c->gw6))
-				src = &c->gw6;
+			if (IN6_IS_ADDR_LINKLOCAL(&c->ip6.gw))
+				src = &c->ip6.gw;
 			else
-				src = &c->addr6_ll;
+				src = &c->ip6.addr_ll;
 
 			memcpy(&sa6.sin6_addr, src, sizeof(*src));
 		}
@@ -2928,8 +2928,8 @@ static void tcp_conn_from_sock(struct ctx *c, union epoll_ref ref,
 		memset(&conn->a.a4.one, 0xff, sizeof(conn->a.a4.one));
 
 		if (s_addr >> IN_CLASSA_NSHIFT == IN_LOOPBACKNET ||
-		    s_addr == INADDR_ANY || htonl(s_addr) == c->addr4_seen)
-			s_addr = ntohl(c->gw4);
+		    s_addr == INADDR_ANY || htonl(s_addr) == c->ip4.addr_seen)
+			s_addr = ntohl(c->ip4.gw);
 
 		s_addr = htonl(s_addr);
 		memcpy(&conn->a.a4.a, &s_addr, sizeof(conn->a.a4.a));
@@ -3118,7 +3118,7 @@ void tcp_sock_init(const struct ctx *c, int ns, sa_family_t af,
 
 	if (af == AF_INET || af == AF_UNSPEC) {
 		if (!addr && c->mode == MODE_PASTA)
-			bind_addr = &c->addr4;
+			bind_addr = &c->ip4.addr;
 		else
 			bind_addr = addr;
 
@@ -3159,7 +3159,7 @@ void tcp_sock_init(const struct ctx *c, int ns, sa_family_t af,
 
 	if (af == AF_INET6 || af == AF_UNSPEC) {
 		if (!addr && c->mode == MODE_PASTA)
-			bind_addr = &c->addr6;
+			bind_addr = &c->ip6.addr;
 		else
 			bind_addr = addr;
 
diff --git a/udp.c b/udp.c
index 856429f..c4ebecc 100644
--- a/udp.c
+++ b/udp.c
@@ -690,20 +690,20 @@ static void udp_sock_fill_data_v4(const struct ctx *c, int n,
 	src_port = htons(b->s_in.sin_port);
 
 	if (src >> IN_CLASSA_NSHIFT == IN_LOOPBACKNET ||
-	    src == INADDR_ANY || src == ntohl(c->addr4_seen)) {
-		b->iph.saddr = c->gw4;
+	    src == INADDR_ANY || src == ntohl(c->ip4.addr_seen)) {
+		b->iph.saddr = c->ip4.gw;
 		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->addr4_seen)
+		if (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->dns4_fwd &&
-		   src == ntohl(c->dns4[0]) && ntohs(src_port) == 53) {
-		b->iph.saddr = c->dns4_fwd;
+	} else if (c->ip4.dns_fwd &&
+		   src == ntohl(c->ip4.dns[0]) && ntohs(src_port) == 53) {
+		b->iph.saddr = c->ip4.dns_fwd;
 	} else {
 		b->iph.saddr = b->s_in.sin_addr.s_addr;
 	}
@@ -768,17 +768,17 @@ static void udp_sock_fill_data_v6(const struct ctx *c, int n,
 	b->ip6h.payload_len = htons(udp6_l2_mh_sock[n].msg_len + sizeof(b->uh));
 
 	if (IN6_IS_ADDR_LINKLOCAL(src)) {
-		b->ip6h.daddr = c->addr6_ll_seen;
+		b->ip6h.daddr = c->ip6.addr_ll_seen;
 		b->ip6h.saddr = b->s_in6.sin6_addr;
 	} else if (IN6_IS_ADDR_LOOPBACK(src)			||
-		   IN6_ARE_ADDR_EQUAL(src, &c->addr6_seen)	||
-		   IN6_ARE_ADDR_EQUAL(src, &c->addr6)) {
-		b->ip6h.daddr = c->addr6_ll_seen;
+		   IN6_ARE_ADDR_EQUAL(src, &c->ip6.addr_seen)	||
+		   IN6_ARE_ADDR_EQUAL(src, &c->ip6.addr)) {
+		b->ip6h.daddr = c->ip6.addr_ll_seen;
 
-		if (IN6_IS_ADDR_LINKLOCAL(&c->gw6))
-			b->ip6h.saddr = c->gw6;
+		if (IN6_IS_ADDR_LINKLOCAL(&c->ip6.gw))
+			b->ip6h.saddr = c->ip6.gw;
 		else
-			b->ip6h.saddr = c->addr6_ll;
+			b->ip6h.saddr = c->ip6.addr_ll;
 
 		udp_tap_map[V6][src_port].ts = now->tv_sec;
 		udp_tap_map[V6][src_port].flags |= PORT_LOCAL;
@@ -788,18 +788,18 @@ static void udp_sock_fill_data_v6(const struct ctx *c, int n,
 		else
 			udp_tap_map[V6][src_port].flags &= ~PORT_LOOPBACK;
 
-		if (IN6_ARE_ADDR_EQUAL(src, &c->addr6))
+		if (IN6_ARE_ADDR_EQUAL(src, &c->ip6.addr))
 			udp_tap_map[V6][src_port].flags |= PORT_GUA;
 		else
 			udp_tap_map[V6][src_port].flags &= ~PORT_GUA;
 
 		bitmap_set(udp_act[V6][UDP_ACT_TAP], src_port);
-	} else if (!IN6_IS_ADDR_UNSPECIFIED(&c->dns6_fwd) &&
-		   IN6_ARE_ADDR_EQUAL(src, &c->dns6_fwd) && src_port == 53) {
-		b->ip6h.daddr = c->addr6_seen;
-		b->ip6h.saddr = c->dns6_fwd;
+	} else if (!IN6_IS_ADDR_UNSPECIFIED(&c->ip6.dns_fwd) &&
+		   IN6_ARE_ADDR_EQUAL(src, &c->ip6.dns_fwd) && src_port == 53) {
+		b->ip6h.daddr = c->ip6.addr_seen;
+		b->ip6h.saddr = c->ip6.dns_fwd;
 	} else {
-		b->ip6h.daddr = c->addr6_seen;
+		b->ip6h.daddr = c->ip6.addr_seen;
 		b->ip6h.saddr = b->s_in6.sin6_addr;
 	}
 
@@ -1015,15 +1015,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->gw4 && !c->no_map_gw) {
+		if (s_in.sin_addr.s_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->addr4_seen;
-		} else if (s_in.sin_addr.s_addr == c->dns4_fwd &&
+				s_in.sin_addr.s_addr = c->ip4.addr_seen;
+		} else if (s_in.sin_addr.s_addr == c->ip4.dns_fwd &&
 			   ntohs(s_in.sin_port) == 53) {
-			s_in.sin_addr.s_addr = c->dns4[0];
+			s_in.sin_addr.s_addr = c->ip4.dns[0];
 		}
 	} else {
 		s_in6 = (struct sockaddr_in6) {
@@ -1036,19 +1036,19 @@ int udp_tap_handler(struct ctx *c, int af, const void *addr,
 		sa = (struct sockaddr *)&s_in6;
 		sl = sizeof(s_in6);
 
-		if (IN6_ARE_ADDR_EQUAL(addr, &c->gw6) && !c->no_map_gw) {
+		if (IN6_ARE_ADDR_EQUAL(addr, &c->ip6.gw) && !c->no_map_gw) {
 			if (!(udp_tap_map[V6][dst].flags & PORT_LOCAL) ||
 			    (udp_tap_map[V6][dst].flags & PORT_LOOPBACK))
 				s_in6.sin6_addr = in6addr_loopback;
 			else if (udp_tap_map[V6][dst].flags & PORT_GUA)
-				s_in6.sin6_addr = c->addr6;
+				s_in6.sin6_addr = c->ip6.addr;
 			else
-				s_in6.sin6_addr = c->addr6_seen;
-		} else if (IN6_ARE_ADDR_EQUAL(addr, &c->dns6_fwd) &&
+				s_in6.sin6_addr = c->ip6.addr_seen;
+		} else if (IN6_ARE_ADDR_EQUAL(addr, &c->ip6.dns_fwd) &&
 			   ntohs(s_in6.sin6_port) == 53) {
-			s_in6.sin6_addr = c->dns6[0];
+			s_in6.sin6_addr = c->ip6.dns[0];
 		} else if (IN6_IS_ADDR_LINKLOCAL(&s_in6.sin6_addr)) {
-			bind_addr = &c->addr6_ll;
+			bind_addr = &c->ip6.addr_ll;
 		}
 
 		if (!(s = udp_tap_map[V6][src].sock)) {
@@ -1122,7 +1122,7 @@ void udp_sock_init(const struct ctx *c, int ns, sa_family_t af,
 
 	if (af == AF_INET || af == AF_UNSPEC) {
 		if (!addr && c->mode == MODE_PASTA)
-			bind_addr = &c->addr4;
+			bind_addr = &c->ip4.addr;
 		else
 			bind_addr = addr;
 
@@ -1155,7 +1155,7 @@ void udp_sock_init(const struct ctx *c, int ns, sa_family_t af,
 
 	if (af == AF_INET6 || af == AF_UNSPEC) {
 		if (!addr && c->mode == MODE_PASTA)
-			bind_addr = &c->addr6;
+			bind_addr = &c->ip6.addr;
 		else
 			bind_addr = addr;
 
diff --git a/util.c b/util.c
index f4ec102..9b87b65 100644
--- a/util.c
+++ b/util.c
@@ -278,8 +278,8 @@ int sock_l4(const struct ctx *c, int af, uint8_t proto,
 		if (bind_addr) {
 			addr6.sin6_addr = *(struct in6_addr *)bind_addr;
 
-			if (!memcmp(bind_addr, &c->addr6_ll,
-			    sizeof(c->addr6_ll)))
+			if (!memcmp(bind_addr, &c->ip6.addr_ll,
+			    sizeof(c->ip6.addr_ll)))
 				addr6.sin6_scope_id = c->ifi6;
 		} else {
 			addr6.sin6_addr = in6addr_any;
-- 
@@ -278,8 +278,8 @@ int sock_l4(const struct ctx *c, int af, uint8_t proto,
 		if (bind_addr) {
 			addr6.sin6_addr = *(struct in6_addr *)bind_addr;
 
-			if (!memcmp(bind_addr, &c->addr6_ll,
-			    sizeof(c->addr6_ll)))
+			if (!memcmp(bind_addr, &c->ip6.addr_ll,
+			    sizeof(c->ip6.addr_ll)))
 				addr6.sin6_scope_id = c->ifi6;
 		} else {
 			addr6.sin6_addr = in6addr_any;
-- 
2.37.1


      parent reply	other threads:[~2022-07-22  5:31 UTC|newest]

Thread overview: 11+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2022-07-22  5:31 [PATCH 0/7] Improved selection of external interface and IP configuration David Gibson
2022-07-22  5:31 ` [PATCH 1/7] Allow different external interfaces for IPv4 and IPv6 connectivity David Gibson
2022-07-22  5:31 ` [PATCH 2/7] Separately locate external interfaces for IPv4 and IPv6 David Gibson
2022-08-01 10:23   ` Stefano Brivio
2022-07-22  5:31 ` [PATCH 3/7] Initialize host side MAC when in IPv6 only mode David Gibson
2022-07-22  5:31 ` [PATCH 4/7] Move passt mac_guest init to be more symmetric with pasta David Gibson
2022-07-22  5:31 ` [PATCH 5/7] Clarify semantics of c->v4 and c->v6 variables David Gibson
2022-08-01 10:24   ` Stefano Brivio
2022-07-22  5:31 ` [PATCH 6/7] Separate IPv4 and IPv6 configuration David Gibson
2022-08-01 10:24   ` Stefano Brivio
2022-07-22  5:31 ` David Gibson [this message]

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20220722053118.1067459-8-david@gibson.dropbear.id.au \
    --to=david@gibson.dropbear.id.au \
    --cc=passt-dev@passt.top \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
Code repositories for project(s) associated with this public inbox

	https://passt.top/passt

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for IMAP folder(s).