diff --git a/conf.c b/conf.c index f175405..675d961 100644 --- a/conf.c +++ b/conf.c @@ -179,9 +179,9 @@ static void conf_ports(const struct ctx *c, char optname, const char *optarg, { char addr_buf[sizeof(struct in6_addr)] = { 0 }, *addr = addr_buf; char buf[BUFSIZ], *spec, *ifname = NULL, *p; + bool exclude_only = true, bound_one = false; uint8_t exclude[PORT_BITMAP_SIZE] = { 0 }; sa_family_t af = AF_UNSPEC; - bool exclude_only = true; if (!strcmp(optarg, "none")) { if (fwd->mode) @@ -215,12 +215,19 @@ static void conf_ports(const struct ctx *c, char optname, const char *optarg, memset(fwd->map, 0xff, PORT_EPHEMERAL_MIN / 8); for (i = 0; i < PORT_EPHEMERAL_MIN; i++) { - if (optname == 't') - tcp_sock_init(c, AF_UNSPEC, NULL, NULL, i); - else if (optname == 'u') - udp_sock_init(c, 0, AF_UNSPEC, NULL, NULL, i); + if (optname == 't') { + if (!tcp_sock_init(c, AF_UNSPEC, NULL, NULL, i)) + bound_one = true; + } else if (optname == 'u') { + if (!udp_sock_init(c, 0, AF_UNSPEC, NULL, NULL, + i)) + bound_one = true; + } } + if (!bound_one) + goto bind_fail; + return; } @@ -293,12 +300,18 @@ static void conf_ports(const struct ctx *c, char optname, const char *optarg, bitmap_set(fwd->map, i); - if (optname == 't') - tcp_sock_init(c, af, addr, ifname, i); - else if (optname == 'u') - udp_sock_init(c, 0, af, addr, ifname, i); + if (optname == 't') { + if (!tcp_sock_init(c, af, addr, ifname, i)) + bound_one = true; + } else if (optname == 'u') { + if (!udp_sock_init(c, 0, af, addr, ifname, i)) + bound_one = true; + } } + if (!bound_one) + goto bind_fail; + return; } @@ -339,13 +352,19 @@ static void conf_ports(const struct ctx *c, char optname, const char *optarg, fwd->delta[i] = mapped_range.first - orig_range.first; - if (optname == 't') - tcp_sock_init(c, af, addr, ifname, i); - else if (optname == 'u') - udp_sock_init(c, 0, af, addr, ifname, i); + if (optname == 't') { + if (!tcp_sock_init(c, af, addr, ifname, i)) + bound_one = true; + } else if (optname == 'u') { + if (udp_sock_init(c, 0, af, addr, ifname, i)) + bound_one = true; + } } } while ((p = next_chunk(p, ','))); + if (!bound_one) + goto bind_fail; + return; bad: die("Invalid port specifier %s", optarg); @@ -353,6 +372,8 @@ overlap: die("Overlapping port specifier %s", optarg); mode_conflict: die("Port forwarding mode '%s' conflicts with previous mode", optarg); +bind_fail: + die("Failed to bind any port for '-%c %s', exiting", optname, optarg); } /** diff --git a/tcp.c b/tcp.c index f028e01..32ce1e9 100644 --- a/tcp.c +++ b/tcp.c @@ -2916,20 +2916,31 @@ static int tcp_sock_init_af(const struct ctx *c, int af, in_port_t port, * @addr: Pointer to address for binding, NULL if not configured * @ifname: Name of interface to bind to, NULL if not configured * @port: Port, host order + * + * Return: 0 on (partial) success, -1 on (complete) failure */ -void tcp_sock_init(const struct ctx *c, sa_family_t af, const void *addr, - const char *ifname, in_port_t port) +int tcp_sock_init(const struct ctx *c, sa_family_t af, const void *addr, + const char *ifname, in_port_t port) { + int ret = 0; + if (af == AF_UNSPEC && c->ifi4 && c->ifi6) /* Attempt to get a dual stack socket */ if (tcp_sock_init_af(c, AF_UNSPEC, port, addr, ifname) >= 0) - return; + return 0; /* Otherwise create a socket per IP version */ - if ((af == AF_INET || af == AF_UNSPEC) && c->ifi4) - tcp_sock_init_af(c, AF_INET, port, addr, ifname); - if ((af == AF_INET6 || af == AF_UNSPEC) && c->ifi6) - tcp_sock_init_af(c, AF_INET6, port, addr, ifname); + if ((af == AF_INET || af == AF_UNSPEC) && c->ifi4) { + if (tcp_sock_init_af(c, AF_INET, port, addr, ifname) < 0) + ret = -1; + } + + if ((af == AF_INET6 || af == AF_UNSPEC) && c->ifi6) { + if (tcp_sock_init_af(c, AF_INET6, port, addr, ifname) < 0) + ret = -1; + } + + return ret; } /** diff --git a/tcp.h b/tcp.h index 236038f..5527c5b 100644 --- a/tcp.h +++ b/tcp.h @@ -17,8 +17,8 @@ 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); -void tcp_sock_init(const struct ctx *c, sa_family_t af, const void *addr, - const char *ifname, in_port_t port); +int tcp_sock_init(const struct ctx *c, sa_family_t af, const void *addr, + const char *ifname, 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 2e9b7e6..c913d27 100644 --- a/udp.c +++ b/udp.c @@ -955,12 +955,14 @@ int udp_tap_handler(struct ctx *c, int af, const void *addr, * @addr: Pointer to address for binding, NULL if not configured * @ifname: Name of interface to bind to, NULL if not configured * @port: Port, host order + * + * Return: 0 on (partial) success, -1 on (complete) failure */ -void udp_sock_init(const struct ctx *c, int ns, sa_family_t af, - const void *addr, const char *ifname, in_port_t port) +int udp_sock_init(const struct ctx *c, int ns, sa_family_t af, + const void *addr, const char *ifname, in_port_t port) { union udp_epoll_ref uref = { .u32 = 0 }; - int s; + int s, ret = 0; if (ns) { uref.udp.port = (in_port_t)(port + @@ -989,6 +991,9 @@ void udp_sock_init(const struct ctx *c, int ns, sa_family_t af, ifname, port, uref.u32); udp_splice_ns[V4][port].sock = s; } + + if (s < 0) + ret = -1; } if ((af == AF_INET6 || af == AF_UNSPEC) && c->ifi6) { @@ -1009,7 +1014,12 @@ void udp_sock_init(const struct ctx *c, int ns, sa_family_t af, ifname, port, uref.u32); udp_splice_ns[V6][port].sock = s; } + + if (s < 0) + ret = -1; } + + return ret; } /** diff --git a/udp.h b/udp.h index 68082ea..0e81be8 100644 --- a/udp.h +++ b/udp.h @@ -12,8 +12,8 @@ void udp_sock_handler(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); -void udp_sock_init(const struct ctx *c, int ns, sa_family_t af, - const void *addr, const char *ifname, in_port_t port); +int udp_sock_init(const struct ctx *c, int ns, sa_family_t af, + const void *addr, const char *ifname, in_port_t port); int udp_init(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,