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; return 1;
/* Don't resolve our own address, either. */ /* 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; return 1;
ah->ar_op = htons(ARPOP_REPLY); ah->ar_op = htons(ARPOP_REPLY);

184
conf.c
View file

@ -404,9 +404,9 @@ overlap:
static void get_dns(struct ctx *c) static void get_dns(struct ctx *c)
{ {
int dns4_set, dns6_set, dnss_set, dns_set, fd; 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; struct fqdn *s = c->dns_search;
uint32_t *dns4 = &c->dns4[0]; uint32_t *dns4 = &c->ip4.dns[0];
struct lineread resolvconf; struct lineread resolvconf;
int line_len; int line_len;
char *line, *p, *end; char *line, *p, *end;
@ -434,7 +434,7 @@ static void get_dns(struct ctx *c)
*end = 0; *end = 0;
if (!dns4_set && 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)) { inet_pton(AF_INET, p + 1, dns4)) {
/* We can only access local addresses via the gw redirect */ /* We can only access local addresses via the gw redirect */
if (ntohl(*dns4) >> IN_CLASSA_NSHIFT == IN_LOOPBACKNET) { if (ntohl(*dns4) >> IN_CLASSA_NSHIFT == IN_LOOPBACKNET) {
@ -442,14 +442,14 @@ static void get_dns(struct ctx *c)
*dns4 = 0; *dns4 = 0;
continue; continue;
} }
*dns4 = c->gw4; *dns4 = c->ip4.gw;
} }
dns4++; dns4++;
*dns4 = 0; *dns4 = 0;
} }
if (!dns6_set && 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)) { inet_pton(AF_INET6, p + 1, dns6)) {
/* We can only access local addresses via the gw redirect */ /* We can only access local addresses via the gw redirect */
if (IN6_IS_ADDR_LOOPBACK(dns6)) { if (IN6_IS_ADDR_LOOPBACK(dns6)) {
@ -457,7 +457,7 @@ static void get_dns(struct ctx *c)
memset(dns6, 0, sizeof(*dns6)); memset(dns6, 0, sizeof(*dns6));
continue; continue;
} }
memcpy(dns6, &c->gw6, sizeof(*dns6)); memcpy(dns6, &c->ip6.gw, sizeof(*dns6));
} }
dns6++; dns6++;
memset(dns6, 0, sizeof(*dns6)); memset(dns6, 0, sizeof(*dns6));
@ -485,7 +485,7 @@ static void get_dns(struct ctx *c)
close(fd); close(fd);
out: 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"); 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 * conf_ip4() - Verify or detect IPv4 support, get relevant addresses
* @c: Execution context
* @ifi: Host interface to attempt (0 to determine one) * @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. * 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) if (!ifi)
ifi = nl_get_ext_if(AF_INET); ifi = nl_get_ext_if(AF_INET);
@ -627,33 +629,33 @@ static unsigned int conf_ip4(struct ctx *c, unsigned int ifi)
return 0; return 0;
} }
if (!c->gw4) if (!ip4->gw)
nl_route(0, ifi, AF_INET, &c->gw4); nl_route(0, ifi, AF_INET, &ip4->gw);
if (!c->addr4) { if (!ip4->addr) {
int mask_len = 0; int mask_len = 0;
nl_addr(0, ifi, AF_INET, &c->addr4, &mask_len, NULL); nl_addr(0, ifi, AF_INET, &ip4->addr, &mask_len, NULL);
c->mask4 = htonl(0xffffffff << (32 - mask_len)); ip4->mask = htonl(0xffffffff << (32 - mask_len));
} }
if (!c->mask4) { if (!ip4->mask) {
if (IN_CLASSA(ntohl(c->addr4))) if (IN_CLASSA(ntohl(ip4->addr)))
c->mask4 = htonl(IN_CLASSA_NET); ip4->mask = htonl(IN_CLASSA_NET);
else if (IN_CLASSB(ntohl(c->addr4))) else if (IN_CLASSB(ntohl(ip4->addr)))
c->mask4 = htonl(IN_CLASSB_NET); ip4->mask = htonl(IN_CLASSB_NET);
else if (IN_CLASSC(ntohl(c->addr4))) else if (IN_CLASSC(ntohl(ip4->addr)))
c->mask4 = htonl(IN_CLASSC_NET); ip4->mask = htonl(IN_CLASSC_NET);
else 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)) if (MAC_IS_ZERO(mac))
nl_link(0, ifi, c->mac, 0, 0); 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 0;
return ifi; 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 * conf_ip6() - Verify or detect IPv6 support, get relevant addresses
* @c: Execution context
* @ifi: Host interface to attempt (0 to determine one) * @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. * 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; int prefix_len = 0;
@ -678,23 +682,23 @@ static unsigned int conf_ip6(struct ctx *c, unsigned int ifi)
return 0; return 0;
} }
if (IN6_IS_ADDR_UNSPECIFIED(&c->gw6)) if (IN6_IS_ADDR_UNSPECIFIED(&ip6->gw))
nl_route(0, ifi, AF_INET6, &c->gw6); nl_route(0, ifi, AF_INET6, &ip6->gw);
nl_addr(0, ifi, AF_INET6, nl_addr(0, ifi, AF_INET6,
IN6_IS_ADDR_UNSPECIFIED(&c->addr6) ? &c->addr6 : NULL, IN6_IS_ADDR_UNSPECIFIED(&ip6->addr) ? &ip6->addr : NULL,
&prefix_len, &c->addr6_ll); &prefix_len, &ip6->addr_ll);
memcpy(&c->addr6_seen, &c->addr6, sizeof(c->addr6)); memcpy(&ip6->addr_seen, &ip6->addr, sizeof(ip6->addr));
memcpy(&c->addr6_ll_seen, &c->addr6_ll, sizeof(c->addr6_ll)); memcpy(&ip6->addr_ll_seen, &ip6->addr_ll, sizeof(ip6->addr_ll));
if (MAC_IS_ZERO(c->mac)) if (MAC_IS_ZERO(mac))
nl_link(0, ifi, c->mac, 0, 0); nl_link(0, ifi, mac, 0, 0);
if (IN6_IS_ADDR_UNSPECIFIED(&c->gw6) || if (IN6_IS_ADDR_UNSPECIFIED(&ip6->gw) ||
IN6_IS_ADDR_UNSPECIFIED(&c->addr6) || IN6_IS_ADDR_UNSPECIFIED(&ip6->addr) ||
IN6_IS_ADDR_UNSPECIFIED(&c->addr6_ll) || IN6_IS_ADDR_UNSPECIFIED(&ip6->addr_ll) ||
MAC_IS_ZERO(c->mac)) MAC_IS_ZERO(mac))
return 0; return 0;
return ifi; return ifi;
@ -899,17 +903,17 @@ static void conf_print(const struct ctx *c)
if (!c->no_dhcp) { if (!c->no_dhcp) {
info("DHCP:"); info("DHCP:");
info(" assign: %s", 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", 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", 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) if (!i)
info("DNS:"); 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); info(" %s", buf4);
} }
@ -933,17 +937,17 @@ static void conf_print(const struct ctx *c)
goto dns6; goto dns6;
info(" assign: %s", 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", 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", 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: 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) if (!i)
info("DNS:"); 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); 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 tcp_tap = 0, tcp_init = 0;
enum conf_port_type udp_tap = 0, udp_init = 0; enum conf_port_type udp_tap = 0, udp_init = 0;
bool v4_only = false, v6_only = false; bool v4_only = false, v6_only = false;
struct in6_addr *dns6 = c->ip6.dns;
struct fqdn *dnss = c->dns_search; struct fqdn *dnss = c->dns_search;
struct in6_addr *dns6 = c->dns6; uint32_t *dns4 = c->ip4.dns;
int name, ret, mask, b, i; int name, ret, mask, b, i;
uint32_t *dns4 = c->dns4;
unsigned int ifi = 0; unsigned int ifi = 0;
if (c->mode == MODE_PASTA) if (c->mode == MODE_PASTA)
@ -1167,17 +1171,17 @@ void conf(struct ctx *c, int argc, char **argv)
c->no_dhcp_dns_search = 1; c->no_dhcp_dns_search = 1;
break; break;
case 9: case 9:
if (IN6_IS_ADDR_UNSPECIFIED(&c->dns6_fwd) && if (IN6_IS_ADDR_UNSPECIFIED(&c->ip6.dns_fwd) &&
inet_pton(AF_INET6, optarg, &c->dns6_fwd) && inet_pton(AF_INET6, optarg, &c->ip6.dns_fwd) &&
!IN6_IS_ADDR_UNSPECIFIED(&c->dns6_fwd) && !IN6_IS_ADDR_UNSPECIFIED(&c->ip6.dns_fwd) &&
!IN6_IS_ADDR_LOOPBACK(&c->dns6_fwd)) !IN6_IS_ADDR_LOOPBACK(&c->ip6.dns_fwd))
break; break;
if (c->dns4_fwd == INADDR_ANY && if (c->ip4.dns_fwd == INADDR_ANY &&
inet_pton(AF_INET, optarg, &c->dns4_fwd) && inet_pton(AF_INET, optarg, &c->ip4.dns_fwd) &&
c->dns4_fwd != INADDR_ANY && c->ip4.dns_fwd != INADDR_ANY &&
c->dns4_fwd != INADDR_BROADCAST && c->ip4.dns_fwd != INADDR_BROADCAST &&
c->dns4_fwd != INADDR_LOOPBACK) c->ip4.dns_fwd != INADDR_LOOPBACK)
break; break;
err("Invalid DNS forwarding address: %s", optarg); err("Invalid DNS forwarding address: %s", optarg);
@ -1334,34 +1338,34 @@ void conf(struct ctx *c, int argc, char **argv)
} }
break; break;
case 'a': case 'a':
if (IN6_IS_ADDR_UNSPECIFIED(&c->addr6) && if (IN6_IS_ADDR_UNSPECIFIED(&c->ip6.addr) &&
inet_pton(AF_INET6, optarg, &c->addr6) && inet_pton(AF_INET6, optarg, &c->ip6.addr) &&
!IN6_IS_ADDR_UNSPECIFIED(&c->addr6) && !IN6_IS_ADDR_UNSPECIFIED(&c->ip6.addr) &&
!IN6_IS_ADDR_LOOPBACK(&c->addr6) && !IN6_IS_ADDR_LOOPBACK(&c->ip6.addr) &&
!IN6_IS_ADDR_V4MAPPED(&c->addr6) && !IN6_IS_ADDR_V4MAPPED(&c->ip6.addr) &&
!IN6_IS_ADDR_V4COMPAT(&c->addr6) && !IN6_IS_ADDR_V4COMPAT(&c->ip6.addr) &&
!IN6_IS_ADDR_MULTICAST(&c->addr6)) !IN6_IS_ADDR_MULTICAST(&c->ip6.addr))
break; break;
if (c->addr4 == INADDR_ANY && if (c->ip4.addr == INADDR_ANY &&
inet_pton(AF_INET, optarg, &c->addr4) && inet_pton(AF_INET, optarg, &c->ip4.addr) &&
c->addr4 != INADDR_ANY && c->ip4.addr != INADDR_ANY &&
c->addr4 != INADDR_BROADCAST && c->ip4.addr != INADDR_BROADCAST &&
c->addr4 != INADDR_LOOPBACK && c->ip4.addr != INADDR_LOOPBACK &&
!IN_MULTICAST(c->addr4)) !IN_MULTICAST(c->ip4.addr))
break; break;
err("Invalid address: %s", optarg); err("Invalid address: %s", optarg);
usage(argv[0]); usage(argv[0]);
break; break;
case 'n': case 'n':
if (inet_pton(AF_INET, optarg, &c->mask4)) if (inet_pton(AF_INET, optarg, &c->ip4.mask))
break; break;
errno = 0; errno = 0;
mask = strtol(optarg, NULL, 0); mask = strtol(optarg, NULL, 0);
if (mask > 0 && mask <= 32 && !errno) { if (mask > 0 && mask <= 32 && !errno) {
c->mask4 = htonl(0xffffffff << (32 - mask)); c->ip4.mask = htonl(0xffffffff << (32 - mask));
break; break;
} }
@ -1380,17 +1384,17 @@ void conf(struct ctx *c, int argc, char **argv)
} }
break; break;
case 'g': case 'g':
if (IN6_IS_ADDR_UNSPECIFIED(&c->gw6) && if (IN6_IS_ADDR_UNSPECIFIED(&c->ip6.gw) &&
inet_pton(AF_INET6, optarg, &c->gw6) && inet_pton(AF_INET6, optarg, &c->ip6.gw) &&
!IN6_IS_ADDR_UNSPECIFIED(&c->gw6) && !IN6_IS_ADDR_UNSPECIFIED(&c->ip6.gw) &&
!IN6_IS_ADDR_LOOPBACK(&c->gw6)) !IN6_IS_ADDR_LOOPBACK(&c->ip6.gw))
break; break;
if (c->gw4 == INADDR_ANY && if (c->ip4.gw == INADDR_ANY &&
inet_pton(AF_INET, optarg, &c->gw4) && inet_pton(AF_INET, optarg, &c->ip4.gw) &&
c->gw4 != INADDR_ANY && c->ip4.gw != INADDR_ANY &&
c->gw4 != INADDR_BROADCAST && c->ip4.gw != INADDR_BROADCAST &&
c->gw4 != INADDR_LOOPBACK) c->ip4.gw != INADDR_LOOPBACK)
break; break;
err("Invalid gateway address: %s", optarg); err("Invalid gateway address: %s", optarg);
@ -1410,7 +1414,7 @@ void conf(struct ctx *c, int argc, char **argv)
break; break;
case 'D': case 'D':
if (c->no_dns || 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"); err("Empty and non-empty DNS options given");
usage(argv[0]); usage(argv[0]);
} }
@ -1420,13 +1424,13 @@ void conf(struct ctx *c, int argc, char **argv)
break; 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)) { inet_pton(AF_INET, optarg, dns4)) {
dns4++; dns4++;
break; 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)) { inet_pton(AF_INET6, optarg, dns6)) {
dns6++; dns6++;
break; break;
@ -1511,9 +1515,9 @@ void conf(struct ctx *c, int argc, char **argv)
usage(argv[0]); usage(argv[0]);
} }
if (!v6_only) if (!v6_only)
c->ifi4 = conf_ip4(c, ifi); c->ifi4 = conf_ip4(ifi, &c->ip4, c->mac);
if (!v4_only) if (!v4_only)
c->ifi6 = conf_ip6(c, ifi); c->ifi6 = conf_ip6(ifi, &c->ip6, c->mac);
if (!c->ifi4 && !c->ifi6) { if (!c->ifi4 && !c->ifi6) {
err("External interface not usable"); err("External interface not usable");
exit(EXIT_FAILURE); 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[0], m->chaddr[1], m->chaddr[2],
m->chaddr[3], m->chaddr[4], m->chaddr[5]); m->chaddr[3], m->chaddr[4], m->chaddr[5]);
m->yiaddr = c->addr4; m->yiaddr = c->ip4.addr;
memcpy(opts[1].s, &c->mask4, sizeof(c->mask4)); memcpy(opts[1].s, &c->ip4.mask, sizeof(c->ip4.mask));
memcpy(opts[3].s, &c->gw4, sizeof(c->gw4)); memcpy(opts[3].s, &c->ip4.gw, sizeof(c->ip4.gw));
memcpy(opts[54].s, &c->gw4, sizeof(c->gw4)); memcpy(opts[54].s, &c->ip4.gw, sizeof(c->ip4.gw));
/* If the gateway is not on the assigned subnet, send an option 121 /* If the gateway is not on the assigned subnet, send an option 121
* (Classless Static Routing) adding a dummy route to it. * (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 */ /* a.b.c.d/32:0.0.0.0, 0:a.b.c.d */
opts[121].slen = 14; opts[121].slen = 14;
opts[121].s[0] = 32; opts[121].s[0] = 32;
memcpy(opts[121].s + 1, &c->gw4, sizeof(c->gw4)); memcpy(opts[121].s + 1, &c->ip4.gw, sizeof(c->ip4.gw));
memcpy(opts[121].s + 10, &c->gw4, sizeof(c->gw4)); memcpy(opts[121].s + 10, &c->ip4.gw, sizeof(c->ip4.gw));
} }
if (c->mtu != -1) { 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; opts[26].s[1] = c->mtu % 256;
} }
for (i = 0, opts[6].slen = 0; !c->no_dhcp_dns && c->dns4[i]; i++) { for (i = 0, opts[6].slen = 0; !c->no_dhcp_dns && c->ip4.dns[i]; i++) {
((uint32_t *)opts[6].s)[i] = c->dns4[i]; ((uint32_t *)opts[6].s)[i] = c->ip4.dns[i];
opts[6].slen += sizeof(uint32_t); opts[6].slen += sizeof(uint32_t);
} }
@ -368,8 +368,8 @@ int dhcp(const struct ctx *c, const struct pool *p)
uh->dest = htons(68); uh->dest = htons(68);
iph->tot_len = htons(len += sizeof(*iph)); iph->tot_len = htons(len += sizeof(*iph));
iph->daddr = c->addr4; iph->daddr = c->ip4.addr;
iph->saddr = c->gw4; iph->saddr = c->ip4.gw;
iph->check = 0; iph->check = 0;
iph->check = csum_unaligned(iph, (intptr_t)(iph->ihl * 4), 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) if (c->no_dhcp_dns)
goto search; 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) { if (!i) {
srv = (struct opt_dns_servers *)(buf + offset); srv = (struct opt_dns_servers *)(buf + offset);
offset += sizeof(struct opt_hdr); 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; 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]); srv->hdr.l += sizeof(srv->addr[i]);
offset += 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)) if (mlen + sizeof(*uh) != ntohs(uh->len) || mlen < sizeof(*mh))
return -1; return -1;
c->addr6_ll_seen = *saddr; c->ip6.addr_ll_seen = *saddr;
if (IN6_IS_ADDR_LINKLOCAL(&c->gw6)) if (IN6_IS_ADDR_LINKLOCAL(&c->ip6.gw))
src = &c->gw6; src = &c->ip6.gw;
else else
src = &c->addr6_ll; src = &c->ip6.addr_ll;
mh = packet_get(p, 0, sizeof(*uh), sizeof(*mh), NULL); mh = packet_get(p, 0, sizeof(*uh), sizeof(*mh), NULL);
if (!mh) if (!mh)
@ -508,7 +508,7 @@ int dhcpv6(struct ctx *c, const struct pool *p,
if (mh->type == TYPE_CONFIRM && server_id) if (mh->type == TYPE_CONFIRM && server_id)
return -1; 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," info("DHCPv6: received CONFIRM with inappropriate IA,"
" sending NotOnLink status in REPLY"); " sending NotOnLink status in REPLY");
@ -580,7 +580,7 @@ int dhcpv6(struct ctx *c, const struct pool *p,
resp.hdr.xid = mh->xid; resp.hdr.xid = mh->xid;
tap_ip_send(c, src, IPPROTO_UDP, (char *)&resp, n, 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; 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.server_id.duid_lladdr, c->mac, sizeof(c->mac));
memcpy(resp_not_on_link.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; p += 4;
*(uint32_t *)p = htonl(3600); /* preferred lifetime */ *(uint32_t *)p = htonl(3600); /* preferred lifetime */
p += 8; p += 8;
memcpy(p, &c->addr6, 8); /* prefix */ memcpy(p, &c->ip6.addr, 8); /* prefix */
p += 16; p += 16;
if (c->mtu != -1) { if (c->mtu != -1) {
@ -121,7 +121,7 @@ int ndp(struct ctx *c, const struct icmp6hdr *ih,
if (c->no_dhcp_dns) if (c->no_dhcp_dns)
goto dns_done; 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) { if (n) {
*p++ = 25; /* RDNSS */ *p++ = 25; /* RDNSS */
*p++ = 1 + 2 * n; /* length */ *p++ = 1 + 2 * n; /* length */
@ -130,7 +130,7 @@ int ndp(struct ctx *c, const struct icmp6hdr *ih,
p += 4; p += 4;
for (i = 0; i < n; i++) { for (i = 0; i < n; i++) {
memcpy(p, &c->dns6[i], 16); /* address */ memcpy(p, &c->ip6.dns[i], 16); /* address */
p += 16; p += 16;
} }
@ -177,15 +177,15 @@ dns_done:
len = (uintptr_t)p - (uintptr_t)ihr - sizeof(*ihr); len = (uintptr_t)p - (uintptr_t)ihr - sizeof(*ihr);
if (IN6_IS_ADDR_LINKLOCAL(saddr)) if (IN6_IS_ADDR_LINKLOCAL(saddr))
c->addr6_ll_seen = *saddr; c->ip6.addr_ll_seen = *saddr;
else else
c->addr6_seen = *saddr; c->ip6.addr_seen = *saddr;
ip6hr->daddr = *saddr; ip6hr->daddr = *saddr;
if (IN6_IS_ADDR_LINKLOCAL(&c->gw6)) if (IN6_IS_ADDR_LINKLOCAL(&c->ip6.gw))
ip6hr->saddr = c->gw6; ip6hr->saddr = c->ip6.gw;
else else
ip6hr->saddr = c->addr6_ll; ip6hr->saddr = c->ip6.addr_ll;
ip6hr->payload_len = htons(sizeof(*ihr) + len); ip6hr->payload_len = htons(sizeof(*ihr) + len);
ip6hr->hop_limit = IPPROTO_ICMPV6; 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))) if ((!c.no_udp && udp_init(&c)) || (!c.no_tcp && tcp_init(&c)))
exit(EXIT_FAILURE); 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) if (c.ifi4 && !c.no_dhcp)
dhcp_init(); dhcp_init();

68
passt.h
View file

@ -94,6 +94,44 @@ enum passt_modes {
MODE_PASTA, 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 * struct ctx - Execution context
* @mode: Operation mode, qemu/UNIX domain socket or namespace/tap * @mode: Operation mode, qemu/UNIX domain socket or namespace/tap
@ -122,21 +160,10 @@ enum passt_modes {
* @mac: Host MAC address * @mac: Host MAC address
* @mac_guest: MAC address of guest or namespace, seen or configured * @mac_guest: MAC address of guest or namespace, seen or configured
* @ifi4: Index of routable interface for IPv4, 0 if IPv4 disabled * @ifi4: Index of routable interface for IPv4, 0 if IPv4 disabled
* @addr4: IPv4 address for external, routable interface * @ip: IPv4 configuration
* @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
* @dns_search: DNS search list * @dns_search: DNS search list
* @ifi6: Index of routable interface for IPv6, 0 if IPv6 disabled * @ifi6: Index of routable interface for IPv6, 0 if IPv6 disabled
* @addr6: IPv6 address for external, routable interface * @ip6: IPv6 configuration
* @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
* @pasta_ifn: Name of namespace interface for pasta * @pasta_ifn: Name of namespace interface for pasta
* @pasta_ifn: Index of namespace interface for pasta * @pasta_ifn: Index of namespace interface for pasta
* @pasta_conf_ns: Configure namespace interface after creating it * @pasta_conf_ns: Configure namespace interface after creating it
@ -192,23 +219,12 @@ struct ctx {
unsigned char mac_guest[ETH_ALEN]; unsigned char mac_guest[ETH_ALEN];
unsigned int ifi4; unsigned int ifi4;
uint32_t addr4; struct ip4_ctx ip4;
uint32_t addr4_seen;
uint32_t mask4;
uint32_t gw4;
uint32_t dns4[MAXNS + 1];
uint32_t dns4_fwd;
struct fqdn dns_search[MAXDNSRCH]; struct fqdn dns_search[MAXDNSRCH];
unsigned int ifi6; unsigned int ifi6;
struct in6_addr addr6; struct ip6_ctx ip6;
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;
char pasta_ifn[IF_NAMESIZE]; char pasta_ifn[IF_NAMESIZE];
unsigned int pasta_ifi; 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); nl_link(1, c->pasta_ifi, c->mac_guest, 1, c->mtu);
if (c->ifi4) { if (c->ifi4) {
prefix_len = __builtin_popcount(c->mask4); prefix_len = __builtin_popcount(c->ip4.mask);
nl_addr(1, c->pasta_ifi, AF_INET, &c->addr4, nl_addr(1, c->pasta_ifi, AF_INET, &c->ip4.addr,
&prefix_len, NULL); &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) { if (c->ifi6) {
prefix_len = 64; 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); &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 { } else {
nl_link(1, c->pasta_ifi, c->mac_guest, 0, 0); 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->frag_off = 0;
iph->ttl = 255; iph->ttl = 255;
iph->protocol = proto; iph->protocol = proto;
iph->daddr = c->addr4_seen; iph->daddr = c->ip4.addr_seen;
memcpy(&iph->saddr, &src->s6_addr[12], 4); memcpy(&iph->saddr, &src->s6_addr[12], 4);
iph->check = 0; 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; ip6h->saddr = *src;
if (IN6_IS_ADDR_LINKLOCAL(src)) if (IN6_IS_ADDR_LINKLOCAL(src))
ip6h->daddr = c->addr6_ll_seen; ip6h->daddr = c->ip6.addr_ll_seen;
else else
ip6h->daddr = c->addr6_seen; ip6h->daddr = c->ip6.addr_seen;
memcpy(data, in, len); memcpy(data, in, len);
@ -354,9 +354,9 @@ resume:
l4_len = l3_len - hlen; l4_len = l3_len - hlen;
if (iph->saddr && c->addr4_seen != iph->saddr) { if (iph->saddr && c->ip4.addr_seen != iph->saddr) {
c->addr4_seen = iph->saddr; c->ip4.addr_seen = iph->saddr;
proto_update_l2_buf(NULL, NULL, &c->addr4_seen); proto_update_l2_buf(NULL, NULL, &c->ip4.addr_seen);
} }
l4h = packet_get(in, i, sizeof(*eh) + hlen, l4_len, NULL); l4h = packet_get(in, i, sizeof(*eh) + hlen, l4_len, NULL);
@ -504,13 +504,13 @@ resume:
continue; continue;
if (IN6_IS_ADDR_LINKLOCAL(saddr)) { 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)) { if (IN6_IS_ADDR_UNSPECIFIED(&c->ip6.addr_seen)) {
c->addr6_seen = *saddr; c->ip6.addr_seen = *saddr;
} }
} else { } else {
c->addr6_seen = *saddr; c->ip6.addr_seen = *saddr;
} }
if (proto == IPPROTO_ICMPV6) { if (proto == IPPROTO_ICMPV6) {
@ -545,7 +545,7 @@ resume:
continue; continue;
} }
*saddr = c->addr6; *saddr = c->ip6.addr;
if (proto != IPPROTO_TCP && proto != IPPROTO_UDP) { if (proto != IPPROTO_TCP && proto != IPPROTO_UDP) {
tap_packet_debug(NULL, ip6h, NULL, proto, NULL, 1); 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.payload_len = htons(plen + sizeof(struct tcphdr));
b->ip6h.saddr = conn->a.a6; b->ip6h.saddr = conn->a.a6;
if (IN6_IS_ADDR_LINKLOCAL(&b->ip6h.saddr)) if (IN6_IS_ADDR_LINKLOCAL(&b->ip6h.saddr))
b->ip6h.daddr = c->addr6_ll_seen; b->ip6h.daddr = c->ip6.addr_ll_seen;
else else
b->ip6h.daddr = c->addr6_seen; b->ip6h.daddr = c->ip6.addr_seen;
memset(b->ip6h.flow_lbl, 0, 3); memset(b->ip6h.flow_lbl, 0, 3);
@ -1723,7 +1723,7 @@ do { \
ip_len = plen + sizeof(struct iphdr) + sizeof(struct tcphdr); ip_len = plen + sizeof(struct iphdr) + sizeof(struct tcphdr);
b->iph.tot_len = htons(ip_len); b->iph.tot_len = htons(ip_len);
b->iph.saddr = conn->a.a4.a.s_addr; b->iph.saddr = conn->a.a4.a.s_addr;
b->iph.daddr = c->addr4_seen; b->iph.daddr = c->ip4.addr_seen;
if (check) if (check)
b->iph.check = *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 = { } __attribute__((__packed__)) in = {
.src = *(struct in_addr *)addr, .src = *(struct in_addr *)addr,
.srcport = srcport, .srcport = srcport,
.dst = { c->addr4 }, .dst = { c->ip4.addr },
.dstport = dstport, .dstport = dstport,
}; };
@ -2083,7 +2083,7 @@ static uint32_t tcp_seq_init(const struct ctx *c, int af, const void *addr,
} __attribute__((__packed__)) in = { } __attribute__((__packed__)) in = {
.src = *(struct in6_addr *)addr, .src = *(struct in6_addr *)addr,
.srcport = srcport, .srcport = srcport,
.dst = c->addr6, .dst = c->ip6.addr,
.dstport = dstport, .dstport = dstport,
}; };
@ -2197,16 +2197,16 @@ static void tcp_conn_from_tap(struct ctx *c, int af, const void *addr,
return; return;
if (!c->no_map_gw) { 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); 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; addr6.sin6_addr = in6addr_loopback;
} }
if (af == AF_INET6 && IN6_IS_ADDR_LINKLOCAL(&addr6.sin6_addr)) { if (af == AF_INET6 && IN6_IS_ADDR_LINKLOCAL(&addr6.sin6_addr)) {
struct sockaddr_in6 addr6_ll = { struct sockaddr_in6 addr6_ll = {
.sin6_family = AF_INET6, .sin6_family = AF_INET6,
.sin6_addr = c->addr6_ll, .sin6_addr = c->ip6.addr_ll,
.sin6_scope_id = c->ifi6, .sin6_scope_id = c->ifi6,
}; };
if (bind(s, (struct sockaddr *)&addr6_ll, sizeof(addr6_ll))) { 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)); memcpy(&sa6, &sa, sizeof(sa6));
if (IN6_IS_ADDR_LOOPBACK(&sa6.sin6_addr) || 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->ip6.addr_seen) ||
IN6_ARE_ADDR_EQUAL(&sa6.sin6_addr, &c->addr6)) { IN6_ARE_ADDR_EQUAL(&sa6.sin6_addr, &c->ip6.addr)) {
struct in6_addr *src; struct in6_addr *src;
if (IN6_IS_ADDR_LINKLOCAL(&c->gw6)) if (IN6_IS_ADDR_LINKLOCAL(&c->ip6.gw))
src = &c->gw6; src = &c->ip6.gw;
else else
src = &c->addr6_ll; src = &c->ip6.addr_ll;
memcpy(&sa6.sin6_addr, src, sizeof(*src)); 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)); memset(&conn->a.a4.one, 0xff, sizeof(conn->a.a4.one));
if (s_addr >> IN_CLASSA_NSHIFT == IN_LOOPBACKNET || if (s_addr >> IN_CLASSA_NSHIFT == IN_LOOPBACKNET ||
s_addr == INADDR_ANY || htonl(s_addr) == c->addr4_seen) s_addr == INADDR_ANY || htonl(s_addr) == c->ip4.addr_seen)
s_addr = ntohl(c->gw4); s_addr = ntohl(c->ip4.gw);
s_addr = htonl(s_addr); s_addr = htonl(s_addr);
memcpy(&conn->a.a4.a, &s_addr, sizeof(conn->a.a4.a)); 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 (af == AF_INET || af == AF_UNSPEC) {
if (!addr && c->mode == MODE_PASTA) if (!addr && c->mode == MODE_PASTA)
bind_addr = &c->addr4; bind_addr = &c->ip4.addr;
else else
bind_addr = addr; 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 (af == AF_INET6 || af == AF_UNSPEC) {
if (!addr && c->mode == MODE_PASTA) if (!addr && c->mode == MODE_PASTA)
bind_addr = &c->addr6; bind_addr = &c->ip6.addr;
else else
bind_addr = addr; 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); src_port = htons(b->s_in.sin_port);
if (src >> IN_CLASSA_NSHIFT == IN_LOOPBACKNET || if (src >> IN_CLASSA_NSHIFT == IN_LOOPBACKNET ||
src == INADDR_ANY || src == ntohl(c->addr4_seen)) { src == INADDR_ANY || src == ntohl(c->ip4.addr_seen)) {
b->iph.saddr = c->gw4; b->iph.saddr = c->ip4.gw;
udp_tap_map[V4][src_port].ts = now->tv_sec; udp_tap_map[V4][src_port].ts = now->tv_sec;
udp_tap_map[V4][src_port].flags |= PORT_LOCAL; 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; udp_tap_map[V4][src_port].flags &= ~PORT_LOOPBACK;
else else
udp_tap_map[V4][src_port].flags |= PORT_LOOPBACK; udp_tap_map[V4][src_port].flags |= PORT_LOOPBACK;
bitmap_set(udp_act[V4][UDP_ACT_TAP], src_port); bitmap_set(udp_act[V4][UDP_ACT_TAP], src_port);
} else if (c->dns4_fwd && } else if (c->ip4.dns_fwd &&
src == ntohl(c->dns4[0]) && ntohs(src_port) == 53) { src == ntohl(c->ip4.dns[0]) && ntohs(src_port) == 53) {
b->iph.saddr = c->dns4_fwd; b->iph.saddr = c->ip4.dns_fwd;
} else { } else {
b->iph.saddr = b->s_in.sin_addr.s_addr; 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)); b->ip6h.payload_len = htons(udp6_l2_mh_sock[n].msg_len + sizeof(b->uh));
if (IN6_IS_ADDR_LINKLOCAL(src)) { 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; b->ip6h.saddr = b->s_in6.sin6_addr;
} else if (IN6_IS_ADDR_LOOPBACK(src) || } else if (IN6_IS_ADDR_LOOPBACK(src) ||
IN6_ARE_ADDR_EQUAL(src, &c->addr6_seen) || IN6_ARE_ADDR_EQUAL(src, &c->ip6.addr_seen) ||
IN6_ARE_ADDR_EQUAL(src, &c->addr6)) { IN6_ARE_ADDR_EQUAL(src, &c->ip6.addr)) {
b->ip6h.daddr = c->addr6_ll_seen; b->ip6h.daddr = c->ip6.addr_ll_seen;
if (IN6_IS_ADDR_LINKLOCAL(&c->gw6)) if (IN6_IS_ADDR_LINKLOCAL(&c->ip6.gw))
b->ip6h.saddr = c->gw6; b->ip6h.saddr = c->ip6.gw;
else 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].ts = now->tv_sec;
udp_tap_map[V6][src_port].flags |= PORT_LOCAL; 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 else
udp_tap_map[V6][src_port].flags &= ~PORT_LOOPBACK; 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; udp_tap_map[V6][src_port].flags |= PORT_GUA;
else else
udp_tap_map[V6][src_port].flags &= ~PORT_GUA; udp_tap_map[V6][src_port].flags &= ~PORT_GUA;
bitmap_set(udp_act[V6][UDP_ACT_TAP], src_port); bitmap_set(udp_act[V6][UDP_ACT_TAP], src_port);
} else if (!IN6_IS_ADDR_UNSPECIFIED(&c->dns6_fwd) && } else if (!IN6_IS_ADDR_UNSPECIFIED(&c->ip6.dns_fwd) &&
IN6_ARE_ADDR_EQUAL(src, &c->dns6_fwd) && src_port == 53) { IN6_ARE_ADDR_EQUAL(src, &c->ip6.dns_fwd) && src_port == 53) {
b->ip6h.daddr = c->addr6_seen; b->ip6h.daddr = c->ip6.addr_seen;
b->ip6h.saddr = c->dns6_fwd; b->ip6h.saddr = c->ip6.dns_fwd;
} else { } else {
b->ip6h.daddr = c->addr6_seen; b->ip6h.daddr = c->ip6.addr_seen;
b->ip6h.saddr = b->s_in6.sin6_addr; 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; 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) || if (!(udp_tap_map[V4][dst].flags & PORT_LOCAL) ||
(udp_tap_map[V4][dst].flags & PORT_LOOPBACK)) (udp_tap_map[V4][dst].flags & PORT_LOOPBACK))
s_in.sin_addr.s_addr = htonl(INADDR_LOOPBACK); s_in.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
else else
s_in.sin_addr.s_addr = c->addr4_seen; s_in.sin_addr.s_addr = c->ip4.addr_seen;
} else if (s_in.sin_addr.s_addr == c->dns4_fwd && } else if (s_in.sin_addr.s_addr == c->ip4.dns_fwd &&
ntohs(s_in.sin_port) == 53) { 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 { } else {
s_in6 = (struct sockaddr_in6) { 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; sa = (struct sockaddr *)&s_in6;
sl = sizeof(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) || if (!(udp_tap_map[V6][dst].flags & PORT_LOCAL) ||
(udp_tap_map[V6][dst].flags & PORT_LOOPBACK)) (udp_tap_map[V6][dst].flags & PORT_LOOPBACK))
s_in6.sin6_addr = in6addr_loopback; s_in6.sin6_addr = in6addr_loopback;
else if (udp_tap_map[V6][dst].flags & PORT_GUA) else if (udp_tap_map[V6][dst].flags & PORT_GUA)
s_in6.sin6_addr = c->addr6; s_in6.sin6_addr = c->ip6.addr;
else else
s_in6.sin6_addr = c->addr6_seen; s_in6.sin6_addr = c->ip6.addr_seen;
} else if (IN6_ARE_ADDR_EQUAL(addr, &c->dns6_fwd) && } else if (IN6_ARE_ADDR_EQUAL(addr, &c->ip6.dns_fwd) &&
ntohs(s_in6.sin6_port) == 53) { 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)) { } 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)) { 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 (af == AF_INET || af == AF_UNSPEC) {
if (!addr && c->mode == MODE_PASTA) if (!addr && c->mode == MODE_PASTA)
bind_addr = &c->addr4; bind_addr = &c->ip4.addr;
else else
bind_addr = addr; 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 (af == AF_INET6 || af == AF_UNSPEC) {
if (!addr && c->mode == MODE_PASTA) if (!addr && c->mode == MODE_PASTA)
bind_addr = &c->addr6; bind_addr = &c->ip6.addr;
else else
bind_addr = addr; 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) { if (bind_addr) {
addr6.sin6_addr = *(struct in6_addr *)bind_addr; addr6.sin6_addr = *(struct in6_addr *)bind_addr;
if (!memcmp(bind_addr, &c->addr6_ll, if (!memcmp(bind_addr, &c->ip6.addr_ll,
sizeof(c->addr6_ll))) sizeof(c->ip6.addr_ll)))
addr6.sin6_scope_id = c->ifi6; addr6.sin6_scope_id = c->ifi6;
} else { } else {
addr6.sin6_addr = in6addr_any; addr6.sin6_addr = in6addr_any;