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; @@ -1092,6 +1093,96 @@ int udp_tap_handler(struct ctx *c, int af, const void *addr, return count; } +/** + * 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);