diff options
-rw-r--r-- | src/loopback-setup.c | 46 | ||||
-rw-r--r-- | src/socket-util.c | 34 | ||||
-rw-r--r-- | src/socket-util.h | 2 | ||||
-rw-r--r-- | src/socket.c | 8 |
4 files changed, 59 insertions, 31 deletions
diff --git a/src/loopback-setup.c b/src/loopback-setup.c index c852ed70ff..a579060d83 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 151757c52b..3f4d65a4c8 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 6eb3b5c6eb..4743c37686 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 da85ca7e8b..aacf9bed9f 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"); |