aboutgitcodebugslistschat
diff options
context:
space:
mode:
-rw-r--r--conf.c2
-rw-r--r--passt.110
-rw-r--r--passt.h2
-rw-r--r--util.c16
4 files changed, 30 insertions, 0 deletions
diff --git a/conf.c b/conf.c
index 6e62510..e360fb9 100644
--- a/conf.c
+++ b/conf.c
@@ -836,6 +836,7 @@ static void usage(const char *name, FILE *f, int status)
" --no-ndp Disable NDP responses\n"
" --no-dhcpv6 Disable DHCPv6 server\n"
" --no-ra Disable router advertisements\n"
+ " --freebind Bind to any address for forwarding\n"
" --no-map-gw Don't map gateway address to host\n"
" -4, --ipv4-only Enable IPv4 operation only\n"
" -6, --ipv6-only Enable IPv6 operation only\n");
@@ -1255,6 +1256,7 @@ void conf(struct ctx *c, int argc, char **argv)
{"no-dhcpv6", no_argument, &c->no_dhcpv6, 1 },
{"no-ndp", no_argument, &c->no_ndp, 1 },
{"no-ra", no_argument, &c->no_ra, 1 },
+ {"freebind", no_argument, &c->freebind, 1 },
{"no-map-gw", no_argument, &no_map_gw, 1 },
{"ipv4-only", no_argument, NULL, '4' },
{"ipv6-only", no_argument, NULL, '6' },
diff --git a/passt.1 b/passt.1
index 79d134d..5ac2962 100644
--- a/passt.1
+++ b/passt.1
@@ -328,6 +328,16 @@ Disable Router Advertisements. Router Solicitations coming from guest or target
namespace will be ignored.
.TP
+.BR \-\-freebind
+Allow any binding address to be specified for \fB-t\fR and \fB-u\fR
+options. Usually binding addresses must be addresses currently
+configured on the host. With \fB\-\-freebind\fR, the
+\fBIP_FREEBIND\fR or \fBIPV6_FREEBIND\fR socket option is enabled
+allowing any address to be used. This is typically used to bind
+addresses which might be configured on the host in future, at which
+point the forwarding will immediately start operating.
+
+.TP
.BR \-\-map-host-loopback " " \fIaddr
Translate \fIaddr\fR to refer to the host. Packets from the guest to
\fIaddr\fR will be redirected to the host. On the host such packets
diff --git a/passt.h b/passt.h
index 031c9b6..4908ed9 100644
--- a/passt.h
+++ b/passt.h
@@ -225,6 +225,7 @@ struct ip6_ctx {
* @no_dhcpv6: Disable DHCPv6 server
* @no_ndp: Disable NDP handler altogether
* @no_ra: Disable router advertisements
+ * @freebind: Allow binding of non-local addresses for forwarding
* @low_wmem: Low probed net.core.wmem_max
* @low_rmem: Low probed net.core.rmem_max
*/
@@ -284,6 +285,7 @@ struct ctx {
int no_dhcpv6;
int no_ndp;
int no_ra;
+ int freebind;
int low_wmem;
int low_rmem;
diff --git a/util.c b/util.c
index ebd93ed..eba7d52 100644
--- a/util.c
+++ b/util.c
@@ -52,6 +52,7 @@ int sock_l4_sa(const struct ctx *c, enum epoll_type type,
{
sa_family_t af = ((const struct sockaddr *)sa)->sa_family;
union epoll_ref ref = { .type = type, .data = data };
+ bool freebind = false;
struct epoll_event ev;
int fd, y = 1, ret;
uint8_t proto;
@@ -61,8 +62,11 @@ int sock_l4_sa(const struct ctx *c, enum epoll_type type,
case EPOLL_TYPE_TCP_LISTEN:
proto = IPPROTO_TCP;
socktype = SOCK_STREAM | SOCK_NONBLOCK;
+ freebind = c->freebind;
break;
case EPOLL_TYPE_UDP_LISTEN:
+ freebind = c->freebind;
+ /* fallthrough */
case EPOLL_TYPE_UDP_REPLY:
proto = IPPROTO_UDP;
socktype = SOCK_DGRAM | SOCK_NONBLOCK;
@@ -127,6 +131,18 @@ int sock_l4_sa(const struct ctx *c, enum epoll_type type,
}
}
+ if (freebind) {
+ int level = af == AF_INET ? IPPROTO_IP : IPPROTO_IPV6;
+ int opt = af == AF_INET ? IP_FREEBIND : IPV6_FREEBIND;
+
+ if (setsockopt(fd, level, opt, &y, sizeof(y))) {
+ err_perror("Failed to set %s on socket %i",
+ af == AF_INET ? "IP_FREEBIND"
+ : "IPV6_FREEBIND",
+ fd);
+ }
+ }
+
if (bind(fd, sa, sl) < 0) {
/* We'll fail to bind to low ports if we don't have enough
* capabilities, and we'll fail to bind on already bound ports,