aboutgitcodebugslistschat
diff options
context:
space:
mode:
-rw-r--r--conf.c102
-rw-r--r--dhcp.c5
-rw-r--r--dhcpv6.c7
-rw-r--r--ndp.c6
-rw-r--r--passt.163
-rw-r--r--passt.h14
-rwxr-xr-xslirp4netns.sh2
-rw-r--r--udp.c16
8 files changed, 177 insertions, 38 deletions
diff --git a/conf.c b/conf.c
index 279fdfe..21e9bc0 100644
--- a/conf.c
+++ b/conf.c
@@ -279,7 +279,7 @@ static void get_dns(struct ctx *c)
dns4_set = !c->v4 || !!*dns4;
dns6_set = !c->v6 || !IN6_IS_ADDR_UNSPECIFIED(dns6);
dnss_set = !!*s->n || c->no_dns_search;
- dns_set = dns4_set || dns6_set || c->no_dns;
+ dns_set = (dns4_set && dns6_set) || c->no_dns;
if (dns_set && dnss_set)
return;
@@ -583,21 +583,35 @@ static void usage(const char *name)
info( " default: gateway from interface with default route");
info( " -i, --interface NAME Interface for addresses and routes");
info( " default: interface with first default route");
- info( " -D, --dns ADDR Pass IPv4 or IPv6 address as DNS");
+ info( " -D, --dns ADDR Use IPv4 or IPv6 address as DNS");
info( " can be specified multiple times");
info( " a single, empty option disables DNS information");
if (strstr(name, "pasta"))
- info( " default: don't send any addresses");
+ info( " default: don't use any addresses");
else
info( " default: use addresses from /etc/resolv.conf");
info( " -S, --search LIST Space-separated list, search domains");
info( " a single, empty option disables the DNS search list");
if (strstr(name, "pasta"))
- info( " default: don't send any search list");
+ info( " default: don't use any search list");
else
info( " default: use search list from /etc/resolv.conf");
+ if (strstr(name, "pasta"))
+ info(" --dhcp-dns: \tPass DNS list via DHCP/DHCPv6/NDP");
+ else
+ info(" --no-dhcp-dns: No DNS list in DHCP/DHCPv6/NDP");
+
+ if (strstr(name, "pasta"))
+ info(" --dhcp-search: Pass list via DHCP/DHCPv6/NDP");
+ else
+ info(" --no-dhcp-search: No list in DHCP/DHCPv6/NDP");
+
+ info( " --dns-forward ADDR Forward DNS queries sent to ADDR");
+ info( " can be specified zero to two times (for IPv4 and IPv6)");
+ info( " default: don't forward DNS queries");
+
info( " --no-tcp Disable TCP protocol handler");
info( " --no-udp Disable UDP protocol handler");
info( " --no-icmp Disable ICMP/ICMPv6 protocol handler");
@@ -699,22 +713,18 @@ void conf_print(struct ctx *c)
info(" router: %s",
inet_ntop(AF_INET, &c->gw4, buf4, sizeof(buf4)));
}
- }
- if (!c->no_dns && !(c->no_dhcp && c->no_ndp && c->no_dhcpv6)) {
for (i = 0; c->dns4[i]; i++) {
if (!i)
- info(" DNS:");
+ info("DNS:");
inet_ntop(AF_INET, &c->dns4[i], buf4, sizeof(buf4));
- info(" %s", buf4);
+ info(" %s", buf4);
}
- }
- if (!c->no_dns_search && !(c->no_dhcp && c->no_ndp && c->no_dhcpv6)) {
for (i = 0; *c->dns_search[i].n; i++) {
if (!i)
- info(" search:");
- info(" %s", c->dns_search[i].n);
+ info("DNS search list:");
+ info(" %s", c->dns_search[i].n);
}
}
@@ -728,7 +738,7 @@ void conf_print(struct ctx *c)
else if (!c->no_dhcpv6)
info("NDP:");
else
- return;
+ goto dns6;
info(" assign: %s",
inet_ntop(AF_INET6, &c->addr6, buf6, sizeof(buf6)));
@@ -737,17 +747,18 @@ void conf_print(struct ctx *c)
info(" our link-local: %s",
inet_ntop(AF_INET6, &c->addr6_ll, buf6, sizeof(buf6)));
+dns6:
for (i = 0; !IN6_IS_ADDR_UNSPECIFIED(&c->dns6[i]); i++) {
if (!i)
- info(" DNS:");
+ info("DNS:");
inet_ntop(AF_INET6, &c->dns6[i], buf6, sizeof(buf6));
- info(" %s", buf6);
+ info(" %s", buf6);
}
for (i = 0; *c->dns_search[i].n; i++) {
if (!i)
- info(" search:");
- info(" %s", c->dns_search[i].n);
+ info("DNS search list:");
+ info(" %s", c->dns_search[i].n);
}
}
}
@@ -797,6 +808,11 @@ void conf(struct ctx *c, int argc, char **argv)
{"nsrun-dir", required_argument, NULL, 3 },
{"config-net", no_argument, &c->pasta_conf_ns, 1 },
{"ns-mac-addr", required_argument, NULL, 4 },
+ {"dhcp-dns", no_argument, NULL, 5 },
+ {"no-dhcp-dns", no_argument, NULL, 6 },
+ {"dhcp-search", no_argument, NULL, 7 },
+ {"no-dhcp-search", no_argument, NULL, 8 },
+ {"dns-forward", required_argument, NULL, 9 },
{ 0 },
};
struct get_bound_ports_ns_arg ns_ports_arg = { .c = c };
@@ -808,6 +824,9 @@ void conf(struct ctx *c, int argc, char **argv)
int name, ret, mask, b, i;
uint32_t *dns4 = c->dns4;
+ if (c->mode == MODE_PASTA)
+ c->no_dhcp_dns = c->no_dhcp_dns_search = 1;
+
do {
enum conf_port_type *set = NULL;
const char *optstring;
@@ -873,6 +892,51 @@ void conf(struct ctx *c, int argc, char **argv)
c->mac_guest[i] = b;
}
break;
+ case 5:
+ if (c->mode != MODE_PASTA) {
+ err("--dhcp-dns is for pasta mode only");
+ usage(argv[0]);
+ }
+ c->no_dhcp_dns = 0;
+ break;
+ case 6:
+ if (c->mode != MODE_PASST) {
+ err("--no-dhcp-dns is for passt mode only");
+ usage(argv[0]);
+ }
+ c->no_dhcp_dns = 1;
+ break;
+ case 7:
+ if (c->mode != MODE_PASTA) {
+ err("--dhcp-search is for pasta mode only");
+ usage(argv[0]);
+ }
+ c->no_dhcp_dns_search = 0;
+ break;
+ case 8:
+ if (c->mode != MODE_PASST) {
+ err("--no-dhcp-search is for passt mode only");
+ usage(argv[0]);
+ }
+ 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))
+ 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)
+ break;
+
+ err("Invalid DNS forwarding address: %s", optarg);
+ usage(argv[0]);
+ break;
case 'd':
if (c->debug) {
err("Multiple --debug options given");
@@ -1189,10 +1253,6 @@ void conf(struct ctx *c, int argc, char **argv)
if (!c->mtu)
c->mtu = ROUND_DOWN(ETH_MAX_MTU - ETH_HLEN, sizeof(uint32_t));
- if (c->mode == MODE_PASTA && dns4 == c->dns4 && dns6 == c->dns6)
- c->no_dns = 1;
- if (c->mode == MODE_PASTA && dnss == c->dns_search)
- c->no_dns_search = 1;
get_dns(c);
if (!*c->pasta_ifn)
diff --git a/dhcp.c b/dhcp.c
index a052397..ab1249c 100644
--- a/dhcp.c
+++ b/dhcp.c
@@ -333,12 +333,13 @@ int dhcp(struct ctx *c, struct ethhdr *eh, size_t len)
opts[26].s[1] = c->mtu % 256;
}
- for (i = 0, opts[6].slen = 0; c->dns4[i]; i++) {
+ for (i = 0, opts[6].slen = 0; !c->no_dhcp_dns && c->dns4[i]; i++) {
((uint32_t *)opts[6].s)[i] = c->dns4[i];
opts[6].slen += sizeof(uint32_t);
}
- opt_set_dns_search(c, sizeof(m->o));
+ if (!c->no_dhcp_dns_search)
+ opt_set_dns_search(c, sizeof(m->o));
uh->len = htons(len = offsetof(struct msg, o) + fill(m) + sizeof(*uh));
uh->check = 0;
diff --git a/dhcpv6.c b/dhcpv6.c
index e4113bc..b79a8e9 100644
--- a/dhcpv6.c
+++ b/dhcpv6.c
@@ -394,6 +394,9 @@ static size_t dhcpv6_dns_fill(struct ctx *c, char *buf, int offset)
char *p = NULL;
int i;
+ if (c->no_dhcp_dns)
+ goto search;
+
for (i = 0; !IN6_IS_ADDR_UNSPECIFIED(&c->dns6[i]); i++) {
if (!i) {
srv = (struct opt_dns_servers *)(buf + offset);
@@ -410,6 +413,10 @@ static size_t dhcpv6_dns_fill(struct ctx *c, char *buf, int offset)
if (srv)
srv->hdr.l = htons(srv->hdr.l);
+search:
+ if (c->no_dhcp_dns_search)
+ return offset;
+
for (i = 0; *c->dns_search[i].n; i++) {
if (!i) {
srch = (struct opt_dns_search *)(buf + offset);
diff --git a/ndp.c b/ndp.c
index 386098c..6b1c1a8 100644
--- a/ndp.c
+++ b/ndp.c
@@ -127,6 +127,9 @@ int ndp(struct ctx *c, struct ethhdr *eh, size_t len)
p += 4;
}
+ if (c->no_dhcp_dns)
+ goto dns_done;
+
for (n = 0; !IN6_IS_ADDR_UNSPECIFIED(&c->dns6[n]); n++);
if (n) {
*p++ = 25; /* RDNSS */
@@ -144,7 +147,7 @@ int ndp(struct ctx *c, struct ethhdr *eh, size_t len)
dns_s_len += strlen(c->dns_search[n].n) + 2;
}
- if (dns_s_len) {
+ if (!c->no_dhcp_dns_search && dns_s_len) {
*p++ = 31; /* DNSSL */
*p++ = (len + 8 - 1) / 8 + 1; /* length */
p += 2; /* reserved */
@@ -171,6 +174,7 @@ int ndp(struct ctx *c, struct ethhdr *eh, size_t len)
p += 8 - dns_s_len % 8;
}
+dns_done:
*p++ = 1; /* source ll */
*p++ = 1; /* length */
memcpy(p, c->mac, ETH_ALEN);
diff --git a/passt.1 b/passt.1
index 92681f6..7070a31 100644
--- a/passt.1
+++ b/passt.1
@@ -165,19 +165,62 @@ Default is to use the interface with the first default route.
.TP
.BR \-D ", " \-\-dns " " \fIaddr
-Assign IPv4 \fIaddr\fR via DHCP (option 23) or IPv6 \fIaddr\fR via NDP Router
-Advertisement (option type 25) and DHCPv6 (option 23) as DNS resolver.
+Use \fIaddr\fR (IPv4 or IPv6) for DHCP, DHCPv6, NDP or DNS forwarding, as
+configured (see options \fB--no-dhcp-dns\fR, \fB--dhcp-dns\fR,
+\fB--dns-forward\fR) instead of reading addresses from \fI/etc/resolv.conf\fR.
This option can be specified multiple times, and a single, empty option disables
-DNS options altogether.
-In \fBpasst\fR mode, default is to use addresses from \fI/etc/resolv.conf\fR,
-and, in \fBpasta\fR mode, no addresses are sent by default.
+usage of DNS addresses altogether.
+
+.TP
+.BR \-D ", " \-\-dns " " \fIaddr
+Use \fIaddr\fR (IPv4 or IPv6) for DHCP, DHCPv6, NDP or DNS forwarding, as
+configured (see options \fB--no-dhcp-dns\fR, \fB--dhcp-dns\fR,
+\fB--dns-forward\fR) instead of reading addresses from \fI/etc/resolv.conf\fR.
+This option can be specified multiple times, and a single, empty option disables
+usage of DNS addresses altogether.
+
+.TP
+.BR \-\-dns-forward " " \fIaddr
+Map \fIaddr\fR (IPv4 or IPv6) as seen from guest or namespace to the first
+configured DNS resolver (with corresponding IP version). Mapping is limited to
+UDP traffic directed to port 53, and DNS answers are translated back with a
+reverse mapping.
+This option can be specified zero to two times (once for IPv4, once for IPv6).
+
.TP
.BR \-S ", " \-\-search " " \fIlist
-Assign space-separated \fIlist\fR via DHCP (option 119), via NDP Router
-Advertisement (option type 31) and DHCPv6 (option 24) as DNS domain search list.
-A single, empty option disables sending the DNS domain search list.
-In \fBpasst\fR mode, default is to use the search list from
-\fI/etc/resolv.conf\fR, and, in \fBpasta\fR mode, no list is sent by default.
+Use space-separated \fIlist\fR for DHCP, DHCPv6, and NDP purposes, instead of
+reading entries from \fI/etc/resolv.conf\fR. See options \fB--no-dhcp-search\fR
+and \fB--dhcp-search\fR. A single, empty option disables the DNS domain search
+list altogether.
+
+.TP
+.BR \-\-no-dhcp-dns " " \fIaddr
+In \fIpasst\fR mode, do not assign IPv4 addresses via DHCP (option 23) or IPv6
+addresses via NDP Router Advertisement (option type 25) and DHCPv6 (option 23)
+as DNS resolvers.
+By default, all the configured addresses are passed.
+
+.TP
+.BR \-\-dhcp-dns " " \fIaddr
+In \fIpasta\fR mode, assign IPv4 addresses via DHCP (option 23) or IPv6
+addresses via NDP Router Advertisement (option type 25) and DHCPv6 (option 23)
+as DNS resolvers.
+By default, configured addresses, if any, are not passed.
+
+.TP
+.BR \-\-no-dhcp-search " " \fIaddr
+In \fIpasst\fR mode, do not send the DNS domain search list addresses via DHCP
+(option 119), via NDP Router Advertisement (option type 31) and DHCPv6 (option
+24).
+By default, the DNS domain search list resulting from configuration is passed.
+
+.TP
+.BR \-\-dhcp-search " " \fIaddr
+In \fIpasta\fR mode, send the DNS domain search list addresses via DHCP (option
+119), via NDP Router Advertisement (option type 31) and DHCPv6 (option 24).
+By default, the DNS domain search list resulting from configuration is not
+passed.
.TP
.BR \-\-no-tcp
diff --git a/passt.h b/passt.h
index d7011da..2589ee7 100644
--- a/passt.h
+++ b/passt.h
@@ -114,6 +114,7 @@ enum passt_modes {
* @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
* @v6: Enable IPv6 transport
* @addr6: IPv6 address for external, routable interface
@@ -121,7 +122,8 @@ enum passt_modes {
* @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
- * @dns4: IPv4 DNS addresses, zero-terminated
+ * @dns6: IPv6 DNS addresses, zero-terminated
+ * @dns6_fwd: Address forwarded (UDP) to first IPv6 DNS, network order
* @ifi: Index of routable interface
* @pasta_ifn: Name of namespace interface for pasta
* @pasta_ifn: Index of namespace interface for pasta
@@ -133,8 +135,10 @@ enum passt_modes {
* @no_icmp: Disable ICMP operation
* @icmp: Context for ICMP protocol handler
* @mtu: MTU passed via DHCP/NDP
- * @no_dns: Do not assign any DNS server via DHCP/DHCPv6/NDP
- * @no_dns_search: Do not assign any DNS domain search via DHCP/DHCPv6/NDP
+ * @no_dns: Do not source/use DNS servers for any purpose
+ * @no_dns_search: Do not source/use domain search lists for any purpose
+ * @no_dhcp_dns: Do not assign any DNS server via DHCP/DHCPv6/NDP
+ * @no_dhcp_dns_search: Do not assign any DNS domain search via DHCP/DHCPv6/NDP
* @no_dhcp: Disable DHCP server
* @no_dhcpv6: Disable DHCPv6 server
* @no_ndp: Disable NDP handler altogether
@@ -172,6 +176,7 @@ struct ctx {
uint32_t mask4;
uint32_t gw4;
uint32_t dns4[MAXNS + 1];
+ uint32_t dns4_fwd;
struct fqdn dns_search[MAXDNSRCH];
@@ -182,6 +187,7 @@ struct ctx {
struct in6_addr addr6_ll_seen;
struct in6_addr gw6;
struct in6_addr dns6[MAXNS + 1];
+ struct in6_addr dns6_fwd;
unsigned int ifi;
char pasta_ifn[IF_NAMESIZE];
@@ -198,6 +204,8 @@ struct ctx {
int mtu;
int no_dns;
int no_dns_search;
+ int no_dhcp_dns;
+ int no_dhcp_dns_search;
int no_dhcp;
int no_dhcpv6;
int no_ndp;
diff --git a/slirp4netns.sh b/slirp4netns.sh
index 1784926..ff12a52 100755
--- a/slirp4netns.sh
+++ b/slirp4netns.sh
@@ -16,7 +16,7 @@
# Author: Stefano Brivio <sbrivio@redhat.com>
PASTA_PID="$(mktemp)"
-PASTA_OPTS="-q --ipv4-only -a 10.0.2.0 -n 24 -g 10.0.2.2 -m 1500 --no-ndp --no-dhcpv6 --no-dhcp -P ${PASTA_PID}"
+PASTA_OPTS="-q --ipv4-only -a 10.0.2.0 -n 24 -g 10.0.2.2 --dns-forward 10.0.2.3 -m 1500 --no-ndp --no-dhcpv6 --no-dhcp -P ${PASTA_PID}"
PASTA="$(command -v ./pasta || command -v pasta || :)"
API_SOCKET=
diff --git a/udp.c b/udp.c
index 348f695..2fc52d3 100644
--- a/udp.c
+++ b/udp.c
@@ -718,6 +718,12 @@ void udp_sock_handler(struct ctx *c, union epoll_ref ref, uint32_t events,
udp_tap_map[V6][src].loopback = 0;
bitmap_set(udp_act[V6][UDP_ACT_TAP], src);
+ } else if (!IN6_IS_ADDR_UNSPECIFIED(&c->dns6_fwd) &&
+ !memcmp(&b->s_in6.sin6_addr, &c->dns6_fwd,
+ sizeof(c->dns6_fwd)) &&
+ ntohs(b->s_in6.sin6_port) == 53) {
+ b->ip6h.daddr = c->addr6_seen;
+ b->ip6h.saddr = c->dns6_fwd;
} else {
b->ip6h.daddr = c->addr6_seen;
b->ip6h.saddr = b->s_in6.sin6_addr;
@@ -797,6 +803,10 @@ void udp_sock_handler(struct ctx *c, union epoll_ref ref, uint32_t events,
udp_tap_map[V4][src].loopback = 1;
bitmap_set(udp_act[V4][UDP_ACT_TAP], src);
+ } else if (c->dns4_fwd &&
+ s_addr == ntohl(c->dns4[0]) &&
+ ntohs(b->s_in.sin_port) == 53) {
+ b->iph.saddr = c->dns4_fwd;
} else {
b->iph.saddr = b->s_in.sin_addr.s_addr;
}
@@ -958,6 +968,9 @@ int udp_tap_handler(struct ctx *c, int af, void *addr,
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 &&
+ ntohs(s_in.sin_port) == 53) {
+ s_in.sin_addr.s_addr = c->dns4[0];
}
} else {
s_in6 = (struct sockaddr_in6) {
@@ -976,6 +989,9 @@ int udp_tap_handler(struct ctx *c, int af, void *addr,
s_in6.sin6_addr = in6addr_loopback;
else
s_in6.sin6_addr = c->addr6_seen;
+ } else if (!memcmp(addr, &c->dns6_fwd, sizeof(c->dns6_fwd)) &&
+ ntohs(s_in6.sin6_port) == 53) {
+ s_in6.sin6_addr = c->dns6[0];
} else if (IN6_IS_ADDR_LINKLOCAL(&s_in6.sin6_addr)) {
bind_to = BIND_LL;
}