[systemd-commits] src/loopback-setup.c src/socket.c src/socket-util.c src/socket-util.h

Lennart Poettering lennart at kemper.freedesktop.org
Mon Sep 20 16:02:04 PDT 2010


 src/loopback-setup.c |   46 +++++++++++++++++++++-------------------------
 src/socket-util.c    |   34 +++++++++++++++++++++++++++++-----
 src/socket-util.h    |    2 ++
 src/socket.c         |    8 +++++++-
 4 files changed, 59 insertions(+), 31 deletions(-)

New commits:
commit 5bfcc1c6ef48af20996412dbaac1daa0492a4d41
Author: Fabiano Fidencio <fidencio at profusion.mobi>
Date:   Mon Sep 20 16:33:14 2010 -0300

    socket: Support IPv6-less systems with runtime check.
    
    This patch introduces socket_ipv6_is_supported() call that checks for
    IPv6 availability. Code then check for it before using specific calls.
    
    In order to be less intrusive, this patch avoids IPv6 entries being
    parsed at all, this way we don't get such entries in the system and
    all other code paths are automatically ignored. However an extra check
    is done at socket_address_listen() to make sure of that.
    
    As the number of Netlink messages is not know upfront anymore,
    loopback-setup.c was refactored to dynamically calculate the sequence
    number and count.
    
    Lennart's suggestions were fixed and squashed with the original patch,
    that was sent by Gustavo Sverzut Barbieri (barbieri at profusion.mobi).

diff --git a/src/loopback-setup.c b/src/loopback-setup.c
index c852ed7..a579060 100644
--- a/src/loopback-setup.c
+++ b/src/loopback-setup.c
@@ -33,14 +33,7 @@
 #include "util.h"
 #include "macro.h"
 #include "loopback-setup.h"
-
-enum {
-        REQUEST_NONE = 0,
-        REQUEST_ADDRESS_IPV4 = 1,
-        REQUEST_ADDRESS_IPV6 = 2,
-        REQUEST_FLAGS = 4,
-        REQUEST_ALL = 7
-};
+#include "socket-util.h"
 
 #define NLMSG_TAIL(nmsg)                                                \
         ((struct rtattr *) (((uint8_t*) (nmsg)) + NLMSG_ALIGN((nmsg)->nlmsg_len)))
@@ -89,7 +82,7 @@ static ssize_t recvfrom_loop(int fd, void *buf, size_t buf_len, int flags, struc
         }
 }
 
