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)