From 5d594d012da06bec9b22cac41ecea7ee77aa972b Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 18 Mar 2019 11:58:11 +0100 Subject: [PATCH 1/2] socket-util: add wrappers for binding socket to ifindex/ifname socket_bind_to_ifindex() uses the the SO_BINDTOIFINDEX sockopt of kernel 5.0, with a fallback to SO_BINDTODEVICE on older kernels. socket_bind_to_ifname() is a trivial wrapper around SO_BINDTODEVICE, the only benefit of using it instead of SO_BINDTODEVICE directly is that it determines the size of the interface name properly so that it also works for unbinding. Moreover, it's an attempt to unify our invocations of the sockopt with a size of strlen(ifname) rather than strlen(ifname)+1... --- src/basic/missing_socket.h | 4 ++++ src/basic/socket-util.c | 36 ++++++++++++++++++++++++++++++++++++ src/basic/socket-util.h | 3 +++ 3 files changed, 43 insertions(+) diff --git a/src/basic/missing_socket.h b/src/basic/missing_socket.h index a5fd457244..276be366c3 100644 --- a/src/basic/missing_socket.h +++ b/src/basic/missing_socket.h @@ -32,6 +32,10 @@ struct sockaddr_vm { #define SO_PEERGROUPS 59 #endif +#ifndef SO_BINDTOIFINDEX +#define SO_BINDTOIFINDEX 62 +#endif + #ifndef SOL_NETLINK #define SOL_NETLINK 270 #endif diff --git a/src/basic/socket-util.c b/src/basic/socket-util.c index 3c156fd659..3d929f5418 100644 --- a/src/basic/socket-util.c +++ b/src/basic/socket-util.c @@ -1354,3 +1354,39 @@ int sockaddr_un_set_path(struct sockaddr_un *ret, const char *path) { return (int) (offsetof(struct sockaddr_un, sun_path) + l + 1); /* include trailing NUL in size */ } } + +int socket_bind_to_ifname(int fd, const char *ifname) { + assert(fd >= 0); + + /* Call with NULL to drop binding */ + + if (setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, ifname, strlen_ptr(ifname)) < 0) + return -errno; + + return 0; +} + +int socket_bind_to_ifindex(int fd, int ifindex) { + char ifname[IFNAMSIZ] = ""; + + assert(fd >= 0); + + if (ifindex <= 0) { + /* Drop binding */ + if (setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, NULL, 0) < 0) + return -errno; + + return 0; + } + + if (setsockopt(fd, SOL_SOCKET, SO_BINDTOIFINDEX, &ifindex, sizeof(ifindex)) >= 0) + return 0; + if (errno != ENOPROTOOPT) + return -errno; + + /* Fall back to SO_BINDTODEVICE on kernels < 5.0 which didn't have SO_BINDTOIFINDEX */ + if (!if_indextoname(ifindex, ifname)) + return -errno; + + return socket_bind_to_ifname(fd, ifname); +} diff --git a/src/basic/socket-util.h b/src/basic/socket-util.h index 574d2b73f5..6920fd99ba 100644 --- a/src/basic/socket-util.h +++ b/src/basic/socket-util.h @@ -198,3 +198,6 @@ static inline int setsockopt_int(int fd, int level, int optname, int value) { return 0; } + +int socket_bind_to_ifname(int fd, const char *ifname); +int socket_bind_to_ifindex(int fd, int ifindex); From 953a02d11bed5f1b01e3f37a4bb17a5464d3a2ba Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 18 Mar 2019 12:01:02 +0100 Subject: [PATCH 2/2] tree-wide: port various users over to socket_bind_to_ifindex() --- src/basic/socket-label.c | 8 +++++--- src/libsystemd-network/dhcp-network.c | 8 ++------ src/libsystemd-network/icmp6-util.c | 12 ++++-------- src/resolve/resolved-dns-stub.c | 10 ++++++---- 4 files changed, 17 insertions(+), 21 deletions(-) diff --git a/src/basic/socket-label.c b/src/basic/socket-label.c index 4ed19cd937..b5e9b374c0 100644 --- a/src/basic/socket-label.c +++ b/src/basic/socket-label.c @@ -68,9 +68,11 @@ int socket_address_listen( } if (IN_SET(socket_address_family(a), AF_INET, AF_INET6)) { - if (bind_to_device) - if (setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, bind_to_device, strlen(bind_to_device)+1) < 0) - return -errno; + if (bind_to_device) { + r = socket_bind_to_ifname(fd, bind_to_device); + if (r < 0) + return r; + } if (reuse_port) { r = setsockopt_int(fd, SOL_SOCKET, SO_REUSEPORT, true); diff --git a/src/libsystemd-network/dhcp-network.c b/src/libsystemd-network/dhcp-network.c index b62eed0dd4..94c10ed14c 100644 --- a/src/libsystemd-network/dhcp-network.c +++ b/src/libsystemd-network/dhcp-network.c @@ -153,7 +153,6 @@ int dhcp_network_bind_udp_socket(int ifindex, be32_t address, uint16_t port) { .in.sin_addr.s_addr = address, }; _cleanup_close_ int s = -1; - char ifname[IF_NAMESIZE] = ""; int r; s = socket(AF_INET, SOCK_DGRAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0); @@ -169,12 +168,9 @@ int dhcp_network_bind_udp_socket(int ifindex, be32_t address, uint16_t port) { return r; if (ifindex > 0) { - if (if_indextoname(ifindex, ifname) == 0) - return -errno; - - r = setsockopt(s, SOL_SOCKET, SO_BINDTODEVICE, ifname, strlen(ifname)); + r = socket_bind_to_ifindex(s, ifindex); if (r < 0) - return -errno; + return r; } if (address == INADDR_ANY) { diff --git a/src/libsystemd-network/icmp6-util.c b/src/libsystemd-network/icmp6-util.c index e535b12cda..e1f193ab24 100644 --- a/src/libsystemd-network/icmp6-util.c +++ b/src/libsystemd-network/icmp6-util.c @@ -31,9 +31,8 @@ static int icmp6_bind_router_message(const struct icmp6_filter *filter, const struct ipv6_mreq *mreq) { - int index = mreq->ipv6mr_interface; + int ifindex = mreq->ipv6mr_interface; _cleanup_close_ int s = -1; - char ifname[IF_NAMESIZE] = ""; int r; s = socket(AF_INET6, SOCK_RAW | SOCK_CLOEXEC | SOCK_NONBLOCK, IPPROTO_ICMPV6); @@ -52,7 +51,7 @@ static int icmp6_bind_router_message(const struct icmp6_filter *filter, IPV6_PKTINFO socket option also applies for ICMPv6 multicast. Empirical experiments indicates otherwise and therefore an IPV6_MULTICAST_IF socket option is used here instead */ - r = setsockopt_int(s, IPPROTO_IPV6, IPV6_MULTICAST_IF, index); + r = setsockopt_int(s, IPPROTO_IPV6, IPV6_MULTICAST_IF, ifindex); if (r < 0) return r; @@ -76,12 +75,9 @@ static int icmp6_bind_router_message(const struct icmp6_filter *filter, if (r < 0) return r; - if (if_indextoname(index, ifname) == 0) - return -errno; - - r = setsockopt(s, SOL_SOCKET, SO_BINDTODEVICE, ifname, strlen(ifname)); + r = socket_bind_to_ifindex(s, ifindex); if (r < 0) - return -errno; + return r; return TAKE_FD(s); } diff --git a/src/resolve/resolved-dns-stub.c b/src/resolve/resolved-dns-stub.c index 2bf04db4c5..65c809490f 100644 --- a/src/resolve/resolved-dns-stub.c +++ b/src/resolve/resolved-dns-stub.c @@ -421,8 +421,9 @@ static int manager_dns_stub_udp_fd(Manager *m) { return r; /* Make sure no traffic from outside the local host can leak to onto this socket */ - if (setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, "lo", 3) < 0) - return -errno; + r = socket_bind_to_ifindex(fd, LOOPBACK_IFINDEX); + if (r < 0) + return r; if (bind(fd, &sa.sa, sizeof(sa.in)) < 0) return -errno; @@ -514,8 +515,9 @@ static int manager_dns_stub_tcp_fd(Manager *m) { return r; /* Make sure no traffic from outside the local host can leak to onto this socket */ - if (setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, "lo", 3) < 0) - return -errno; + r = socket_bind_to_ifindex(fd, LOOPBACK_IFINDEX); + if (r < 0) + return r; if (bind(fd, &sa.sa, sizeof(sa.in)) < 0) return -errno;