-static int add_adresses(int fd, int if_loopback) {
+static int add_adresses(int fd, int if_loopback, unsigned *requests) {
         union {
                 struct sockaddr sa;
                 struct sockaddr_nl nl;
@@ -110,7 +103,7 @@ static int add_adresses(int fd, int if_loopback) {
         request.header.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrmsg));
         request.header.nlmsg_type = RTM_NEWADDR;
         request.header.nlmsg_flags = NLM_F_REQUEST|NLM_F_CREATE|NLM_F_ACK;
-        request.header.nlmsg_seq = REQUEST_ADDRESS_IPV4;
+        request.header.nlmsg_seq = *requests + 1;
 
         ifaddrmsg = NLMSG_DATA(&request.header);
         ifaddrmsg->ifa_family = AF_INET;
@@ -127,9 +120,13 @@ static int add_adresses(int fd, int if_loopback) {
 
         if (sendto_loop(fd, &request, request.header.nlmsg_len, 0, &sa.sa, sizeof(sa)) < 0)
                 return -errno;
+        (*requests)++;
+
+        if (!socket_ipv6_is_supported())
+                return 0;
 
         request.header.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrmsg));
-        request.header.nlmsg_seq = REQUEST_ADDRESS_IPV6;
+        request.header.nlmsg_seq = *requests + 1;
 
         ifaddrmsg->ifa_family = AF_INET6;
         ifaddrmsg->ifa_prefixlen = 128;
@@ -139,11 +136,12 @@ static int add_adresses(int fd, int if_loopback) {
 
         if (sendto_loop(fd, &request, request.header.nlmsg_len, 0, &sa.sa, sizeof(sa)) < 0)
                 return -errno;
+        (*requests)++;
 
         return 0;
 }
 
-static int start_interface(int fd, int if_loopback) {
+static int start_interface(int fd, int if_loopback, unsigned *requests) {
         union {
                 struct sockaddr sa;
                 struct sockaddr_nl nl;
@@ -161,7 +159,7 @@ static int start_interface(int fd, int if_loopback) {
         request.header.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
         request.header.nlmsg_type = RTM_NEWLINK;
         request.header.nlmsg_flags = NLM_F_REQUEST|NLM_F_ACK;
-        request.header.nlmsg_seq = REQUEST_FLAGS;
+        request.header.nlmsg_seq = *requests + 1;
 
         ifinfomsg = NLMSG_DATA(&request.header);
         ifinfomsg->ifi_family = AF_UNSPEC;
@@ -175,10 +173,12 @@ static int start_interface(int fd, int if_loopback) {
         if (sendto_loop(fd, &request, request.header.nlmsg_len, 0, &sa.sa, sizeof(sa)) < 0)
                 return -errno;
 
+        (*requests)++;
+
         return 0;
 }
 
-static int read_response(int fd) {
+static int read_response(int fd, unsigned requests_max) {
         union {
                 struct sockaddr sa;
                 struct sockaddr_nl nl;
@@ -208,7 +208,7 @@ static int read_response(int fd) {
 
         if (response.header.nlmsg_type != NLMSG_ERROR ||
             (pid_t) response.header.nlmsg_pid != getpid() ||
-            response.header.nlmsg_seq >= REQUEST_ALL)
+            response.header.nlmsg_seq >= requests_max)
                 return 0;
 
         if ((size_t) l < NLMSG_LENGTH(sizeof(struct nlmsgerr)) ||
@@ -232,8 +232,7 @@ int loopback_setup(void) {
                 struct sockaddr_nl nl;
                 struct sockaddr_storage storage;
         } sa;
-        int requests = REQUEST_NONE;
-
+        unsigned requests = 0, i;
         int fd;
 
         errno = 0;
@@ -251,19 +250,16 @@ int loopback_setup(void) {
                 goto finish;
         }
 
-        if ((r = add_adresses(fd, if_loopback)) < 0)
+        if ((r = add_adresses(fd, if_loopback, &requests)) < 0)
                 goto finish;
 
-        if ((r = start_interface(fd, if_loopback)) < 0)
+        if ((r = start_interface(fd, if_loopback, &requests)) < 0)
                 goto finish;
 
-        do {
-                if ((r = read_response(fd)) < 0)
+        for (i = 0; i < requests; i++) {
+                if ((r = read_response(fd, requests)) < 0)
                         goto finish;
-
-                requests |= r;
-
-        } while (requests != REQUEST_ALL);
+        }
 
         r = 0;
 
diff --git a/src/socket-util.c b/src/socket-util.c
index 151757c..3f4d65a 100644
--- a/src/socket-util.c
+++ b/src/socket-util.c
@@ -35,6 +35,7 @@
 #include "socket-util.h"
 #include "missing.h"
 #include "label.h"
+#include <sys/ioctl.h>
 
 int socket_address_parse(SocketAddress *a, const char *s) {
         int r;
@@ -50,6 +51,11 @@ int socket_address_parse(SocketAddress *a, const char *s) {
         if (*s == '[') {
                 /* IPv6 in [x:.....:z]:p notation */
 
+                if (!socket_ipv6_is_supported()) {
+                        log_warning("Binding to IPv6 address not available since kernel does not support IPv6.");
+                        return -EAFNOSUPPORT;
+                }
+
                 if (!(e = strchr(s+1, ']')))
                         return -EINVAL;
 
@@ -145,12 +151,16 @@ int socket_address_parse(SocketAddress *a, const char *s) {
                                 if (idx == 0)
                                         return -EINVAL;
 
+                                if (!socket_ipv6_is_supported()) {
+                                        log_warning("Binding to interface is not available since kernel does not support IPv6.");
+                                        return -EAFNOSUPPORT;
+                                }
+
                                 a->sockaddr.in6.sin6_family = AF_INET6;
                                 a->sockaddr.in6.sin6_port = htons((uint16_t) u);
                                 a->sockaddr.in6.sin6_scope_id = idx;
                                 a->sockaddr.in6.sin6_addr = in6addr_any;
                                 a->size = sizeof(struct sockaddr_in6);
-
                         }
                 } else {
 
@@ -161,10 +171,17 @@ int socket_address_parse(SocketAddress *a, const char *s) {
                         if (u <= 0 || u > 0xFFFF)
                                 return -EINVAL;
 
-                        a->sockaddr.in6.sin6_family = AF_INET6;
-                        a->sockaddr.in6.sin6_port = htons((uint16_t) u);
-                        a->sockaddr.in6.sin6_addr = in6addr_any;
-                        a->size = sizeof(struct sockaddr_in6);
+                        if (socket_ipv6_is_supported()) {
+                                a->sockaddr.in6.sin6_family = AF_INET6;
+                                a->sockaddr.in6.sin6_port = htons((uint16_t) u);
+                                a->sockaddr.in6.sin6_addr = in6addr_any;
+                                a->size = sizeof(struct sockaddr_in6);
+                        } else {
+                                a->sockaddr.in4.sin_family = AF_INET;
+                                a->sockaddr.in4.sin_port = htons((uint16_t) u);
+                                a->sockaddr.in4.sin_addr.s_addr = INADDR_ANY;
+                                a->size = sizeof(struct sockaddr_in);
+                        }
                 }
         }
 
@@ -316,6 +333,9 @@ int socket_address_listen(
         if ((r = socket_address_verify(a)) < 0)
                 return r;
 
+        if (socket_address_family(a) == AF_INET6 && !socket_ipv6_is_supported())
+                return -EAFNOSUPPORT;
+
         r = label_socket_set(label);
         if (r < 0)
                 return r;
@@ -484,6 +504,10 @@ bool socket_address_needs_mount(const SocketAddress *a, const char *prefix) {
         return path_startswith(a->sockaddr.un.sun_path, prefix);
 }
 
+bool socket_ipv6_is_supported(void) {
+        return access("/sys/module/ipv6", F_OK) == 0;
+}
+
 static const char* const socket_address_bind_ipv6_only_table[_SOCKET_ADDRESS_BIND_IPV6_ONLY_MAX] = {
         [SOCKET_ADDRESS_DEFAULT] = "default",
         [SOCKET_ADDRESS_BOTH] = "both",
diff --git a/src/socket-util.h b/src/socket-util.h
index 6eb3b5c..4743c37 100644
--- a/src/socket-util.h
+++ b/src/socket-util.h
@@ -85,4 +85,6 @@ bool socket_address_needs_mount(const SocketAddress *a, const char *prefix);
 const char* socket_address_bind_ipv6_only_to_string(SocketAddressBindIPv6Only b);
 SocketAddressBindIPv6Only socket_address_bind_ipv6_only_from_string(const char *s);
 
+bool socket_ipv6_is_supported(void);
+
 #endif
diff --git a/src/socket.c b/src/socket.c
index da85ca7..aacf9be 100644
--- a/src/socket.c
+++ b/src/socket.c
@@ -634,7 +634,13 @@ static void socket_apply_socket_options(Socket *s, int fd) {
                 int r, x;
 
                 r = setsockopt(fd, IPPROTO_IP, IP_TTL, &s->ip_ttl, sizeof(s->ip_ttl));
-                x = setsockopt(fd, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &s->ip_ttl, sizeof(s->ip_ttl));
+
+                if (socket_ipv6_is_supported())
+                        x = setsockopt(fd, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &s->ip_ttl, sizeof(s->ip_ttl));
+                else {
+                        x = -1;
+                        errno = EAFNOSUPPORT;
+                }
 
                 if (r < 0 && x < 0)
                         log_warning("IP_TTL/IPV6_UNICAST_HOPS failed: %m");


More information about the systemd-commits mailing list