aboutgitcodebugslistschat
diff options
context:
space:
mode:
-rw-r--r--util.c123
1 files changed, 70 insertions, 53 deletions
diff --git a/util.c b/util.c
index 4446180..77448ec 100644
--- a/util.c
+++ b/util.c
@@ -33,36 +33,25 @@
#include "log.h"
/**
- * sock_l4() - Create and bind socket for given L4, add to epoll list
+ * sock_l4_sa() - Create and bind socket to socket address, add to epoll list
* @c: Execution context
- * @af: Address family, AF_INET or AF_INET6
* @proto: Protocol number
- * @bind_addr: Address for binding, NULL for any
+ * @sa: Socket address to bind to
+ * @sl: Length of @sa
* @ifname: Interface for binding, NULL for any
- * @port: Port, host order
+ * @v6only: Set IPV6_V6ONLY socket option
* @data: epoll reference portion for protocol handlers
*
* Return: newly created socket, negative error code on failure
*/
-int sock_l4(const struct ctx *c, sa_family_t af, uint8_t proto,
- const void *bind_addr, const char *ifname, uint16_t port,
- uint32_t data)
+static int sock_l4_sa(const struct ctx *c, uint8_t proto,
+ const void *sa, socklen_t sl,
+ const char *ifname, bool v6only, uint32_t data)
{
+ sa_family_t af = ((const struct sockaddr *)sa)->sa_family;
union epoll_ref ref = { .data = data };
- struct sockaddr_in addr4 = {
- .sin_family = AF_INET,
- .sin_port = htons(port),
- { 0 }, { 0 },
- };
- struct sockaddr_in6 addr6 = {
- .sin6_family = AF_INET6,
- .sin6_port = htons(port),
- 0, IN6ADDR_ANY_INIT, 0,
- };
- const struct sockaddr *sa;
- bool dual_stack = false;
- int fd, sl, y = 1, ret;
struct epoll_event ev;
+ int fd, y = 1, ret;
switch (proto) {
case IPPROTO_TCP:
@@ -79,13 +68,6 @@ int sock_l4(const struct ctx *c, sa_family_t af, uint8_t proto,
return -EPFNOSUPPORT; /* Not implemented. */
}
- if (af == AF_UNSPEC) {
- if (!DUAL_STACK_SOCKETS || bind_addr)
- return -EINVAL;
- dual_stack = true;
- af = AF_INET6;
- }
-
if (proto == IPPROTO_TCP)
fd = socket(af, SOCK_STREAM | SOCK_NONBLOCK, proto);
else
@@ -104,30 +86,9 @@ int sock_l4(const struct ctx *c, sa_family_t af, uint8_t proto,
ref.fd = fd;
- if (af == AF_INET) {
- if (bind_addr)
- addr4.sin_addr = *(struct in_addr *)bind_addr;
-
- sa = (const struct sockaddr *)&addr4;
- sl = sizeof(addr4);
- } else {
- if (bind_addr) {
- addr6.sin6_addr = *(struct in6_addr *)bind_addr;
-
- if (!memcmp(bind_addr, &c->ip6.addr_ll,
- sizeof(c->ip6.addr_ll)))
- addr6.sin6_scope_id = c->ifi6;
- }
-
- sa = (const struct sockaddr *)&addr6;
- sl = sizeof(addr6);
-
- if (!dual_stack)
- if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY,
- &y, sizeof(y)))
- debug("Failed to set IPV6_V6ONLY on socket %i",
- fd);
- }
+ if (v6only)
+ if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &y, sizeof(y)))
+ debug("Failed to set IPV6_V6ONLY on socket %i", fd);
if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &y, sizeof(y)))
debug("Failed to set SO_REUSEADDR on socket %i", fd);
@@ -140,9 +101,12 @@ int sock_l4(const struct ctx *c, sa_family_t af, uint8_t proto,
*/
if (setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE,
ifname, strlen(ifname))) {
+ char str[SOCKADDR_STRLEN];
+
ret = -errno;
- warn("Can't bind %s socket for port %u to %s, closing",
- EPOLL_TYPE_STR(proto), port, ifname);
+ warn("Can't bind %s socket for %s to %s, closing",
+ EPOLL_TYPE_STR(proto),
+ sockaddr_ntop(sa, str, sizeof(str)), ifname);
close(fd);
return ret;
}
@@ -178,6 +142,59 @@ int sock_l4(const struct ctx *c, sa_family_t af, uint8_t proto,
return fd;
}
+/**
+ * sock_l4() - Create and bind socket for given L4, add to epoll list
+ * @c: Execution context
+ * @af: Address family, AF_INET or AF_INET6
+ * @proto: Protocol number
+ * @bind_addr: Address for binding, NULL for any
+ * @ifname: Interface for binding, NULL for any
+ * @port: Port, host order
+ * @data: epoll reference portion for protocol handlers
+ *
+ * Return: newly created socket, negative error code on failure
+ */
+int sock_l4(const struct ctx *c, sa_family_t af, uint8_t proto,
+ const void *bind_addr, const char *ifname, uint16_t port,
+ uint32_t data)
+{
+ switch (af) {
+ case AF_INET: {
+ struct sockaddr_in addr4 = {
+ .sin_family = AF_INET,
+ .sin_port = htons(port),
+ { 0 }, { 0 },
+ };
+ if (bind_addr)
+ addr4.sin_addr = *(struct in_addr *)bind_addr;
+ return sock_l4_sa(c, proto, &addr4, sizeof(addr4), ifname,
+ false, data);
+ }
+
+ case AF_UNSPEC:
+ if (!DUAL_STACK_SOCKETS || bind_addr)
+ return -EINVAL;
+ /* fallthrough */
+ case AF_INET6: {
+ struct sockaddr_in6 addr6 = {
+ .sin6_family = AF_INET6,
+ .sin6_port = htons(port),
+ 0, IN6ADDR_ANY_INIT, 0,
+ };
+ if (bind_addr) {
+ addr6.sin6_addr = *(struct in6_addr *)bind_addr;
+
+ if (!memcmp(bind_addr, &c->ip6.addr_ll,
+ sizeof(c->ip6.addr_ll)))
+ addr6.sin6_scope_id = c->ifi6;
+ }
+ return sock_l4_sa(c, proto, &addr6, sizeof(addr6), ifname,
+ af == AF_INET6, data);
+ }
+ default:
+ return -EINVAL;
+ }
+}
/**
* sock_probe_mem() - Check if setting high SO_SNDBUF and SO_RCVBUF is allowed