Make substructures for IPv4 and IPv6 specific context information

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@gibson.dropbear.id.au>
This commit is contained in:
David Gibson 2022-07-22 15:31:18 +10:00 committed by Stefano Brivio
parent 5e12d23acb
commit 16f5586bb8
12 changed files with 232 additions and 212 deletions

2
arp.c
View file

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

184
conf.c
View file

@ -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,10 +1069,10 @@ 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;
bool v4_only = false, v6_only = false;
struct in6_addr *dns6 = c->ip6.dns;
struct fqdn *dnss = c->dns_search;
struct in6_addr *dns6 = c->dns6;
uint32_t *dns4 = c->ip4.dns;
int name, ret, mask, b, i;
uint32_t *dns4 = c->dns4;
unsigned int ifi = 0;
if (c->mode == MODE_PASTA)
@ -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);

22
dhcp.c
View file

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

View file

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

16
ndp.c
View file

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

View file

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

68
passt.h
View file

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

10
pasta.c
View file

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

22
tap.c
View file

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

34
tcp.c
View file

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

62
udp.c
View file

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

4
util.c
View file

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