diff --git a/man/systemd.socket.xml b/man/systemd.socket.xml
index 1bcbef2033..253da8a6d4 100644
--- a/man/systemd.socket.xml
+++ b/man/systemd.socket.xml
@@ -200,22 +200,24 @@
If the address string is a string in the format
- v.w.x.y:z, it is read as IPv4 specifier for listening on an
- address v.w.x.y on a port z.
-
- If the address string is a string in the format [x]:y,
- it is read as IPv6 address x on a port y. Note that this might
- make the service available via IPv4, too, depending on the
- BindIPv6Only= setting (see below).
-
+ v.w.x.y:z, it is interpeted
+ as IPv4 address v.w.x.y and port z.
If the address string is a string in the format
- vsock:x:y, it is read as CID x on
- a port y address in the
- AF_VSOCK family. The CID is a unique 32-bit
- integer identifier in AF_VSOCK analogous to an IP
- address. Specifying the CID is optional, and may be set to the empty
- string.
+ [x]:y, it is interpreted as
+ IPv6 address x and port y. An optional
+ interface scope (interface name or number) may be specifed after a % symbol:
+ [x]:y%dev.
+ Interface scopes are only useful with link-local addresses, because the kernel ignores them in other
+ cases. Note that if an address is specified as IPv6, it might still make the service available via
+ IPv4 too, depending on the BindIPv6Only= setting (see below).
+
+ If the address string is a string in the format
+ vsock:x:y, it is read as CID
+ x on a port y address in the
+ AF_VSOCK family. The CID is a unique 32-bit integer identifier in
+ AF_VSOCK analogous to an IP address. Specifying the CID is optional, and may be
+ set to the empty string.
Note that SOCK_SEQPACKET (i.e.
ListenSequentialPacket=) is only available
diff --git a/src/basic/socket-util.c b/src/basic/socket-util.c
index 4b3a4f206c..7a3299672a 100644
--- a/src/basic/socket-util.c
+++ b/src/basic/socket-util.c
@@ -68,7 +68,7 @@ int socket_address_verify(const SocketAddress *a, bool strict) {
if (a->sockaddr.in.sin_port == 0)
return -EINVAL;
- if (!IN_SET(a->type, SOCK_STREAM, SOCK_DGRAM))
+ if (!IN_SET(a->type, 0, SOCK_STREAM, SOCK_DGRAM))
return -EINVAL;
return 0;
@@ -80,7 +80,7 @@ int socket_address_verify(const SocketAddress *a, bool strict) {
if (a->sockaddr.in6.sin6_port == 0)
return -EINVAL;
- if (!IN_SET(a->type, SOCK_STREAM, SOCK_DGRAM))
+ if (!IN_SET(a->type, 0, SOCK_STREAM, SOCK_DGRAM))
return -EINVAL;
return 0;
@@ -114,7 +114,7 @@ int socket_address_verify(const SocketAddress *a, bool strict) {
}
}
- if (!IN_SET(a->type, SOCK_STREAM, SOCK_DGRAM, SOCK_SEQPACKET))
+ if (!IN_SET(a->type, 0, SOCK_STREAM, SOCK_DGRAM, SOCK_SEQPACKET))
return -EINVAL;
return 0;
@@ -124,7 +124,7 @@ int socket_address_verify(const SocketAddress *a, bool strict) {
if (a->size != sizeof(struct sockaddr_nl))
return -EINVAL;
- if (!IN_SET(a->type, SOCK_RAW, SOCK_DGRAM))
+ if (!IN_SET(a->type, 0, SOCK_RAW, SOCK_DGRAM))
return -EINVAL;
return 0;
@@ -133,7 +133,7 @@ int socket_address_verify(const SocketAddress *a, bool strict) {
if (a->size != sizeof(struct sockaddr_vm))
return -EINVAL;
- if (!IN_SET(a->type, SOCK_STREAM, SOCK_DGRAM))
+ if (!IN_SET(a->type, 0, SOCK_STREAM, SOCK_DGRAM))
return -EINVAL;
return 0;
@@ -399,19 +399,23 @@ int sockaddr_pretty(
if (r < 0)
return -ENOMEM;
} else {
- char a[INET6_ADDRSTRLEN];
+ char a[INET6_ADDRSTRLEN], ifname[IF_NAMESIZE + 1];
inet_ntop(AF_INET6, &sa->in6.sin6_addr, a, sizeof(a));
+ if (sa->in6.sin6_scope_id != 0)
+ format_ifname_full(sa->in6.sin6_scope_id, ifname, FORMAT_IFNAME_IFINDEX);
if (include_port) {
r = asprintf(&p,
- "[%s]:%u",
+ "[%s]:%u%s%s",
a,
- be16toh(sa->in6.sin6_port));
+ be16toh(sa->in6.sin6_port),
+ sa->in6.sin6_scope_id != 0 ? "%" : "",
+ sa->in6.sin6_scope_id != 0 ? ifname : "");
if (r < 0)
return -ENOMEM;
} else {
- p = strdup(a);
+ p = sa->in6.sin6_scope_id != 0 ? strjoin(a, "%", ifname) : strdup(a);
if (!p)
return -ENOMEM;
}
@@ -686,17 +690,19 @@ static const char* const ip_tos_table[] = {
DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(ip_tos, int, 0xff);
-bool ifname_valid_full(const char *p, bool alternative) {
+bool ifname_valid_full(const char *p, IfnameValidFlags flags) {
bool numeric = true;
/* Checks whether a network interface name is valid. This is inspired by dev_valid_name() in the kernel sources
* but slightly stricter, as we only allow non-control, non-space ASCII characters in the interface name. We
* also don't permit names that only container numbers, to avoid confusion with numeric interface indexes. */
+ assert(!(flags & ~_IFNAME_VALID_ALL));
+
if (isempty(p))
return false;
- if (alternative) {
+ if (flags & IFNAME_VALID_ALTERNATIVE) {
if (strlen(p) >= ALTIFNAMSIZ)
return false;
} else {
@@ -707,22 +713,27 @@ bool ifname_valid_full(const char *p, bool alternative) {
if (dot_or_dot_dot(p))
return false;
- while (*p) {
- if ((unsigned char) *p >= 127U)
+ for (const char *t = p; *t; t++) {
+ if ((unsigned char) *t >= 127U)
return false;
- if ((unsigned char) *p <= 32U)
+ if ((unsigned char) *t <= 32U)
return false;
- if (IN_SET(*p, ':', '/'))
+ if (IN_SET(*t, ':', '/'))
return false;
- numeric = numeric && (*p >= '0' && *p <= '9');
- p++;
+ numeric = numeric && (*t >= '0' && *t <= '9');
}
- if (numeric)
- return false;
+ if (numeric) {
+ if (!(flags & IFNAME_VALID_NUMERIC))
+ return false;
+
+ /* Verify that the number is well-formatted and in range. */
+ if (parse_ifindex(p) < 0)
+ return false;
+ }
return true;
}
@@ -1107,12 +1118,10 @@ int sockaddr_un_set_path(struct sockaddr_un *ret, const char *path) {
* reference paths in the abstract namespace that include NUL bytes in the name. */
l = strlen(path);
- if (l == 0)
+ if (l < 2)
return -EINVAL;
if (!IN_SET(path[0], '/', '@'))
return -EINVAL;
- if (path[1] == 0)
- return -EINVAL;
/* Don't allow paths larger than the space in sockaddr_un. Note that we are a tiny bit more restrictive than
* the kernel is: we insist on NUL termination (both for abstract namespace and regular file system socket
diff --git a/src/basic/socket-util.h b/src/basic/socket-util.h
index 6a320a976f..fee9055cec 100644
--- a/src/basic/socket-util.h
+++ b/src/basic/socket-util.h
@@ -130,9 +130,14 @@ static inline int fd_inc_rcvbuf(int fd, size_t n) {
int ip_tos_to_string_alloc(int i, char **s);
int ip_tos_from_string(const char *s);
-bool ifname_valid_full(const char *p, bool alternative);
+typedef enum {
+ IFNAME_VALID_ALTERNATIVE = 1 << 0,
+ IFNAME_VALID_NUMERIC = 1 << 1,
+ _IFNAME_VALID_ALL = IFNAME_VALID_ALTERNATIVE | IFNAME_VALID_NUMERIC,
+} IfnameValidFlags;
+bool ifname_valid_full(const char *p, IfnameValidFlags flags);
static inline bool ifname_valid(const char *p) {
- return ifname_valid_full(p, false);
+ return ifname_valid_full(p, 0);
}
bool address_label_valid(const char *p);
diff --git a/src/network/networkd-network-gperf.gperf b/src/network/networkd-network-gperf.gperf
index 3f1652b190..d07714f5a1 100644
--- a/src/network/networkd-network-gperf.gperf
+++ b/src/network/networkd-network-gperf.gperf
@@ -39,7 +39,7 @@ Match.Type, config_parse_match_strv,
Match.WLANInterfaceType, config_parse_match_strv, 0, offsetof(Network, match_wlan_iftype)
Match.SSID, config_parse_match_strv, 0, offsetof(Network, match_ssid)
Match.BSSID, config_parse_hwaddrs, 0, offsetof(Network, match_bssid)
-Match.Name, config_parse_match_ifnames, 1, offsetof(Network, match_name)
+Match.Name, config_parse_match_ifnames, IFNAME_VALID_ALTERNATIVE, offsetof(Network, match_name)
Match.Property, config_parse_match_property, 0, offsetof(Network, match_property)
Match.Host, config_parse_net_condition, CONDITION_HOST, offsetof(Network, conditions)
Match.Virtualization, config_parse_net_condition, CONDITION_VIRTUALIZATION, offsetof(Network, conditions)
diff --git a/src/resolve/resolved-conf.c b/src/resolve/resolved-conf.c
index 00cea964b4..0b7c5c8fc9 100644
--- a/src/resolve/resolved-conf.c
+++ b/src/resolve/resolved-conf.c
@@ -35,9 +35,6 @@ static int manager_add_dns_server_by_string(Manager *m, DnsServerType type, cons
if (r < 0)
return r;
- if (IN_SET(port, 53, 853))
- port = 0;
-
/* Silently filter out 0.0.0.0 and 127.0.0.53 (our own stub DNS listener) */
if (!dns_server_address_valid(family, &address))
return 0;
@@ -50,12 +47,8 @@ static int manager_add_dns_server_by_string(Manager *m, DnsServerType type, cons
/* Filter out duplicates */
s = dns_server_find(manager_get_first_dns_server(m, type), family, &address, port, ifindex, server_name);
if (s) {
- /*
- * Drop the marker. This is used to find the servers
- * that ceased to exist, see
- * manager_mark_dns_servers() and
- * manager_flush_marked_dns_servers().
- */
+ /* Drop the marker. This is used to find the servers that ceased to exist, see
+ * manager_mark_dns_servers() and manager_flush_marked_dns_servers(). */
dns_server_move_back_and_unmark(s);
return 0;
}
@@ -447,7 +440,7 @@ int config_parse_dns_stub_listener_extra(
}
}
- r = in_addr_port_from_string_auto(p, &stub->family, &stub->address, &stub->port);
+ r = in_addr_port_ifindex_name_from_string_auto(p, &stub->family, &stub->address, &stub->port, NULL, NULL);
if (r < 0) {
log_syntax(unit, LOG_WARNING, filename, line, r,
"Failed to parse address in %s=%s, ignoring assignment: %m",
diff --git a/src/resolve/resolved-dns-stub.c b/src/resolve/resolved-dns-stub.c
index 59ced33847..572be26c2d 100644
--- a/src/resolve/resolved-dns-stub.c
+++ b/src/resolve/resolved-dns-stub.c
@@ -15,7 +15,7 @@
* IP and UDP header sizes */
#define ADVERTISE_DATAGRAM_SIZE_MAX (65536U-14U-20U-8U)
-static int manager_dns_stub_udp_fd_extra(Manager *m, DnsStubListenerExtra *l);
+static int manager_dns_stub_fd_extra(Manager *m, DnsStubListenerExtra *l, int type);
static void dns_stub_listener_extra_hash_func(const DnsStubListenerExtra *a, struct siphash *state) {
assert(a);
@@ -217,7 +217,7 @@ static int dns_stub_send(
* is because otherwise the kernel will choose it automatically based on the routing table and will
* thus pick 127.0.0.1 rather than 127.0.0.53. */
r = manager_send(m,
- manager_dns_stub_udp_fd_extra(m, l),
+ manager_dns_stub_fd_extra(m, l, SOCK_DGRAM),
l ? p->ifindex : LOOPBACK_IFINDEX, /* force loopback iface if this is the main listener stub */
p->family, &p->sender, p->sender_port, &p->destination,
reply);
@@ -477,151 +477,6 @@ static int on_dns_stub_packet_extra(sd_event_source *s, int fd, uint32_t revents
return on_dns_stub_packet_internal(s, fd, revents, l->manager, l);
}
-static int set_dns_stub_common_socket_options(int fd, int family) {
- int r;
-
- assert(fd >= 0);
- assert(IN_SET(family, AF_INET, AF_INET6));
-
- r = setsockopt_int(fd, SOL_SOCKET, SO_REUSEADDR, true);
- if (r < 0)
- return r;
-
- if (family == AF_INET) {
- r = setsockopt_int(fd, IPPROTO_IP, IP_PKTINFO, true);
- if (r < 0)
- return r;
-
- r = setsockopt_int(fd, IPPROTO_IP, IP_RECVTTL, true);
- if (r < 0)
- return r;
- } else {
- r = setsockopt_int(fd, IPPROTO_IPV6, IPV6_RECVPKTINFO, true);
- if (r < 0)
- return r;
-
- r = setsockopt_int(fd, IPPROTO_IPV6, IPV6_RECVHOPLIMIT, true);
- if (r < 0)
- return r;
- }
-
- return 0;
-}
-
-static int manager_dns_stub_udp_fd(Manager *m) {
- union sockaddr_union sa = {
- .in.sin_family = AF_INET,
- .in.sin_port = htobe16(53),
- .in.sin_addr.s_addr = htobe32(INADDR_DNS_STUB),
- };
- _cleanup_close_ int fd = -1;
- int r;
-
- if (m->dns_stub_udp_event_source)
- return sd_event_source_get_io_fd(m->dns_stub_udp_event_source);
-
- fd = socket(AF_INET, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
- if (fd < 0)
- return -errno;
-
- r = set_dns_stub_common_socket_options(fd, AF_INET);
- if (r < 0)
- return r;
-
- /* Make sure no traffic from outside the local host can leak to onto this socket */
- r = socket_bind_to_ifindex(fd, LOOPBACK_IFINDEX);
- if (r < 0)
- return r;
-
- if (bind(fd, &sa.sa, sizeof(sa.in)) < 0)
- return -errno;
-
- r = sd_event_add_io(m->event, &m->dns_stub_udp_event_source, fd, EPOLLIN, on_dns_stub_packet, m);
- if (r < 0)
- return r;
-
- r = sd_event_source_set_io_fd_own(m->dns_stub_udp_event_source, true);
- if (r < 0)
- return r;
-
- (void) sd_event_source_set_description(m->dns_stub_udp_event_source, "dns-stub-udp");
-
- return TAKE_FD(fd);
-}
-
-static int manager_dns_stub_udp_fd_extra(Manager *m, DnsStubListenerExtra *l) {
- _cleanup_free_ char *pretty = NULL;
- _cleanup_close_ int fd = -1;
- union sockaddr_union sa;
- int r;
-
- assert(m);
-
- if (!l)
- return manager_dns_stub_udp_fd(m);
-
- if (l->udp_event_source)
- return 0;
-
- if (l->family == AF_INET)
- sa = (union sockaddr_union) {
- .in.sin_family = l->family,
- .in.sin_port = htobe16(l->port != 0 ? l->port : 53U),
- .in.sin_addr = l->address.in,
- };
- else
- sa = (union sockaddr_union) {
- .in6.sin6_family = l->family,
- .in6.sin6_port = htobe16(l->port != 0 ? l->port : 53U),
- .in6.sin6_addr = l->address.in6,
- };
-
- fd = socket(l->family, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
- if (fd < 0) {
- r = -errno;
- goto fail;
- }
-
- if (l->family == AF_INET) {
- r = setsockopt_int(fd, IPPROTO_IP, IP_FREEBIND, true);
- if (r < 0)
- goto fail;
- }
-
- r = set_dns_stub_common_socket_options(fd, l->family);
- if (r < 0)
- goto fail;
-
- if (bind(fd, &sa.sa, SOCKADDR_LEN(sa)) < 0) {
- r = -errno;
- goto fail;
- }
-
- r = sd_event_add_io(m->event, &l->udp_event_source, fd, EPOLLIN, on_dns_stub_packet_extra, l);
- if (r < 0)
- goto fail;
-
- r = sd_event_source_set_io_fd_own(l->udp_event_source, true);
- if (r < 0)
- goto fail;
-
- (void) sd_event_source_set_description(l->udp_event_source, "dns-stub-udp-extra");
-
- if (DEBUG_LOGGING) {
- (void) in_addr_port_to_string(l->family, &l->address, l->port, &pretty);
- log_debug("Listening on UDP socket %s.", strnull(pretty));
- }
-
- return TAKE_FD(fd);
-
-fail:
- assert(r < 0);
- (void) in_addr_port_to_string(l->family, &l->address, l->port, &pretty);
- if (r == -EADDRINUSE)
- return log_warning_errno(r, "Another process is already listening on UDP socket %s: %m", strnull(pretty));
- return log_warning_errno(r, "Failed to listen on UDP socket %s: %m", strnull(pretty));
-}
-
static int on_dns_stub_stream_packet(DnsStream *s) {
_cleanup_(dns_packet_unrefp) DnsPacket *p = NULL;
@@ -678,7 +533,38 @@ static int on_dns_stub_stream_extra(sd_event_source *s, int fd, uint32_t revents
return on_dns_stub_stream_internal(s, fd, revents, l->manager, l);
}
-static int manager_dns_stub_tcp_fd(Manager *m) {
+static int set_dns_stub_common_socket_options(int fd, int family) {
+ int r;
+
+ assert(fd >= 0);
+ assert(IN_SET(family, AF_INET, AF_INET6));
+
+ r = setsockopt_int(fd, SOL_SOCKET, SO_REUSEADDR, true);
+ if (r < 0)
+ return r;
+
+ if (family == AF_INET) {
+ r = setsockopt_int(fd, IPPROTO_IP, IP_PKTINFO, true);
+ if (r < 0)
+ return r;
+
+ r = setsockopt_int(fd, IPPROTO_IP, IP_RECVTTL, true);
+ if (r < 0)
+ return r;
+ } else {
+ r = setsockopt_int(fd, IPPROTO_IPV6, IPV6_RECVPKTINFO, true);
+ if (r < 0)
+ return r;
+
+ r = setsockopt_int(fd, IPPROTO_IPV6, IPV6_RECVHOPLIMIT, true);
+ if (r < 0)
+ return r;
+ }
+
+ return 0;
+}
+
+static int manager_dns_stub_fd(Manager *m, int type) {
union sockaddr_union sa = {
.in.sin_family = AF_INET,
.in.sin_addr.s_addr = htobe32(INADDR_DNS_STUB),
@@ -687,10 +573,13 @@ static int manager_dns_stub_tcp_fd(Manager *m) {
_cleanup_close_ int fd = -1;
int r;
- if (m->dns_stub_tcp_event_source)
- return sd_event_source_get_io_fd(m->dns_stub_tcp_event_source);
+ assert(IN_SET(type, SOCK_DGRAM, SOCK_STREAM));
- fd = socket(AF_INET, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
+ sd_event_source **event_source = type == SOCK_DGRAM ? &m->dns_stub_udp_event_source : &m->dns_stub_tcp_event_source;
+ if (*event_source)
+ return sd_event_source_get_io_fd(*event_source);
+
+ fd = socket(AF_INET, type | SOCK_CLOEXEC | SOCK_NONBLOCK, 0);
if (fd < 0)
return -errno;
@@ -698,42 +587,53 @@ static int manager_dns_stub_tcp_fd(Manager *m) {
if (r < 0)
return r;
- r = setsockopt_int(fd, IPPROTO_IP, IP_TTL, 1);
- if (r < 0)
- return r;
-
/* Make sure no traffic from outside the local host can leak to onto this socket */
r = socket_bind_to_ifindex(fd, LOOPBACK_IFINDEX);
if (r < 0)
return r;
+ r = setsockopt_int(fd, IPPROTO_IP, IP_TTL, 1);
+ if (r < 0)
+ return r;
+
if (bind(fd, &sa.sa, sizeof(sa.in)) < 0)
return -errno;
- if (listen(fd, SOMAXCONN) < 0)
+ if (type == SOCK_STREAM &&
+ listen(fd, SOMAXCONN) < 0)
return -errno;
- r = sd_event_add_io(m->event, &m->dns_stub_tcp_event_source, fd, EPOLLIN, on_dns_stub_stream, m);
+ r = sd_event_add_io(m->event, event_source, fd, EPOLLIN,
+ type == SOCK_DGRAM ? on_dns_stub_packet : on_dns_stub_stream,
+ m);
if (r < 0)
return r;
- r = sd_event_source_set_io_fd_own(m->dns_stub_tcp_event_source, true);
+ r = sd_event_source_set_io_fd_own(*event_source, true);
if (r < 0)
return r;
- (void) sd_event_source_set_description(m->dns_stub_tcp_event_source, "dns-stub-tcp");
+ (void) sd_event_source_set_description(*event_source,
+ type == SOCK_DGRAM ? "dns-stub-udp" : "dns-stub-tcp");
return TAKE_FD(fd);
}
-static int manager_dns_stub_tcp_fd_extra(Manager *m, DnsStubListenerExtra *l) {
+static int manager_dns_stub_fd_extra(Manager *m, DnsStubListenerExtra *l, int type) {
_cleanup_free_ char *pretty = NULL;
_cleanup_close_ int fd = -1;
union sockaddr_union sa;
int r;
- if (l->tcp_event_source)
- return sd_event_source_get_io_fd(l->tcp_event_source);;
+ assert(m);
+ assert(IN_SET(type, SOCK_DGRAM, SOCK_STREAM));
+
+ if (!l)
+ return manager_dns_stub_fd(m, type);
+
+ sd_event_source **event_source = type == SOCK_DGRAM ? &l->udp_event_source : &l->tcp_event_source;
+ if (*event_source)
+ return sd_event_source_get_io_fd(*event_source);
if (l->family == AF_INET)
sa = (union sockaddr_union) {
@@ -748,7 +648,7 @@ static int manager_dns_stub_tcp_fd_extra(Manager *m, DnsStubListenerExtra *l) {
.in6.sin6_addr = l->address.in6,
};
- fd = socket(l->family, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
+ fd = socket(l->family, type | SOCK_CLOEXEC | SOCK_NONBLOCK, 0);
if (fd < 0) {
r = -errno;
goto fail;
@@ -758,8 +658,8 @@ static int manager_dns_stub_tcp_fd_extra(Manager *m, DnsStubListenerExtra *l) {
if (r < 0)
goto fail;
- /* Do not set IP_TTL for extra DNS stub listners, as the address may not be local and in that
- * case people may want ttl > 1. */
+ /* Do not set IP_TTL for extra DNS stub listners, as the address may not be local and in that case
+ * people may want ttl > 1. */
if (l->family == AF_INET)
r = setsockopt_int(fd, IPPROTO_IP, IP_FREEBIND, true);
@@ -773,24 +673,30 @@ static int manager_dns_stub_tcp_fd_extra(Manager *m, DnsStubListenerExtra *l) {
goto fail;
}
- if (listen(fd, SOMAXCONN) < 0) {
+ if (type == SOCK_STREAM &&
+ listen(fd, SOMAXCONN) < 0) {
r = -errno;
goto fail;
}
- r = sd_event_add_io(m->event, &l->tcp_event_source, fd, EPOLLIN, on_dns_stub_stream_extra, l);
+ r = sd_event_add_io(m->event, event_source, fd, EPOLLIN,
+ type == SOCK_DGRAM ? on_dns_stub_packet_extra : on_dns_stub_stream_extra,
+ l);
if (r < 0)
goto fail;
- r = sd_event_source_set_io_fd_own(l->tcp_event_source, true);
+ r = sd_event_source_set_io_fd_own(*event_source, true);
if (r < 0)
goto fail;
- (void) sd_event_source_set_description(l->tcp_event_source, "dns-stub-tcp-extra");
+ (void) sd_event_source_set_description(*event_source,
+ type == SOCK_DGRAM ? "dns-stub-udp-extra" : "dns-stub-tcp-extra");
if (DEBUG_LOGGING) {
(void) in_addr_port_to_string(l->family, &l->address, l->port, &pretty);
- log_debug("Listening on TCP socket %s.", strnull(pretty));
+ log_debug("Listening on %s socket %s.",
+ type == SOCK_DGRAM ? "UDP" : "TCP",
+ strnull(pretty));
}
return TAKE_FD(fd);
@@ -798,9 +704,11 @@ static int manager_dns_stub_tcp_fd_extra(Manager *m, DnsStubListenerExtra *l) {
fail:
assert(r < 0);
(void) in_addr_port_to_string(l->family, &l->address, l->port, &pretty);
- if (r == -EADDRINUSE)
- return log_warning_errno(r, "Another process is already listening on TCP socket %s: %m", strnull(pretty));
- return log_warning_errno(r, "Failed to listen on TCP socket %s: %m", strnull(pretty));
+ return log_warning_errno(r,
+ r == -EADDRINUSE ? "Another process is already listening on %s socket %s: %m" :
+ "Failed to listen on %s socket %s: %m",
+ type == SOCK_DGRAM ? "UDP" : "TCP",
+ strnull(pretty));
}
int manager_dns_stub_start(Manager *m) {
@@ -818,23 +726,21 @@ int manager_dns_stub_start(Manager *m) {
"UDP/TCP");
if (FLAGS_SET(m->dns_stub_listener_mode, DNS_STUB_LISTENER_UDP))
- r = manager_dns_stub_udp_fd(m);
+ r = manager_dns_stub_fd(m, SOCK_DGRAM);
if (r >= 0 &&
FLAGS_SET(m->dns_stub_listener_mode, DNS_STUB_LISTENER_TCP)) {
t = "TCP";
- r = manager_dns_stub_tcp_fd(m);
+ r = manager_dns_stub_fd(m, SOCK_STREAM);
}
if (IN_SET(r, -EADDRINUSE, -EPERM)) {
- if (r == -EADDRINUSE)
- log_warning_errno(r,
- "Another process is already listening on %s socket 127.0.0.53:53.\n"
- "Turning off local DNS stub support.", t);
- else
- log_warning_errno(r,
- "Failed to listen on %s socket 127.0.0.53:53: %m.\n"
- "Turning off local DNS stub support.", t);
+ log_warning_errno(r,
+ r == -EADDRINUSE ? "Another process is already listening on %s socket 127.0.0.53:53.\n"
+ "Turning off local DNS stub support." :
+ "Failed to listen on %s socket 127.0.0.53:53: %m.\n"
+ "Turning off local DNS stub support.",
+ t);
manager_dns_stub_stop(m);
} else if (r < 0)
return log_error_errno(r, "Failed to listen on %s socket 127.0.0.53:53: %m", t);
@@ -846,9 +752,9 @@ int manager_dns_stub_start(Manager *m) {
ORDERED_SET_FOREACH(l, m->dns_extra_stub_listeners) {
if (FLAGS_SET(l->mode, DNS_STUB_LISTENER_UDP))
- (void) manager_dns_stub_udp_fd_extra(m, l);
+ (void) manager_dns_stub_fd_extra(m, l, SOCK_DGRAM);
if (FLAGS_SET(l->mode, DNS_STUB_LISTENER_TCP))
- (void) manager_dns_stub_tcp_fd_extra(m, l);
+ (void) manager_dns_stub_fd_extra(m, l, SOCK_STREAM);
}
}
diff --git a/src/shared/socket-netlink.c b/src/shared/socket-netlink.c
index 6c121a4c9a..23970dbe55 100644
--- a/src/shared/socket-netlink.c
+++ b/src/shared/socket-netlink.c
@@ -62,75 +62,23 @@ int socket_address_parse(SocketAddress *a, const char *s) {
assert(a);
assert(s);
- *a = (SocketAddress) {
- .type = SOCK_STREAM,
- };
+ if (IN_SET(*s, '/', '@')) {
+ /* AF_UNIX socket */
+ struct sockaddr_un un;
- if (*s == '[') {
- uint16_t port;
-
- /* IPv6 in [x:.....:z]:p notation */
-
- e = strchr(s+1, ']');
- if (!e)
- return -EINVAL;
-
- n = strndup(s+1, e-s-1);
- if (!n)
- return -ENOMEM;
-
- errno = 0;
- if (inet_pton(AF_INET6, n, &a->sockaddr.in6.sin6_addr) <= 0)
- return errno_or_else(EINVAL);
-
- e++;
- if (*e != ':')
- return -EINVAL;
-
- e++;
- r = parse_ip_port(e, &port);
+ r = sockaddr_un_set_path(&un, s);
if (r < 0)
return r;
- a->sockaddr.in6.sin6_family = AF_INET6;
- a->sockaddr.in6.sin6_port = htobe16(port);
- a->size = sizeof(struct sockaddr_in6);
-
- } else if (*s == '/') {
- /* AF_UNIX socket */
-
- size_t l;
-
- l = strlen(s);
- if (l >= sizeof(a->sockaddr.un.sun_path)) /* Note that we refuse non-NUL-terminated sockets when
- * parsing (the kernel itself is less strict here in what it
- * accepts) */
- return -EINVAL;
-
- a->sockaddr.un.sun_family = AF_UNIX;
- memcpy(a->sockaddr.un.sun_path, s, l);
- a->size = offsetof(struct sockaddr_un, sun_path) + l + 1;
-
- } else if (*s == '@') {
- /* Abstract AF_UNIX socket */
- size_t l;
-
- l = strlen(s+1);
- if (l >= sizeof(a->sockaddr.un.sun_path) - 1) /* Note that we refuse non-NUL-terminated sockets here
- * when parsing, even though abstract namespace sockets
- * explicitly allow embedded NUL bytes and don't consider
- * them special. But it's simply annoying to debug such
- * sockets. */
- return -EINVAL;
-
- a->sockaddr.un.sun_family = AF_UNIX;
- memcpy(a->sockaddr.un.sun_path+1, s+1, l);
- a->size = offsetof(struct sockaddr_un, sun_path) + 1 + l;
+ *a = (SocketAddress) {
+ .sockaddr.un = un,
+ .size = r,
+ };
} else if (startswith(s, "vsock:")) {
/* AF_VSOCK socket in vsock:cid:port notation */
const char *cid_start = s + STRLEN("vsock:");
- unsigned port;
+ unsigned port, cid;
e = strchr(cid_start, ':');
if (!e)
@@ -144,72 +92,82 @@ int socket_address_parse(SocketAddress *a, const char *s) {
if (!n)
return -ENOMEM;
- if (!isempty(n)) {
- r = safe_atou(n, &a->sockaddr.vm.svm_cid);
+ if (isempty(n))
+ cid = VMADDR_CID_ANY;
+ else {
+ r = safe_atou(n, &cid);
if (r < 0)
return r;
- } else
- a->sockaddr.vm.svm_cid = VMADDR_CID_ANY;
+ }
- a->sockaddr.vm.svm_family = AF_VSOCK;
- a->sockaddr.vm.svm_port = port;
- a->size = sizeof(struct sockaddr_vm);
+ *a = (SocketAddress) {
+ .sockaddr.vm = {
+ .svm_cid = cid,
+ .svm_family = AF_VSOCK,
+ .svm_port = port,
+ },
+ .size = sizeof(struct sockaddr_vm),
+ };
} else {
uint16_t port;
- e = strchr(s, ':');
- if (e) {
- r = parse_ip_port(e + 1, &port);
- if (r < 0)
- return r;
-
- n = strndup(s, e-s);
- if (!n)
- return -ENOMEM;
-
- /* IPv4 in w.x.y.z:p notation? */
- r = inet_pton(AF_INET, n, &a->sockaddr.in.sin_addr);
- if (r < 0)
- return -errno;
-
- if (r > 0) {
- /* Gotcha, it's a traditional IPv4 address */
- a->sockaddr.in.sin_family = AF_INET;
- a->sockaddr.in.sin_port = htobe16(port);
- a->size = sizeof(struct sockaddr_in);
- } else {
- int idx;
-
- /* Uh, our last resort, an interface name */
- idx = resolve_ifname(NULL, n);
- if (idx < 0)
- return idx;
-
- a->sockaddr.in6.sin6_family = AF_INET6;
- a->sockaddr.in6.sin6_port = htobe16(port);
- a->sockaddr.in6.sin6_scope_id = idx;
- a->sockaddr.in6.sin6_addr = in6addr_any;
- a->size = sizeof(struct sockaddr_in6);
- }
- } else {
-
+ r = parse_ip_port(s, &port);
+ if (r == -ERANGE)
+ return r; /* Valid port syntax, but the numerical value is wrong for a port. */
+ if (r >= 0) {
/* Just a port */
- r = parse_ip_port(s, &port);
+ if (socket_ipv6_is_supported())
+ *a = (SocketAddress) {
+ .sockaddr.in6 = {
+ .sin6_family = AF_INET6,
+ .sin6_port = htobe16(port),
+ .sin6_addr = in6addr_any,
+ },
+ .size = sizeof(struct sockaddr_in6),
+ };
+ else
+ *a = (SocketAddress) {
+ .sockaddr.in = {
+ .sin_family = AF_INET,
+ .sin_port = htobe16(port),
+ .sin_addr.s_addr = INADDR_ANY,
+ },
+ .size = sizeof(struct sockaddr_in),
+ };
+
+ } else {
+ union in_addr_union address;
+ int family, ifindex;
+
+ r = in_addr_port_ifindex_name_from_string_auto(s, &family, &address, &port, &ifindex, NULL);
if (r < 0)
return r;
- if (socket_ipv6_is_supported()) {
- a->sockaddr.in6.sin6_family = AF_INET6;
- a->sockaddr.in6.sin6_port = htobe16(port);
- a->sockaddr.in6.sin6_addr = in6addr_any;
- a->size = sizeof(struct sockaddr_in6);
- } else {
- a->sockaddr.in.sin_family = AF_INET;
- a->sockaddr.in.sin_port = htobe16(port);
- a->sockaddr.in.sin_addr.s_addr = INADDR_ANY;
- a->size = sizeof(struct sockaddr_in);
- }
+ if (port == 0) /* No port, no go. */
+ return -EINVAL;
+
+ if (family == AF_INET)
+ *a = (SocketAddress) {
+ .sockaddr.in = {
+ .sin_family = AF_INET,
+ .sin_addr = address.in,
+ .sin_port = htobe16(port),
+ },
+ .size = sizeof(struct sockaddr_in),
+ };
+ else if (family == AF_INET6)
+ *a = (SocketAddress) {
+ .sockaddr.in6 = {
+ .sin6_family = AF_INET6,
+ .sin6_addr = address.in6,
+ .sin6_port = htobe16(port),
+ .sin6_scope_id = ifindex,
+ },
+ .size = sizeof(struct sockaddr_in6),
+ };
+ else
+ assert_not_reached("Family quarrel");
}
}
@@ -243,10 +201,6 @@ int socket_address_parse_netlink(SocketAddress *a, const char *s) {
assert(a);
assert(s);
- *a = (SocketAddress) {
- .type = SOCK_RAW,
- };
-
r = extract_first_word(&s, &word, NULL, 0);
if (r < 0)
return r;
@@ -263,12 +217,13 @@ int socket_address_parse_netlink(SocketAddress *a, const char *s) {
return r;
}
- a->sockaddr.nl.nl_family = AF_NETLINK;
- a->sockaddr.nl.nl_groups = group;
-
- a->type = SOCK_RAW;
- a->size = sizeof(struct sockaddr_nl);
- a->protocol = family;
+ *a = (SocketAddress) {
+ .type = SOCK_RAW,
+ .sockaddr.nl.nl_family = AF_NETLINK,
+ .sockaddr.nl.nl_groups = group,
+ .protocol = family,
+ .size = sizeof(struct sockaddr_nl),
+ };
return 0;
}
@@ -345,10 +300,14 @@ int in_addr_port_ifindex_name_from_string_auto(
/* This accepts the following:
* 192.168.0.1:53#example.com
- * [2001:4860:4860::8888]:53%eth0#example.com */
-
- /* if ret_port is NULL, then strings with port cannot be specified.
- * Also, if ret_server_name is NULL, then server_name cannot be specified. */
+ * [2001:4860:4860::8888]:53%eth0#example.com
+ *
+ * If ret_port is NULL, then the port cannot be specified.
+ * If ret_ifindex is NULL, then the interface index cannot be specified.
+ * If ret_server_name is NULL, then server_name cannot be specified.
+ *
+ * ret_family is always AF_INET or AF_INET6.
+ */
m = strchr(s, '#');
if (m) {
@@ -369,15 +328,19 @@ int in_addr_port_ifindex_name_from_string_auto(
m = strchr(s, '%');
if (m) {
+ if (!ret_ifindex)
+ return -EINVAL;
+
if (isempty(m + 1))
return -EINVAL;
- if (ret_ifindex) {
- /* If we shall return the interface index, try to parse it */
- ifindex = resolve_interface(NULL, m + 1);
- if (ifindex < 0)
- return ifindex;
- }
+ if (!ifname_valid_full(m + 1, IFNAME_VALID_ALTERNATIVE | IFNAME_VALID_NUMERIC))
+ return -EINVAL; /* We want to return -EINVAL for syntactically invalid names,
+ * and -ENODEV for valid but nonexistent interfaces. */
+
+ ifindex = resolve_interface(NULL, m + 1);
+ if (ifindex < 0)
+ return ifindex;
s = buf2 = strndup(s, m - s);
if (!buf2)
@@ -455,36 +418,6 @@ int in_addr_port_ifindex_name_from_string_auto(
return r;
}
-int in_addr_port_from_string_auto(
- const char *s,
- int *ret_family,
- union in_addr_union *ret_address,
- uint16_t *ret_port) {
-
- union in_addr_union addr;
- int family, ifindex, r;
- uint16_t port;
-
- assert(s);
-
- r = in_addr_port_ifindex_name_from_string_auto(s, &family, &addr, &port, &ifindex, NULL);
- if (r < 0)
- return r;
-
- /* This does not accept interface specified. */
- if (ifindex != 0)
- return -EINVAL;
-
- if (ret_family)
- *ret_family = family;
- if (ret_address)
- *ret_address = addr;
- if (ret_port)
- *ret_port = port;
-
- return r;
-}
-
struct in_addr_full *in_addr_full_free(struct in_addr_full *a) {
if (!a)
return NULL;
diff --git a/src/shared/socket-netlink.h b/src/shared/socket-netlink.h
index d019bb31c6..e6cd7d9bf1 100644
--- a/src/shared/socket-netlink.h
+++ b/src/shared/socket-netlink.h
@@ -33,7 +33,6 @@ static inline int in_addr_ifindex_name_from_string_auto(const char *s, int *fami
static inline int in_addr_ifindex_from_string_auto(const char *s, int *family, union in_addr_union *ret, int *ifindex) {
return in_addr_ifindex_name_from_string_auto(s, family, ret, ifindex, NULL);
}
-int in_addr_port_from_string_auto(const char *s, int *ret_family, union in_addr_union *ret_address, uint16_t *ret_port);
struct in_addr_full {
int family;
diff --git a/src/test/test-in-addr-util.c b/src/test/test-in-addr-util.c
index 63e9800ec8..a9ecd0627b 100644
--- a/src/test/test-in-addr-util.c
+++ b/src/test/test-in-addr-util.c
@@ -58,6 +58,8 @@ static void test_in_addr_prefix_from_string_one(
}
static void test_in_addr_prefix_from_string(void) {
+ log_info("/* %s */", __func__);
+
test_in_addr_prefix_from_string_one("", AF_INET, -EINVAL, NULL, 0, -EINVAL, 0, -EINVAL, 0);
test_in_addr_prefix_from_string_one("/", AF_INET, -EINVAL, NULL, 0, -EINVAL, 0, -EINVAL, 0);
test_in_addr_prefix_from_string_one("/8", AF_INET, -EINVAL, NULL, 0, -EINVAL, 0, -EINVAL, 0);
@@ -90,7 +92,7 @@ static void test_in_addr_prefix_to_string_valid(int family, const char *p) {
union in_addr_union u;
unsigned char l;
- log_info("/* %s */", p);
+ log_info("%s: %s", __func__, p);
assert_se(in_addr_prefix_from_string(p, family, &u, &l) >= 0);
assert_se(in_addr_prefix_to_string(family, &u, l, &str) >= 0);
@@ -102,7 +104,7 @@ static void test_in_addr_prefix_to_string_unoptimized(int family, const char *p)
union in_addr_union u1, u2;
unsigned char len1, len2;
- log_info("/* %s */", p);
+ log_info("%s: %s", __func__, p);
assert_se(in_addr_prefix_from_string(p, family, &u1, &len1) >= 0);
assert_se(in_addr_prefix_to_string(family, &u1, len1, &str1) >= 0);
@@ -115,6 +117,8 @@ static void test_in_addr_prefix_to_string_unoptimized(int family, const char *p)
}
static void test_in_addr_prefix_to_string(void) {
+ log_info("/* %s */", __func__);
+
test_in_addr_prefix_to_string_valid(AF_INET, "0.0.0.0/32");
test_in_addr_prefix_to_string_valid(AF_INET, "1.2.3.4/0");
test_in_addr_prefix_to_string_valid(AF_INET, "1.2.3.4/24");
@@ -137,6 +141,8 @@ static void test_in_addr_random_prefix(void) {
_cleanup_free_ char *str = NULL;
union in_addr_union a;
+ log_info("/* %s */", __func__);
+
assert_se(in_addr_from_string(AF_INET, "192.168.10.1", &a) >= 0);
assert_se(in_addr_random_prefix(AF_INET, &a, 31, 32) >= 0);
diff --git a/src/test/test-socket-netlink.c b/src/test/test-socket-netlink.c
index f86f123782..afb7038621 100644
--- a/src/test/test-socket-netlink.c
+++ b/src/test/test-socket-netlink.c
@@ -12,11 +12,20 @@ static void test_socket_address_parse_one(const char *in, int ret, int family, c
int r;
r = socket_address_parse(&a, in);
- if (r >= 0)
- assert_se(socket_address_print(&a, &out) >= 0);
+ if (r >= 0) {
+ r = socket_address_print(&a, &out);
+ if (r < 0)
+ log_error_errno(r, "Printing failed for \"%s\": %m", in);
+ assert(r >= 0);
+ assert_se(a.type == 0);
+ }
- log_info("\"%s\" → %s → \"%s\" (expect \"%s\")", in,
- r >= 0 ? "✓" : "✗", empty_to_dash(out), r >= 0 ? expected ?: in : "-");
+ log_info("\"%s\" → %s %d → \"%s\" (expect %d / \"%s\")",
+ in,
+ r >= 0 ? "✓" : "✗", r,
+ empty_to_dash(out),
+ ret,
+ ret >= 0 ? expected ?: in : "-");
assert_se(r == ret);
if (r >= 0) {
assert_se(a.sockaddr.sa.sa_family == family);
@@ -50,14 +59,24 @@ static void test_socket_address_parse(void) {
test_socket_address_parse_one("[::1]:0", -EINVAL, 0, NULL);
test_socket_address_parse_one("[::1]:65536", -ERANGE, 0, NULL);
test_socket_address_parse_one("[a:b:1]:8888", -EINVAL, 0, NULL);
+ test_socket_address_parse_one("[::1]%lo:1234", -EINVAL, 0, NULL);
+ test_socket_address_parse_one("[::1]%lo:0", -EINVAL, 0, NULL);
+ test_socket_address_parse_one("[::1]%lo", -EINVAL, 0, NULL);
+ test_socket_address_parse_one("[::1]%lo%lo:1234", -EINVAL, 0, NULL);
+ test_socket_address_parse_one("[::1]% lo:1234", -EINVAL, 0, NULL);
test_socket_address_parse_one("8888", 0, default_family, "[::]:8888");
test_socket_address_parse_one("[2001:0db8:0000:85a3:0000:0000:ac1f:8001]:8888", 0, AF_INET6,
"[2001:db8:0:85a3::ac1f:8001]:8888");
test_socket_address_parse_one("[::1]:8888", 0, AF_INET6, NULL);
+ test_socket_address_parse_one("[::1]:1234%lo", 0, AF_INET6, NULL);
+ test_socket_address_parse_one("[::1]:0%lo", -EINVAL, 0, NULL);
+ test_socket_address_parse_one("[::1]%lo", -EINVAL, 0, NULL);
+ test_socket_address_parse_one("[::1]:1234%lo%lo", -ENODEV, 0, NULL);
+ test_socket_address_parse_one("[::1]:1234%xxxxasdf", -ENODEV, 0, NULL);
test_socket_address_parse_one("192.168.1.254:8888", 0, AF_INET, NULL);
test_socket_address_parse_one("/foo/bar", 0, AF_UNIX, NULL);
- test_socket_address_parse_one("/", 0, AF_UNIX, NULL);
+ test_socket_address_parse_one("/", -EINVAL, 0, NULL);
test_socket_address_parse_one("@abstract", 0, AF_UNIX, NULL);
{
@@ -198,9 +217,13 @@ static void test_socket_address_is(void) {
log_info("/* %s */", __func__);
assert_se(socket_address_parse(&a, "192.168.1.1:8888") >= 0);
- assert_se(socket_address_is(&a, "192.168.1.1:8888", SOCK_STREAM));
+ assert_se( socket_address_is(&a, "192.168.1.1:8888", 0 /* unspecified yet */));
+ assert_se(!socket_address_is(&a, "route", 0));
assert_se(!socket_address_is(&a, "route", SOCK_STREAM));
assert_se(!socket_address_is(&a, "192.168.1.1:8888", SOCK_RAW));
+ assert_se(!socket_address_is(&a, "192.168.1.1:8888", SOCK_STREAM));
+ a.type = SOCK_STREAM;
+ assert_se( socket_address_is(&a, "192.168.1.1:8888", SOCK_STREAM));
}
static void test_socket_address_is_netlink(void) {
@@ -209,7 +232,7 @@ static void test_socket_address_is_netlink(void) {
log_info("/* %s */", __func__);
assert_se(socket_address_parse_netlink(&a, "route 10") >= 0);
- assert_se(socket_address_is_netlink(&a, "route 10"));
+ assert_se( socket_address_is_netlink(&a, "route 10"));
assert_se(!socket_address_is_netlink(&a, "192.168.1.1:8888"));
assert_se(!socket_address_is_netlink(&a, "route 1"));
}
@@ -284,66 +307,83 @@ static void test_in_addr_ifindex_name_from_string_auto(void) {
test_in_addr_ifindex_name_from_string_auto_one("fe80::18%19#another.test.com", "another.test.com");
}
-static void test_in_addr_port_ifindex_name_from_string_auto_one(const char *str, int family, uint16_t port, int ifindex, const char *server_name) {
- _cleanup_free_ char *name = NULL, *x = NULL;
+static void test_in_addr_port_ifindex_name_from_string_auto_one(const char *str, int family, uint16_t port, int ifindex,
+ const char *server_name, const char *str_repr) {
union in_addr_union a;
uint16_t p;
int f, i;
+ char *fake;
- assert_se(in_addr_port_ifindex_name_from_string_auto(str, &f, &a, &p, &i, &name) >= 0);
- assert_se(family == f);
- assert_se(port == p);
- assert_se(ifindex == i);
- assert_se(streq_ptr(server_name, name));
- assert_se(in_addr_port_ifindex_name_to_string(f, &a, p, i, name, &x) >= 0);
- assert_se(streq(str, x));
+ log_info("%s: %s", __func__, str);
+
+ {
+ _cleanup_free_ char *name = NULL, *x = NULL;
+ assert_se(in_addr_port_ifindex_name_from_string_auto(str, &f, &a, &p, &i, &name) == 0);
+ assert_se(family == f);
+ assert_se(port == p);
+ assert_se(ifindex == i);
+ assert_se(streq_ptr(server_name, name));
+ assert_se(in_addr_port_ifindex_name_to_string(f, &a, p, i, name, &x) >= 0);
+ assert_se(streq(str_repr ?: str, x));
+ }
+
+ if (port > 0)
+ assert_se(in_addr_port_ifindex_name_from_string_auto(str, &f, &a, NULL, &i, &fake) == -EINVAL);
+ else {
+ _cleanup_free_ char *name = NULL, *x = NULL;
+ assert_se(in_addr_port_ifindex_name_from_string_auto(str, &f, &a, NULL, &i, &name) == 0);
+ assert_se(family == f);
+ assert_se(ifindex == i);
+ assert_se(streq_ptr(server_name, name));
+ assert_se(in_addr_port_ifindex_name_to_string(f, &a, 0, i, name, &x) >= 0);
+ assert_se(streq(str_repr ?: str, x));
+ }
+
+ if (ifindex > 0)
+ assert_se(in_addr_port_ifindex_name_from_string_auto(str, &f, &a, &p, NULL, &fake) == -EINVAL);
+ else {
+ _cleanup_free_ char *name = NULL, *x = NULL;
+ assert_se(in_addr_port_ifindex_name_from_string_auto(str, &f, &a, &p, NULL, &name) == 0);
+ assert_se(family == f);
+ assert_se(port == p);
+ assert_se(streq_ptr(server_name, name));
+ assert_se(in_addr_port_ifindex_name_to_string(f, &a, p, 0, name, &x) >= 0);
+ assert_se(streq(str_repr ?: str, x));
+ }
+
+ if (server_name)
+ assert_se(in_addr_port_ifindex_name_from_string_auto(str, &f, &a, &p, &i, NULL) == -EINVAL);
+ else {
+ _cleanup_free_ char *x = NULL;
+ assert_se(in_addr_port_ifindex_name_from_string_auto(str, &f, &a, &p, &i, NULL) == 0);
+ assert_se(family == f);
+ assert_se(port == p);
+ assert_se(ifindex == i);
+ assert_se(in_addr_port_ifindex_name_to_string(f, &a, p, i, NULL, &x) >= 0);
+ assert_se(streq(str_repr ?: str, x));
+ }
}
static void test_in_addr_port_ifindex_name_from_string_auto(void) {
log_info("/* %s */", __func__);
- test_in_addr_port_ifindex_name_from_string_auto_one("192.168.0.1", AF_INET, 0, 0, NULL);
- test_in_addr_port_ifindex_name_from_string_auto_one("192.168.0.1#test.com", AF_INET, 0, 0, "test.com");
- test_in_addr_port_ifindex_name_from_string_auto_one("192.168.0.1:53", AF_INET, 53, 0, NULL);
- test_in_addr_port_ifindex_name_from_string_auto_one("192.168.0.1:53#example.com", AF_INET, 53, 0, "example.com");
- test_in_addr_port_ifindex_name_from_string_auto_one("fe80::18", AF_INET6, 0, 0, NULL);
- test_in_addr_port_ifindex_name_from_string_auto_one("fe80::18#hoge.com", AF_INET6, 0, 0, "hoge.com");
- test_in_addr_port_ifindex_name_from_string_auto_one("fe80::18%19", AF_INET6, 0, 19, NULL);
- test_in_addr_port_ifindex_name_from_string_auto_one("[fe80::18]:53", AF_INET6, 53, 0, NULL);
- test_in_addr_port_ifindex_name_from_string_auto_one("fe80::18%19#hoge.com", AF_INET6, 0, 19, "hoge.com");
- test_in_addr_port_ifindex_name_from_string_auto_one("[fe80::18]:53#hoge.com", AF_INET6, 53, 0, "hoge.com");
- test_in_addr_port_ifindex_name_from_string_auto_one("[fe80::18]:53%19", AF_INET6, 53, 19, NULL);
- test_in_addr_port_ifindex_name_from_string_auto_one("[fe80::18]:53%19#hoge.com", AF_INET6, 53, 19, "hoge.com");
-}
-
-static void test_in_addr_port_from_string_auto_one(const char *str, int family, const char *address_string, uint16_t port) {
- union in_addr_union a, b;
- uint16_t p;
- int f;
-
- assert_se(in_addr_port_from_string_auto(str, &f, &a, &p) >= 0);
- assert_se(family == f);
- assert_se(port == p);
- assert_se(in_addr_from_string(family, address_string, &b) >= 0);
- assert_se(in_addr_equal(family, &a, &b) == 1);
-}
-
-static void test_in_addr_port_from_string_auto(void) {
- log_info("/* %s */", __func__);
-
- assert_se(in_addr_port_from_string_auto("192.168.0.1#test.com", NULL, NULL, NULL) < 0);
- assert_se(in_addr_port_from_string_auto("192.168.0.1:53#example.com", NULL, NULL, NULL) < 0);
- assert_se(in_addr_port_from_string_auto("fe80::18#hoge.com", NULL, NULL, NULL) < 0);
- assert_se(in_addr_port_from_string_auto("fe80::18%19", NULL, NULL, NULL) < 0);
- assert_se(in_addr_port_from_string_auto("fe80::18%19#hoge.com", NULL, NULL, NULL) < 0);
- assert_se(in_addr_port_from_string_auto("[fe80::18]:53#hoge.com", NULL, NULL, NULL) < 0);
- assert_se(in_addr_port_from_string_auto("[fe80::18]:53%19", NULL, NULL, NULL) < 0);
- assert_se(in_addr_port_from_string_auto("[fe80::18]:53%19#hoge.com", NULL, NULL, NULL) < 0);
-
- test_in_addr_port_from_string_auto_one("192.168.0.1", AF_INET, "192.168.0.1", 0);
- test_in_addr_port_from_string_auto_one("192.168.0.1:53", AF_INET, "192.168.0.1", 53);
- test_in_addr_port_from_string_auto_one("fe80::18", AF_INET6, "fe80::18", 0);
- test_in_addr_port_from_string_auto_one("[fe80::18]:53", AF_INET6, "fe80::18", 53);
+ test_in_addr_port_ifindex_name_from_string_auto_one("192.168.0.1", AF_INET, 0, 0, NULL, NULL);
+ test_in_addr_port_ifindex_name_from_string_auto_one("192.168.0.1#test.com", AF_INET, 0, 0, "test.com", NULL);
+ test_in_addr_port_ifindex_name_from_string_auto_one("192.168.0.1:53", AF_INET, 53, 0, NULL, NULL);
+ test_in_addr_port_ifindex_name_from_string_auto_one("192.168.0.1:53#example.com", AF_INET, 53, 0, "example.com", NULL);
+ test_in_addr_port_ifindex_name_from_string_auto_one("fe80::18", AF_INET6, 0, 0, NULL, NULL);
+ test_in_addr_port_ifindex_name_from_string_auto_one("fe80::18#hoge.com", AF_INET6, 0, 0, "hoge.com", NULL);
+ test_in_addr_port_ifindex_name_from_string_auto_one("fe80::18%19", AF_INET6, 0, 19, NULL, NULL);
+ test_in_addr_port_ifindex_name_from_string_auto_one("fe80::18%lo", AF_INET6, 0, 1, NULL, "fe80::18%1");
+ test_in_addr_port_ifindex_name_from_string_auto_one("[fe80::18]:53", AF_INET6, 53, 0, NULL, NULL);
+ test_in_addr_port_ifindex_name_from_string_auto_one("[fe80::18]:53%19", AF_INET6, 53, 19, NULL, NULL);
+ test_in_addr_port_ifindex_name_from_string_auto_one("[fe80::18]:53%lo", AF_INET6, 53, 1, NULL, "[fe80::18]:53%1");
+ test_in_addr_port_ifindex_name_from_string_auto_one("fe80::18%19#hoge.com", AF_INET6, 0, 19, "hoge.com", NULL);
+ test_in_addr_port_ifindex_name_from_string_auto_one("[fe80::18]:53#hoge.com", AF_INET6, 53, 0, "hoge.com", NULL);
+ test_in_addr_port_ifindex_name_from_string_auto_one("[fe80::18]:53%19", AF_INET6, 53, 19, NULL, NULL);
+ test_in_addr_port_ifindex_name_from_string_auto_one("[fe80::18]:53%19#hoge.com", AF_INET6, 53, 19, "hoge.com", NULL);
+ test_in_addr_port_ifindex_name_from_string_auto_one("[fe80::18]:53%lo", AF_INET6, 53, 1, NULL, "[fe80::18]:53%1");
+ test_in_addr_port_ifindex_name_from_string_auto_one("[fe80::18]:53%lo#hoge.com", AF_INET6, 53, 1, "hoge.com", "[fe80::18]:53%1#hoge.com");
}
int main(int argc, char *argv[]) {
@@ -360,7 +400,6 @@ int main(int argc, char *argv[]) {
test_in_addr_ifindex_from_string_auto();
test_in_addr_ifindex_name_from_string_auto();
test_in_addr_port_ifindex_name_from_string_auto();
- test_in_addr_port_from_string_auto();
return 0;
}
diff --git a/src/test/test-socket-util.c b/src/test/test-socket-util.c
index 0bc713cb53..1bb186655d 100644
--- a/src/test/test-socket-util.c
+++ b/src/test/test-socket-util.c
@@ -26,13 +26,13 @@ assert_cc(SUN_PATH_LEN == 108);
static void test_ifname_valid(void) {
log_info("/* %s */", __func__);
- assert(ifname_valid("foo"));
- assert(ifname_valid("eth0"));
+ assert( ifname_valid("foo"));
+ assert( ifname_valid("eth0"));
assert(!ifname_valid("0"));
assert(!ifname_valid("99"));
- assert(ifname_valid("a99"));
- assert(ifname_valid("99a"));
+ assert( ifname_valid("a99"));
+ assert( ifname_valid("99a"));
assert(!ifname_valid(NULL));
assert(!ifname_valid(""));
@@ -44,9 +44,13 @@ static void test_ifname_valid(void) {
assert(ifname_valid("foo.bar"));
assert(!ifname_valid("x:y"));
- assert(ifname_valid("xxxxxxxxxxxxxxx"));
- assert(!ifname_valid("xxxxxxxxxxxxxxxx"));
- assert(ifname_valid_full("xxxxxxxxxxxxxxxx", true));
+ assert( ifname_valid_full("xxxxxxxxxxxxxxx", 0));
+ assert(!ifname_valid_full("xxxxxxxxxxxxxxxx", 0));
+ assert( ifname_valid_full("xxxxxxxxxxxxxxxx", IFNAME_VALID_ALTERNATIVE));
+ assert( ifname_valid_full("xxxxxxxxxxxxxxxx", IFNAME_VALID_ALTERNATIVE));
+ assert(!ifname_valid_full("999", IFNAME_VALID_ALTERNATIVE));
+ assert( ifname_valid_full("999", IFNAME_VALID_ALTERNATIVE | IFNAME_VALID_NUMERIC));
+ assert(!ifname_valid_full("0", IFNAME_VALID_ALTERNATIVE | IFNAME_VALID_NUMERIC));
}
static void test_socket_print_unix_one(const char *in, size_t len_in, const char *expected) {
@@ -504,17 +508,11 @@ int main(int argc, char *argv[]) {
test_setup_logging(LOG_DEBUG);
test_ifname_valid();
-
test_socket_print_unix();
-
test_sockaddr_equal();
-
test_sockaddr_un_len();
-
test_in_addr_is_multicast();
-
test_getpeercred_getpeergroups();
-
test_passfd_read();
test_passfd_contents_read();
test_receive_nopassfd();
diff --git a/src/udev/net/link-config-gperf.gperf b/src/udev/net/link-config-gperf.gperf
index 60a9d21c1d..20f5d7e5a4 100644
--- a/src/udev/net/link-config-gperf.gperf
+++ b/src/udev/net/link-config-gperf.gperf
@@ -7,6 +7,7 @@ _Pragma("GCC diagnostic ignored \"-Wimplicit-fallthrough\"")
#include "ethtool-util.h"
#include "link-config.h"
#include "network-internal.h"
+#include "socket-util.h"
%}
struct ConfigPerfItem;
%null_strings
@@ -36,7 +37,7 @@ Link.MACAddressPolicy, config_parse_mac_address_policy, 0,
Link.MACAddress, config_parse_hwaddr, 0, offsetof(link_config, mac)
Link.NamePolicy, config_parse_name_policy, 0, offsetof(link_config, name_policy)
Link.Name, config_parse_ifname, 0, offsetof(link_config, name)
-Link.AlternativeName, config_parse_ifnames, 1, offsetof(link_config, alternative_names)
+Link.AlternativeName, config_parse_ifnames, IFNAME_VALID_ALTERNATIVE, offsetof(link_config, alternative_names)
Link.AlternativeNamesPolicy, config_parse_alternative_names_policy, 0, offsetof(link_config, alternative_names_policy)
Link.Alias, config_parse_ifalias, 0, offsetof(link_config, alias)
Link.MTUBytes, config_parse_mtu, AF_UNSPEC, offsetof(link_config, mtu)