]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
socket-util: add wrappers for binding socket to ifindex/ifname
authorLennart Poettering <lennart@poettering.net>
Mon, 18 Mar 2019 10:58:11 +0000 (11:58 +0100)
committerLennart Poettering <lennart@poettering.net>
Mon, 18 Mar 2019 11:02:32 +0000 (12:02 +0100)
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
src/basic/socket-util.c
src/basic/socket-util.h

index a5fd457244b25757a7d43141f3c6d1805ba5a21e..276be366c3d742ddbee34a15a53f141410a7e061 100644 (file)
@@ -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
index 3c156fd659ce470e134fc92d529bc41cbac34a7d..3d929f5418dcda72f1391f605473bb8756a9d942 100644 (file)
@@ -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);
+}
index 574d2b73f5627e8dc52194a8ac4cbd3996bfbad5..6920fd99ba5d4ac27a67eae8ebeb607777e42a38 100644 (file)
@@ -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);