summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/loopback-setup.c46
-rw-r--r--src/socket-util.c34
-rw-r--r--src/socket-util.h2
-rw-r--r--src/socket.c8
4 files changed, 59 insertions, 31 deletions
diff --git a/src/loopback-setup.c b/src/loopback-setup.c
index c852ed70f..a579060d8 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 151757c52..3f4d65a4c 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 6eb3b5c6e..4743c3768 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 da85ca7e8..aacf9bed9 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");