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; -- 2.37.1