aboutgitcodebugslistschat
diff options
context:
space:
mode:
-rw-r--r--conf.c120
-rw-r--r--icmp.c5
-rw-r--r--passt.112
-rw-r--r--passt.c22
-rw-r--r--tcp.c63
-rw-r--r--tcp.h4
-rw-r--r--udp.c162
-rw-r--r--udp.h4
-rw-r--r--util.c27
-rw-r--r--util.h11
10 files changed, 274 insertions, 156 deletions
diff --git a/conf.c b/conf.c
index 5c614cd..0baf4fa 100644
--- a/conf.c
+++ b/conf.c
@@ -109,14 +109,24 @@ enum conf_port_type {
PORT_ALL,
};
+/**
+ * conf_ports() - Parse port configuration options, initialise UDP/TCP sockets
+ * @c: Execution context
+ * @optname: Short option name, t, T, u, or U
+ * @optarg: Option argument (port specification)
+ * @set: Pointer to @conf_port_type to be set (port binding type)
+ *
+ * Return: -EINVAL on parsing error, 0 otherwise
+ */
static int conf_ports(struct ctx *c, char optname, const char *optarg,
enum conf_port_type *set)
{
int start_src = -1, end_src = -1, start_dst = -1, end_dst = -1;
void (*remap)(in_port_t port, in_port_t delta);
- const char *p;
+ char addr_buf[sizeof(struct in6_addr)] = { 0 };
+ sa_family_t af = AF_UNSPEC;
+ char buf[BUFSIZ], *sep, *p, *addr = addr_buf;
uint8_t *map;
- char *sep;
if (optname == 't') {
map = c->tcp.port_to_tap;
@@ -149,10 +159,20 @@ static int conf_ports(struct ctx *c, char optname, const char *optarg,
}
if (!strcmp(optarg, "all")) {
+ int i;
+
if (*set || c->mode != MODE_PASST)
return -EINVAL;
*set = PORT_ALL;
memset(map, 0xff, PORT_EPHEMERAL_MIN / 8);
+
+ for (i = 0; i < PORT_EPHEMERAL_MIN; i++) {
+ if (optname == 't')
+ tcp_sock_init(c, 0, AF_UNSPEC, NULL, i);
+ else if (optname == 'u')
+ udp_sock_init(c, 0, AF_UNSPEC, NULL, i);
+ }
+
return 0;
}
@@ -161,12 +181,30 @@ static int conf_ports(struct ctx *c, char optname, const char *optarg,
*set = PORT_SPEC;
- if (strspn(optarg, "0123456789-,:") != strlen(optarg)) {
- err("Invalid port specifier %s", optarg);
- return -EINVAL;
+ strncpy(buf, optarg, sizeof(buf) - 1);
+
+ if ((p = strchr(buf, '/'))) {
+ *p = 0;
+ p++;
+
+ if (optname != 't' && optname != 'u')
+ goto bad;
+
+ if (inet_pton(AF_INET, buf, addr))
+ af = AF_INET;
+ else if (inet_pton(AF_INET6, buf, addr))
+ af = AF_INET6;
+ else
+ goto bad;
+ } else {
+ p = buf;
+
+ addr = NULL;
}
- p = optarg;
+ if (strspn(p, "0123456789-,:") != strlen(p))
+ goto bad;
+
do {
int i, port;
@@ -242,11 +280,16 @@ static int conf_ports(struct ctx *c, char optname, const char *optarg,
bitmap_set(map, i);
- if (start_dst == -1) /* 22 or 22-80 */
- continue;
+ if (start_dst != -1) {
+ /* 80:8080 or 22-80:8080:8080 */
+ remap(i, (in_port_t)(start_dst -
+ start_src));
+ }
- /* 80:8080 or 22-80:8080:8080 */
- remap(i, (in_port_t)(start_dst - start_src));
+ if (optname == 't')
+ tcp_sock_init(c, 0, af, addr, i);
+ else if (optname == 'u')
+ udp_sock_init(c, 0, af, addr, i);
}
start_src = end_src = start_dst = end_dst = -1;
@@ -655,13 +698,15 @@ static void usage(const char *name)
info( " 'none': don't forward any ports");
info( " 'all': forward all unbound, non-ephemeral ports");
info( " a comma-separated list, optionally ranged with '-'");
- info( " and optional target ports after ':'. Examples:");
+ info( " and optional target ports after ':', with optional");
+ info( " address specification suffixed by '/'. Examples:");
info( " -t 22 Forward local port 22 to 22 on guest");
info( " -t 22:23 Forward local port 22 to 23 on guest");
info( " -t 22,25 Forward ports 22, 25 to ports 22, 25");
info( " -t 22-80 Forward ports 22 to 80");
info( " -t 22-80:32-90 Forward ports 22 to 80 to");
info( " corresponding port numbers plus 10");
+ info( " -t 192.0.2.1/5 Bind port 5 of 192.0.2.1 to guest");
info( " default: none");
info( " -u, --udp-ports SPEC UDP port forwarding to guest");
info( " SPEC is as described for TCP above");
@@ -676,13 +721,15 @@ pasta_opts:
info( " 'none': don't forward any ports");
info( " 'auto': forward all ports currently bound in namespace");
info( " a comma-separated list, optionally ranged with '-'");
- info( " and optional target ports after ':'. Examples:");
+ info( " and optional target ports after ':', with optional");
+ info( " address specification suffixed by '/'. Examples:");
info( " -t 22 Forward local port 22 to port 22 in netns");
info( " -t 22:23 Forward local port 22 to port 23");
info( " -t 22,25 Forward ports 22, 25 to ports 22, 25");
info( " -t 22-80 Forward ports 22 to 80");
info( " -t 22-80:32-90 Forward ports 22 to 80 to");
info( " corresponding port numbers plus 10");
+ info( " -t 192.0.2.1/5 Bind port 5 of 192.0.2.1 to namespace");
info( " default: auto");
info( " IPv6 bound ports are also forwarded for IPv4");
info( " -u, --udp-ports SPEC UDP port forwarding to namespace");
@@ -857,7 +904,6 @@ void conf(struct ctx *c, int argc, char **argv)
c->no_dhcp_dns = c->no_dhcp_dns_search = 1;
do {
- enum conf_port_type *set = NULL;
const char *optstring;
if (c->mode == MODE_PASST)
@@ -1242,18 +1288,7 @@ void conf(struct ctx *c, int argc, char **argv)
case 'u':
case 'T':
case 'U':
- if (name == 't')
- set = &tcp_tap;
- else if (name == 'T')
- set = &tcp_init;
- else if (name == 'u')
- set = &udp_tap;
- else if (name == 'U')
- set = &udp_init;
-
- if (conf_ports(c, name, optarg, set))
- usage(argv[0]);
-
+ /* Handle these later, once addresses are configured */
break;
case '?':
case 'h':
@@ -1294,6 +1329,41 @@ void conf(struct ctx *c, int argc, char **argv)
conf_ip(c);
+ /* Now we can process port configuration options */
+ optind = 1;
+ do {
+ enum conf_port_type *set = NULL;
+ const char *optstring;
+
+ if (c->mode == MODE_PASST)
+ optstring = "dqfehs:p::P:m:a:n:M:g:i:D::S::46t:u:";
+ else
+ optstring = "dqfehI:p::P:m:a:n:M:g:i:D::S::46t:u:T:U:";
+
+ name = getopt_long(argc, argv, optstring, options, NULL);
+ switch (name) {
+ case 't':
+ case 'u':
+ case 'T':
+ case 'U':
+ if (name == 't')
+ set = &tcp_tap;
+ else if (name == 'T')
+ set = &tcp_init;
+ else if (name == 'u')
+ set = &udp_tap;
+ else if (name == 'U')
+ set = &udp_init;
+
+ if (!optarg || conf_ports(c, name, optarg, set))
+ usage(argv[0]);
+
+ break;
+ default:
+ break;
+ }
+ } while (name != -1);
+
if (!c->v4)
c->no_dhcp = 1;
diff --git a/icmp.c b/icmp.c
index 8abc94b..2da8b58 100644
--- a/icmp.c
+++ b/icmp.c
@@ -168,7 +168,8 @@ int icmp_tap_handler(const struct ctx *c, int af, const void *addr,
iref.icmp.id = id = ntohs(ih->un.echo.id);
if ((s = icmp_id_map[V4][id].sock) <= 0) {
- s = sock_l4(c, AF_INET, IPPROTO_ICMP, id, 0, iref.u32);
+ s = sock_l4(c, AF_INET, IPPROTO_ICMP, NULL, id,
+ iref.u32);
if (s < 0)
goto fail_sock;
if (s > SOCKET_MAX) {
@@ -205,7 +206,7 @@ int icmp_tap_handler(const struct ctx *c, int af, const void *addr,
iref.icmp.id = id = ntohs(ih->icmp6_identifier);
if ((s = icmp_id_map[V6][id].sock) <= 0) {
- s = sock_l4(c, AF_INET6, IPPROTO_ICMPV6, id, 0,
+ s = sock_l4(c, AF_INET6, IPPROTO_ICMPV6, NULL, id,
iref.u32);
if (s < 0)
goto fail_sock;
diff --git a/passt.1 b/passt.1
index d9708b6..cdca3e9 100644
--- a/passt.1
+++ b/passt.1
@@ -298,7 +298,8 @@ For low (< 1024) ports, see \fBNOTES\fR.
.TP
.BR ports
A comma-separated list of ports, optionally ranged with \fI-\fR, and,
-optionally, with target ports after \fI:\fR, if they differ. Examples:
+optionally, with target ports after \fI:\fR, if they differ. Specific addresses
+can be bound as well, separated by \fI/\fR. Examples:
.RS
.TP
-t 22
@@ -315,6 +316,9 @@ Forward local ports 22 to 80 to corresponding ports on the guest
.TP
-t 22-80-32:90
Forward local ports 22 to 80 to corresponding ports on the guest plus 10
+.TP
+-t 192.0.2.1/22
+Forward local port 22, bound to 192.0.2.1, to port 22 on the guest
.RE
Default is \fBnone\fR.
@@ -356,7 +360,8 @@ periodically derived (every second) from listening sockets reported by
.TP
.BR ports
A comma-separated list of ports, optionally ranged with \fI-\fR, and,
-optionally, with target ports after \fI:\fR, if they differ. Examples:
+optionally, with target ports after \fI:\fR, if they differ. Specific addresses
+can be bound as well, separated by \fI/\fR. Examples:
.RS
.TP
-t 22
@@ -374,6 +379,9 @@ Forward local ports 22 to 80 to corresponding ports in the target namespace
-t 22-80-32:90
Forward local ports 22 to 80 to corresponding ports plus 10 in the target
namespace
+.TP
+-t 192.0.2.1/22
+Forward local port 22, bound to 192.0.2.1, to port 22 in the target namespace
.RE
IPv6 bound ports are also forwarded for IPv4.
diff --git a/passt.c b/passt.c
index 8781a7f..e5064f8 100644
--- a/passt.c
+++ b/passt.c
@@ -370,20 +370,13 @@ int main(int argc, char **argv)
__setlogmask(LOG_MASK(LOG_EMERG));
- conf(&c, argc, argv);
- trace_init(c.trace);
-
- if (!c.debug && (c.stderr || isatty(fileno(stdout))))
- __openlog(log_name, LOG_PERROR, LOG_DAEMON);
-
- c.epollfd = epoll_create1(c.foreground ? O_CLOEXEC : 0);
+ /* NOLINTNEXTLINE(android-cloexec-epoll-create1): forking in a moment */
+ c.epollfd = epoll_create1(0);
if (c.epollfd == -1) {
perror("epoll_create1");
exit(EXIT_FAILURE);
}
- quit_fd = pasta_netns_quit_init(&c);
-
if (getrlimit(RLIMIT_NOFILE, &limit)) {
perror("getrlimit");
exit(EXIT_FAILURE);
@@ -395,13 +388,20 @@ int main(int argc, char **argv)
}
sock_probe_mem(&c);
+ conf(&c, argc, argv);
+ trace_init(c.trace);
+
+ if (!c.debug && (c.stderr || isatty(fileno(stdout))))
+ __openlog(log_name, LOG_PERROR, LOG_DAEMON);
+
+ quit_fd = pasta_netns_quit_init(&c);
+
c.fd_tap = c.fd_tap_listen = -1;
tap_sock_init(&c);
clock_gettime(CLOCK_MONOTONIC, &now);
- if ((!c.no_udp && udp_sock_init(&c)) ||
- (!c.no_tcp && tcp_sock_init(&c)))
+ 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);
diff --git a/tcp.c b/tcp.c
index ad10688..e68409a 100644
--- a/tcp.c
+++ b/tcp.c
@@ -3082,14 +3082,18 @@ void tcp_sock_handler(struct ctx *c, union epoll_ref ref, uint32_t events,
}
/**
- * tcp_sock_init_one() - Initialise listening sockets for a given port
+ * tcp_sock_init() - Initialise listening sockets for a given port
* @c: Execution context
* @ns: In pasta mode, if set, bind with loopback address in namespace
+ * @af: Address family to select a specific IP version, or AF_UNSPEC
+ * @addr: Pointer to address for binding, NULL if not configured
* @port: Port, host order
*/
-static void tcp_sock_init_one(const struct ctx *c, int ns, in_port_t port)
+void tcp_sock_init(const struct ctx *c, int ns, sa_family_t af,
+ const void *addr, in_port_t port)
{
union tcp_epoll_ref tref = { .tcp.listen = 1 };
+ const void *bind_addr;
int s;
if (ns) {
@@ -3100,13 +3104,17 @@ static void tcp_sock_init_one(const struct ctx *c, int ns, in_port_t port)
tcp_port_delta_to_tap[port]);
}
- if (c->v4) {
- tref.tcp.v6 = 0;
+ if (af == AF_INET || af == AF_UNSPEC) {
+ if (!addr && c->mode == MODE_PASTA)
+ bind_addr = &c->addr4;
+ else
+ bind_addr = addr;
+ tref.tcp.v6 = 0;
tref.tcp.splice = 0;
+
if (!ns) {
- s = sock_l4(c, AF_INET, IPPROTO_TCP, port,
- c->mode == MODE_PASTA ? BIND_EXT : BIND_ANY,
+ s = sock_l4(c, AF_INET, IPPROTO_TCP, bind_addr, port,
tref.u32);
if (s >= 0)
tcp_sock_set_bufsize(c, s);
@@ -3118,9 +3126,11 @@ static void tcp_sock_init_one(const struct ctx *c, int ns, in_port_t port)
}
if (c->mode == MODE_PASTA) {
+ bind_addr = &(uint32_t){ htonl(INADDR_LOOPBACK) };
+
tref.tcp.splice = 1;
- s = sock_l4(c, AF_INET, IPPROTO_TCP, port,
- BIND_LOOPBACK, tref.u32);
+ s = sock_l4(c, AF_INET, IPPROTO_TCP, bind_addr, port,
+ tref.u32);
if (s >= 0)
tcp_sock_set_bufsize(c, s);
else
@@ -3135,13 +3145,17 @@ static void tcp_sock_init_one(const struct ctx *c, int ns, in_port_t port)
}
}
- if (c->v6) {
+ if (af == AF_INET6 || af == AF_UNSPEC) {
+ if (!addr && c->mode == MODE_PASTA)
+ bind_addr = &c->addr6;
+ else
+ bind_addr = addr;
+
tref.tcp.v6 = 1;
tref.tcp.splice = 0;
if (!ns) {
- s = sock_l4(c, AF_INET6, IPPROTO_TCP, port,
- c->mode == MODE_PASTA ? BIND_EXT : BIND_ANY,
+ s = sock_l4(c, AF_INET6, IPPROTO_TCP, bind_addr, port,
tref.u32);
if (s >= 0)
tcp_sock_set_bufsize(c, s);
@@ -3153,9 +3167,11 @@ static void tcp_sock_init_one(const struct ctx *c, int ns, in_port_t port)
}
if (c->mode == MODE_PASTA) {
+ bind_addr = &in6addr_loopback;
+
tref.tcp.splice = 1;
- s = sock_l4(c, AF_INET6, IPPROTO_TCP, port,
- BIND_LOOPBACK, tref.u32);
+ s = sock_l4(c, AF_INET6, IPPROTO_TCP, bind_addr, port,
+ tref.u32);
if (s >= 0)
tcp_sock_set_bufsize(c, s);
else
@@ -3188,7 +3204,7 @@ static int tcp_sock_init_ns(void *arg)
if (!bitmap_isset(c->tcp.port_to_init, port))
continue;
- tcp_sock_init_one(c, 1, port);
+ tcp_sock_init(c, 1, AF_UNSPEC, NULL, port);
}
return 0;
@@ -3259,15 +3275,15 @@ static int tcp_sock_refill(void *arg)
}
/**
- * tcp_sock_init() - Bind sockets for inbound connections, get key for sequence
+ * tcp_init() - Get initial sequence, hash secret, initialise per-socket data
* @c: Execution context
*
- * Return: 0 on success, -1 on failure
+ * Return: 0, doesn't return on failure
*/
-int tcp_sock_init(struct ctx *c)
+int tcp_init(struct ctx *c)
{
struct tcp_sock_refill_arg refill_arg = { c, 0 };
- int i, port;
+ int i;
#ifndef HAS_GETRANDOM
int dev_random = open("/dev/random", O_RDONLY);
unsigned int random_read = 0;
@@ -3296,13 +3312,6 @@ int tcp_sock_init(struct ctx *c)
exit(EXIT_FAILURE);
}
- for (port = 0; port < USHRT_MAX; port++) {
- if (!bitmap_isset(c->tcp.port_to_tap, port))
- continue;
-
- tcp_sock_init_one(c, 0, port);
- }
-
for (i = 0; i < ARRAY_SIZE(tcp_l2_mh); i++)
tcp_l2_mh[i] = (struct mmsghdr) { .msg_hdr.msg_iovlen = 1 };
@@ -3412,7 +3421,7 @@ static int tcp_port_rebind(void *arg)
if ((a->c->v4 && tcp_sock_ns[port][V4] == -1) ||
(a->c->v6 && tcp_sock_ns[port][V6] == -1))
- tcp_sock_init_one(a->c, 1, port);
+ tcp_sock_init(a->c, 1, AF_UNSPEC, NULL, port);
}
} else {
for (port = 0; port < USHRT_MAX; port++) {
@@ -3445,7 +3454,7 @@ static int tcp_port_rebind(void *arg)
if ((a->c->v4 && tcp_sock_init_ext[port][V4] == -1) ||
(a->c->v6 && tcp_sock_init_ext[port][V6] == -1))
- tcp_sock_init_one(a->c, 0, port);
+ tcp_sock_init(a->c, 0, AF_UNSPEC, NULL, port);
}
}
diff --git a/tcp.h b/tcp.h
index 99edf81..7b720c1 100644
--- a/tcp.h
+++ b/tcp.h
@@ -20,7 +20,9 @@ void tcp_sock_handler(struct ctx *c, union epoll_ref ref, uint32_t events,
const struct timespec *now);
int tcp_tap_handler(struct ctx *c, int af, const void *addr,
const struct pool *p, const struct timespec *now);
-int tcp_sock_init(struct ctx *c);
+void tcp_sock_init(const struct ctx *c, int ns, sa_family_t af,
+ const void *addr, in_port_t port);
+int tcp_init(struct ctx *c);
void tcp_timer(struct ctx *c, const struct timespec *ts);
void tcp_defer_handler(struct ctx *c);
diff --git a/udp.c b/udp.c
index 86d806a..f425d14 100644
--- a/udp.c
+++ b/udp.c
@@ -1000,7 +1000,8 @@ int udp_tap_handler(struct ctx *c, int af, const void *addr,
union udp_epoll_ref uref = { .udp.bound = 1,
.udp.port = src };
- s = sock_l4(c, AF_INET, IPPROTO_UDP, src, 0, uref.u32);
+ s = sock_l4(c, AF_INET, IPPROTO_UDP, NULL, src,
+ uref.u32);
if (s < 0)
return p->count;
@@ -1026,7 +1027,7 @@ int udp_tap_handler(struct ctx *c, int af, const void *addr,
.sin6_port = uh->dest,
.sin6_addr = *(struct in6_addr *)addr,
};
- enum bind_type bind_to = BIND_ANY;
+ const void *bind_addr = &in6addr_any;
sa = (struct sockaddr *)&s_in6;
sl = sizeof(s_in6);
@@ -1043,7 +1044,7 @@ int udp_tap_handler(struct ctx *c, int af, const void *addr,
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;
+ bind_addr = &c->addr6_ll;
}
if (!(s = udp_tap_map[V6][src].sock)) {
@@ -1051,7 +1052,7 @@ int udp_tap_handler(struct ctx *c, int af, const void *addr,
.udp.v6 = 1,
.udp.port = src };
- s = sock_l4(c, AF_INET6, IPPROTO_UDP, src, bind_to,
+ s = sock_l4(c, AF_INET6, IPPROTO_UDP, bind_addr, src,
uref.u32);
if (s < 0)
return p->count;
@@ -1093,6 +1094,96 @@ int udp_tap_handler(struct ctx *c, int af, const void *addr,
}
/**
+ * udp_sock_init() - Initialise listening sockets for a given port
+ * @c: Execution context
+ * @ns: In pasta mode, if set, bind with loopback address in namespace
+ * @af: Address family to select a specific IP version, or AF_UNSPEC
+ * @addr: Pointer to address for binding, NULL if not configured
+ * @port: Port, host order
+ */
+void udp_sock_init(const struct ctx *c, int ns, sa_family_t af,
+ const void *addr, in_port_t port)
+{
+ union udp_epoll_ref uref = { .udp.bound = 1 };
+ const void *bind_addr;
+ int s;
+
+ if (ns) {
+ uref.udp.port = (in_port_t)(port +
+ udp_port_delta_to_init[port]);
+ } else {
+ uref.udp.port = (in_port_t)(port +
+ udp_port_delta_to_tap[port]);
+ }
+
+ if (af == AF_INET || af == AF_UNSPEC) {
+ if (!addr && c->mode == MODE_PASTA)
+ bind_addr = &c->addr4;
+ else
+ bind_addr = addr;
+
+ uref.udp.v6 = 0;
+
+ if (!ns) {
+ uref.udp.splice = 0;
+ s = sock_l4(c, AF_INET, IPPROTO_UDP, bind_addr, port,
+ uref.u32);
+
+ udp_tap_map[V4][uref.udp.port].sock = s;
+ }
+
+ if (c->mode == MODE_PASTA) {
+ bind_addr = &(uint32_t){ htonl(INADDR_LOOPBACK) };
+ uref.udp.splice = UDP_TO_NS;
+
+ sock_l4(c, AF_INET, IPPROTO_UDP, bind_addr, port,
+ uref.u32);
+ }
+
+ if (ns) {
+ bind_addr = &(uint32_t){ htonl(INADDR_LOOPBACK) };
+ uref.udp.splice = UDP_TO_INIT;
+
+ sock_l4(c, AF_INET, IPPROTO_UDP, bind_addr, port,
+ uref.u32);
+ }
+ }
+
+ if (af == AF_INET6 || af == AF_UNSPEC) {
+ if (!addr && c->mode == MODE_PASTA)
+ bind_addr = &c->addr6;
+ else
+ bind_addr = addr;
+
+ uref.udp.v6 = 1;
+
+ if (!ns) {
+ uref.udp.splice = 0;
+ s = sock_l4(c, AF_INET6, IPPROTO_UDP, bind_addr, port,
+ uref.u32);
+
+ udp_tap_map[V6][uref.udp.port].sock = s;
+ }
+
+ if (c->mode == MODE_PASTA) {
+ bind_addr = &in6addr_loopback;
+ uref.udp.splice = UDP_TO_NS;
+
+ sock_l4(c, AF_INET6, IPPROTO_UDP, bind_addr, port,
+ uref.u32);
+ }
+
+ if (ns) {
+ bind_addr = &in6addr_loopback;
+ uref.udp.splice = UDP_TO_INIT;
+
+ sock_l4(c, AF_INET6, IPPROTO_UDP, bind_addr, port,
+ uref.u32);
+ }
+ }
+}
+
+/**
* udp_sock_init_ns() - Bind sockets in namespace for inbound connections
* @arg: Execution context
*
@@ -1100,8 +1191,6 @@ int udp_tap_handler(struct ctx *c, int af, const void *addr,
*/
int udp_sock_init_ns(void *arg)
{
- union udp_epoll_ref uref = { .udp.bound = 1,
- .udp.splice = UDP_TO_INIT };
struct ctx *c = (struct ctx *)arg;
int dst;
@@ -1112,19 +1201,7 @@ int udp_sock_init_ns(void *arg)
if (!bitmap_isset(c->udp.port_to_init, dst))
continue;
- uref.udp.port = dst + udp_port_delta_to_init[dst];
-
- if (c->v4) {
- uref.udp.v6 = 0;
- sock_l4(c, AF_INET, IPPROTO_UDP, dst, BIND_LOOPBACK,
- uref.u32);
- }
-
- if (c->v6) {
- uref.udp.v6 = 1;
- sock_l4(c, AF_INET6, IPPROTO_UDP, dst, BIND_LOOPBACK,
- uref.u32);
- }
+ udp_sock_init(c, 1, AF_UNSPEC, NULL, dst);
}
return 0;
@@ -1178,54 +1255,13 @@ static void udp_splice_iov_init(void)
}
/**
- * udp_sock_init() - Create and bind listening sockets for inbound packets
+ * udp_init() - Initialise per-socket data, and sockets in namespace
* @c: Execution context
*
- * Return: 0 on success, -1 on failure
+ * Return: 0
*/
-int udp_sock_init(const struct ctx *c)
+int udp_init(const struct ctx *c)
{
- union udp_epoll_ref uref = { .udp.bound = 1 };
- int dst, s;
-
- for (dst = 0; dst < USHRT_MAX; dst++) {
- if (!bitmap_isset(c->udp.port_to_tap, dst))
- continue;
-
- uref.udp.port = dst + udp_port_delta_to_tap[dst];
-
- if (c->v4) {
- uref.udp.splice = 0;
- uref.udp.v6 = 0;
- s = sock_l4(c, AF_INET, IPPROTO_UDP, dst,
- c->mode == MODE_PASTA ? BIND_EXT : BIND_ANY,
- uref.u32);
- if (s > 0)
- udp_tap_map[V4][uref.udp.port].sock = s;
-
- if (c->mode == MODE_PASTA) {
- uref.udp.splice = UDP_TO_NS;
- sock_l4(c, AF_INET, IPPROTO_UDP, dst,
- BIND_LOOPBACK, uref.u32);
- }
- }
- if (c->v6) {
- uref.udp.splice = 0;
- uref.udp.v6 = 1;
- s = sock_l4(c, AF_INET6, IPPROTO_UDP, dst,
- c->mode == MODE_PASTA ? BIND_EXT : BIND_ANY,
- uref.u32);
- if (s > 0)
- udp_tap_map[V6][uref.udp.port].sock = s;
-
- if (c->mode == MODE_PASTA) {
- uref.udp.splice = UDP_TO_NS;
- sock_l4(c, AF_INET6, IPPROTO_UDP, dst,
- BIND_LOOPBACK, uref.u32);
- }
- }
- }
-
if (c->v4)
udp_sock4_iov_init();
diff --git a/udp.h b/udp.h
index 4b6f465..f16fe5e 100644
--- a/udp.h
+++ b/udp.h
@@ -12,7 +12,9 @@ void udp_sock_handler(const struct ctx *c, union epoll_ref ref, uint32_t events,
const struct timespec *now);
int udp_tap_handler(struct ctx *c, int af, const void *addr,
const struct pool *p, const struct timespec *now);
-int udp_sock_init(const struct ctx *c);
+void udp_sock_init(const struct ctx *c, int ns, sa_family_t af,
+ const void *addr, in_port_t port);
+int udp_init(const struct ctx *c);
void udp_timer(struct ctx *c, const struct timespec *ts);
void udp_update_l2_buf(const unsigned char *eth_d, const unsigned char *eth_s,
const uint32_t *ip_da);
diff --git a/util.c b/util.c
index c3475d6..9afd2a5 100644
--- a/util.c
+++ b/util.c
@@ -218,14 +218,14 @@ found:
* @c: Execution context
* @af: Address family, AF_INET or AF_INET6
* @proto: Protocol number
+ * @bind_addr: Address for binding, NULL for any
* @port: Port, host order
- * @bind_type: Type of address for binding
* @data: epoll reference portion for protocol handlers
*
* Return: newly created socket, -1 on error
*/
-int sock_l4(const struct ctx *c, int af, uint8_t proto, uint16_t port,
- enum bind_type bind_addr, uint32_t data)
+int sock_l4(const struct ctx *c, int af, uint8_t proto,
+ const void *bind_addr, uint16_t port, uint32_t data)
{
union epoll_ref ref = { .r.proto = proto, .r.p.data = data };
struct sockaddr_in addr4 = {
@@ -264,23 +264,20 @@ int sock_l4(const struct ctx *c, int af, uint8_t proto, uint16_t port,
ref.r.s = fd;
if (af == AF_INET) {
- if (bind_addr == BIND_LOOPBACK)
- addr4.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
- else if (bind_addr == BIND_EXT)
- addr4.sin_addr.s_addr = c->addr4;
+ if (bind_addr)
+ addr4.sin_addr.s_addr = *(in_addr_t *)bind_addr;
else
addr4.sin_addr.s_addr = htonl(INADDR_ANY);
sa = (const struct sockaddr *)&addr4;
sl = sizeof(addr4);
} else {
- if (bind_addr == BIND_LOOPBACK) {
- addr6.sin6_addr = in6addr_loopback;
- } else if (bind_addr == BIND_EXT) {
- addr6.sin6_addr = c->addr6;
- } else if (bind_addr == BIND_LL) {
- addr6.sin6_addr = c->addr6_ll;
- addr6.sin6_scope_id = c->ifi;
+ if (bind_addr) {
+ addr6.sin6_addr = *(struct in6_addr *)bind_addr;
+
+ if (!memcmp(bind_addr, &c->addr6_ll,
+ sizeof(c->addr6_ll)))
+ addr6.sin6_scope_id = c->ifi;
} else {
addr6.sin6_addr = in6addr_any;
}
@@ -303,7 +300,7 @@ int sock_l4(const struct ctx *c, int af, uint8_t proto, uint16_t port,
*/
if (proto != IPPROTO_ICMP && proto != IPPROTO_ICMPV6) {
close(fd);
- return 0;
+ return -1;
}
}
diff --git a/util.h b/util.h
index 5172bf6..f85a87a 100644
--- a/util.h
+++ b/util.h
@@ -170,13 +170,6 @@ enum {
#include "packet.h"
-enum bind_type {
- BIND_ANY = 0,
- BIND_LOOPBACK,
- BIND_LL,
- BIND_EXT,
-};
-
struct ctx;
struct ipv6hdr {
@@ -213,8 +206,8 @@ void passt_vsyslog(int pri, const char *format, va_list ap);
void __setlogmask(int mask);
char *ipv6_l4hdr(const struct pool *p, int index, size_t offset, uint8_t *proto,
size_t *dlen);
-int sock_l4(const struct ctx *c, int af, uint8_t proto, uint16_t port,
- enum bind_type bind_addr, uint32_t data);
+int sock_l4(const struct ctx *c, int af, uint8_t proto,
+ const void *bind_addr, uint16_t port, uint32_t data);
void sock_probe_mem(struct ctx *c);
int timespec_diff_ms(const struct timespec *a, const struct timespec *b);
void bitmap_set(uint8_t *map, int bit);