diff --git a/man/resolved.conf.xml b/man/resolved.conf.xml index 338bee6c38..c3c6b26329 100644 --- a/man/resolved.conf.xml +++ b/man/resolved.conf.xml @@ -271,27 +271,27 @@ DNSStubListenerExtra= - Takes an IPv4 or IPv6 address to listen on. The address may optionally be prefixed by : and - a protocol name (udp or tcp). When an IPv6 address is specified with a port number, then the - address must be in the square brackets. This option can be specified multiple times. If an empty string is assigned, then the all - previous assignments are cleared. It may also be optionally suffixed by a numeric port number with separator :. - If the protocol is not specified, the service will listen on both UDP and TCP. If the port is not - specified, then the service takes port as 53. This option may be used multiple times. Note that this is independent of the - primary DNS stub configured with DNSStubListener=, and only configures additional - sockets to listen on. Defaults to unset. + Takes an IPv4 or IPv6 address to listen on. The address may be optionally + prefixed with a protocol name (udp or tcp) separated with + :. If the protocol is not specified, the service will listen on both UDP and + TCP. It may be also optionally suffixed by a numeric port number with separator + :. When an IPv6 address is specified with a port number, then the address + must be in the square brackets. If the port is not specified, then the service uses port 53. + Note that this is independent of the primary DNS stub configured with + DNSStubListener=, and only configures additional + sockets to listen on. This option can be specified multiple times. If an empty string is + assigned, then the all previous assignments are cleared. Defaults to unset. - If the string in the format udp:[x]:y, - it is read as protocol udp and IPv6 address x on a port y. - - If the string in the format [x]:y, it is read as both protocol - udp and tcp, IPv6 address x on a port y. - - If the string in the format x, it is read as protocol both udp and - tcp, IPv6/IPv4 address x on a port 53. - - If the string in the format udp:x:y, - it is read as protocol udp and IPv4 address x on a port y. - + Examples: + DNSStubListenerExtra=192.168.10.10 +DNSStubListenerExtra=2001:db8:0:f102::10 +DNSStubListenerExtra=192.168.10.11:9953 +DNSStubListenerExtra=[2001:db8:0:f102::11]:9953 +DNSStubListenerExtra=tcp:192.168.10.12 +DNSStubListenerExtra=udp:2001:db8:0:f102::12 +DNSStubListenerExtra=tcp:192.168.10.13:9953 +DNSStubListenerExtra=udp:[2001:db8:0:f102::13]:9953 + diff --git a/src/basic/in-addr-util.c b/src/basic/in-addr-util.c index ea50e26197..f0ce6900ef 100644 --- a/src/basic/in-addr-util.c +++ b/src/basic/in-addr-util.c @@ -402,46 +402,6 @@ int in_addr_prefix_to_string(int family, const union in_addr_union *u, unsigned return 0; } -int in_addr_ifindex_to_string(int family, const union in_addr_union *u, int ifindex, char **ret) { - _cleanup_free_ char *x = NULL; - size_t l; - int r; - - assert(u); - assert(ret); - - /* Much like in_addr_to_string(), but optionally appends the zone interface index to the address, to properly - * handle IPv6 link-local addresses. */ - - if (family != AF_INET6) - goto fallback; - if (ifindex <= 0) - goto fallback; - - r = in_addr_is_link_local(family, u); - if (r < 0) - return r; - if (r == 0) - goto fallback; - - l = INET6_ADDRSTRLEN + 1 + DECIMAL_STR_MAX(ifindex) + 1; - x = new(char, l); - if (!x) - return -ENOMEM; - - errno = 0; - if (!inet_ntop(family, u, x, l)) - return errno_or_else(EINVAL); - - sprintf(strchr(x, 0), "%%%i", ifindex); - - *ret = TAKE_PTR(x); - return 0; - -fallback: - return in_addr_to_string(family, u, ret); -} - int in_addr_port_ifindex_name_to_string(int family, const union in_addr_union *u, uint16_t port, int ifindex, const char *server_name, char **ret) { _cleanup_free_ char *ip_str = NULL, *x = NULL; int r; diff --git a/src/basic/in-addr-util.h b/src/basic/in-addr-util.h index 03583f2566..6ce0bef578 100644 --- a/src/basic/in-addr-util.h +++ b/src/basic/in-addr-util.h @@ -41,8 +41,13 @@ int in_addr_prefix_nth(int family, union in_addr_union *u, unsigned prefixlen, u int in_addr_random_prefix(int family, union in_addr_union *u, unsigned prefixlen_fixed_part, unsigned prefixlen); int in_addr_to_string(int family, const union in_addr_union *u, char **ret); int in_addr_prefix_to_string(int family, const union in_addr_union *u, unsigned prefixlen, char **ret); -int in_addr_ifindex_to_string(int family, const union in_addr_union *u, int ifindex, char **ret); int in_addr_port_ifindex_name_to_string(int family, const union in_addr_union *u, uint16_t port, int ifindex, const char *server_name, char **ret); +static inline int in_addr_ifindex_to_string(int family, const union in_addr_union *u, int ifindex, char **ret) { + return in_addr_port_ifindex_name_to_string(family, u, 0, ifindex, NULL, ret); +} +static inline int in_addr_port_to_string(int family, const union in_addr_union *u, uint16_t port, char **ret) { + return in_addr_port_ifindex_name_to_string(family, u, port, 0, NULL, ret); +} int in_addr_from_string(int family, const char *s, union in_addr_union *ret); int in_addr_from_string_auto(const char *s, int *ret_family, union in_addr_union *ret); diff --git a/src/basic/missing_socket.h b/src/basic/missing_socket.h index 8c3fec1e35..c4f33449a3 100644 --- a/src/basic/missing_socket.h +++ b/src/basic/missing_socket.h @@ -63,6 +63,10 @@ struct sockaddr_vm { #define IP_TRANSPARENT 19 #endif +#ifndef IPV6_FREEBIND +#define IPV6_FREEBIND 78 +#endif + /* linux/sockios.h */ #ifndef SIOCGSKNS #define SIOCGSKNS 0x894C diff --git a/src/basic/socket-util.h b/src/basic/socket-util.h index 9e02e39887..5610a99e53 100644 --- a/src/basic/socket-util.h +++ b/src/basic/socket-util.h @@ -205,6 +205,35 @@ struct cmsghdr* cmsg_find(struct msghdr *mh, int level, int type, socklen_t leng strnlen(_sa->sun_path, sizeof(_sa->sun_path))+1); \ }) +#define SOCKADDR_LEN(sa) \ + ({ \ + const union sockaddr_union *__sa = &(sa); \ + size_t _len; \ + switch(__sa->sa.sa_family) { \ + case AF_INET: \ + _len = sizeof(struct sockaddr_in); \ + break; \ + case AF_INET6: \ + _len = sizeof(struct sockaddr_in6); \ + break; \ + case AF_UNIX: \ + _len = SOCKADDR_UN_LEN(__sa->un); \ + break; \ + case AF_PACKET: \ + _len = SOCKADDR_LL_LEN(__sa->ll); \ + break; \ + case AF_NETLINK: \ + _len = sizeof(struct sockaddr_nl); \ + break; \ + case AF_VSOCK: \ + _len = sizeof(struct sockaddr_vm); \ + break; \ + default: \ + assert_not_reached("invalid socket family"); \ + } \ + _len; \ + }) + int socket_ioctl_fd(void); int sockaddr_un_set_path(struct sockaddr_un *ret, const char *path); diff --git a/src/resolve/resolved-conf.c b/src/resolve/resolved-conf.c index 3b2b4d2063..639fd34178 100644 --- a/src/resolve/resolved-conf.c +++ b/src/resolve/resolved-conf.c @@ -30,20 +30,15 @@ static const char* const dns_stub_listener_mode_table[_DNS_STUB_LISTENER_MODE_MA DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(dns_stub_listener_mode, DnsStubListenerMode, DNS_STUB_LISTENER_YES); static void dns_stub_listener_extra_hash_func(const DNSStubListenerExtra *a, struct siphash *state) { - unsigned port; - assert(a); siphash24_compress(&a->mode, sizeof(a->mode), state); - siphash24_compress(&socket_address_family(&a->address), sizeof(a->address.type), state); - siphash24_compress(&a->address, FAMILY_ADDRESS_SIZE(socket_address_family(&a->address)), state); - - (void) sockaddr_port(&a->address.sockaddr.sa, &port); - siphash24_compress(&port, sizeof(port), state); + siphash24_compress(&a->family, sizeof(a->family), state); + siphash24_compress(&a->address, FAMILY_ADDRESS_SIZE(a->family), state); + siphash24_compress(&a->port, sizeof(a->port), state); } static int dns_stub_listener_extra_compare_func(const DNSStubListenerExtra *a, const DNSStubListenerExtra *b) { - unsigned p, q; int r; assert(a); @@ -53,18 +48,15 @@ static int dns_stub_listener_extra_compare_func(const DNSStubListenerExtra *a, c if (r != 0) return r; - r = CMP(socket_address_family(&a->address), socket_address_family(&b->address)); + r = CMP(a->family, b->family); if (r != 0) return r; - r = memcmp(&a->address, &b->address, FAMILY_ADDRESS_SIZE(socket_address_family(&a->address))); + r = memcmp(&a->address, &b->address, FAMILY_ADDRESS_SIZE(a->family)); if (r != 0) return r; - (void) sockaddr_port(&a->address.sockaddr.sa, &p); - (void) sockaddr_port(&b->address.sockaddr.sa, &q); - - return CMP(p, q); + return CMP(a->port, b->port); } DEFINE_PRIVATE_HASH_OPS_WITH_KEY_DESTRUCTOR( @@ -72,7 +64,7 @@ DEFINE_PRIVATE_HASH_OPS_WITH_KEY_DESTRUCTOR( DNSStubListenerExtra, dns_stub_listener_extra_hash_func, dns_stub_listener_extra_compare_func, - free); + dns_stub_listener_extra_free); static int manager_add_dns_server_by_string(Manager *m, DnsServerType type, const char *word) { _cleanup_free_ char *server_name = NULL; @@ -444,10 +436,8 @@ int config_parse_dns_stub_listener_extra( void *data, void *userdata) { - _cleanup_free_ DNSStubListenerExtra *udp = NULL, *tcp = NULL; - _cleanup_free_ char *word = NULL; + _cleanup_free_ DNSStubListenerExtra *stub = NULL; Manager *m = userdata; - bool both = false; const char *p; int r; @@ -461,78 +451,41 @@ int config_parse_dns_stub_listener_extra( return 0; } - p = rvalue; - r = extract_first_word(&p, &word, ":", 0); - if (r == -ENOMEM) + r = dns_stub_listener_extra_new(&stub); + if (r < 0) return log_oom(); - if (r <= 0) { + + p = startswith(rvalue, "udp:"); + if (p) + stub->mode = DNS_STUB_LISTENER_UDP; + else { + p = startswith(rvalue, "tcp:"); + if (p) + stub->mode = DNS_STUB_LISTENER_TCP; + else { + stub->mode = DNS_STUB_LISTENER_YES; + p = rvalue; + } + } + + r = in_addr_port_from_string_auto(p, &stub->family, &stub->address, &stub->port); + if (r < 0) { log_syntax(unit, LOG_WARNING, filename, line, r, - "Invalid DNSStubListenExtra='%s', ignoring assignment", rvalue); + "Failed to parse address in %s=%s, ignoring assignment: %m", + lvalue, rvalue); return 0; } - /* First look for udp/tcp. If not specified then turn both TCP and UDP */ - if (!STR_IN_SET(word, "tcp", "udp")) { - both = true; - p = rvalue; + r = ordered_set_ensure_put(&m->dns_extra_stub_listeners, &dns_stub_listener_extra_hash_ops, stub); + if (r == -ENOMEM) + return log_oom(); + if (r < 0) { + log_syntax(unit, LOG_WARNING, filename, line, r, + "Failed to store %s=%s, ignoring assignment: %m", lvalue, rvalue); + return 0; } - if (streq(word, "tcp") || both) { - r = dns_stub_extra_new(&tcp); - if (r < 0) - return log_oom(); - - tcp->mode = DNS_STUB_LISTENER_TCP; - } - - if (streq(word, "udp") || both) { - r = dns_stub_extra_new(&udp); - if (r < 0) - return log_oom(); - - udp->mode = DNS_STUB_LISTENER_UDP; - } - - if (tcp) { - r = socket_addr_port_from_string_auto(p, 53, &tcp->address); - if (r < 0) { - log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse address in DNSStubListenExtra='%s', ignoring", rvalue); - return 0; - } - } - - if (udp) { - r = socket_addr_port_from_string_auto(p, 53, &udp->address); - if (r < 0) { - log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse address in DNSStubListenExtra='%s', ignoring", rvalue); - return 0; - } - } - - if (tcp) { - r = ordered_set_ensure_put(&m->dns_extra_stub_listeners, &dns_stub_listener_extra_hash_ops, tcp); - if (r < 0) { - if (r == -ENOMEM) - return log_oom(); - - log_warning_errno(r, "Failed to store TCP DNSStubListenExtra='%s', ignoring assignment: %m", rvalue); - return 0; - } - } - - if (udp) { - r = ordered_set_ensure_put(&m->dns_extra_stub_listeners, &dns_stub_listener_extra_hash_ops, udp); - if (r < 0) { - if (r == -ENOMEM) - return log_oom(); - - log_warning_errno(r, "Failed to store UDP DNSStubListenExtra='%s', ignoring assignment: %m", rvalue); - return 0; - } - } - - TAKE_PTR(tcp); - TAKE_PTR(udp); + TAKE_PTR(stub); return 0; } diff --git a/src/resolve/resolved-conf.h b/src/resolve/resolved-conf.h index f8d16b5a8e..50a0caaf16 100644 --- a/src/resolve/resolved-conf.h +++ b/src/resolve/resolved-conf.h @@ -7,9 +7,9 @@ typedef enum DnsStubListenerMode DnsStubListenerMode; enum DnsStubListenerMode { DNS_STUB_LISTENER_NO, - DNS_STUB_LISTENER_UDP, - DNS_STUB_LISTENER_TCP, - DNS_STUB_LISTENER_YES, + DNS_STUB_LISTENER_UDP = 1 << 0, + DNS_STUB_LISTENER_TCP = 1 << 1, + DNS_STUB_LISTENER_YES = DNS_STUB_LISTENER_UDP | DNS_STUB_LISTENER_TCP, _DNS_STUB_LISTENER_MODE_MAX, _DNS_STUB_LISTENER_MODE_INVALID = -1 }; diff --git a/src/resolve/resolved-dns-packet.h b/src/resolve/resolved-dns-packet.h index 56614c4a07..359cdcfd04 100644 --- a/src/resolve/resolved-dns-packet.h +++ b/src/resolve/resolved-dns-packet.h @@ -66,6 +66,7 @@ struct DnsPacket { DnsResourceRecord *opt; /* Packet reception metadata */ + int fd; /* Used by UDP extra DNS stub listners */ int ifindex; int family, ipproto; union in_addr_union sender, destination; diff --git a/src/resolve/resolved-dns-stub.c b/src/resolve/resolved-dns-stub.c index d3999ea0a3..132bac8153 100644 --- a/src/resolve/resolved-dns-stub.c +++ b/src/resolve/resolved-dns-stub.c @@ -1,8 +1,11 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ +#include + #include "errno-util.h" #include "fd-util.h" #include "missing_network.h" +#include "missing_socket.h" #include "resolved-dns-stub.h" #include "socket-netlink.h" #include "socket-util.h" @@ -11,25 +14,28 @@ * IP and UDP header sizes */ #define ADVERTISE_DATAGRAM_SIZE_MAX (65536U-14U-20U-8U) -static int manager_dns_stub_udp_fd(Manager *m); -static int manager_dns_stub_tcp_fd(Manager *m); - -int dns_stub_extra_new(DNSStubListenerExtra **ret) { +int dns_stub_listener_extra_new(DNSStubListenerExtra **ret) { DNSStubListenerExtra *l; - l = new(DNSStubListenerExtra, 1); + l = new0(DNSStubListenerExtra, 1); if (!l) return -ENOMEM; - *l = (DNSStubListenerExtra) { - .fd = -1, - }; - *ret = TAKE_PTR(l); return 0; } +DNSStubListenerExtra *dns_stub_listener_extra_free(DNSStubListenerExtra *p) { + if (!p) + return NULL; + + p->udp_event_source = sd_event_source_unref(p->udp_event_source); + p->tcp_event_source = sd_event_source_unref(p->tcp_event_source); + + return mfree(p); +} + static int dns_stub_make_reply_packet( DnsPacket **p, size_t max_size, @@ -155,17 +161,11 @@ static int dns_stub_send(Manager *m, DnsStream *s, DnsPacket *p, DnsPacket *repl if (s) r = dns_stream_write_packet(s, reply); else { - int fd; - - fd = manager_dns_stub_udp_fd(m); - if (fd < 0) - return log_debug_errno(fd, "Failed to get reply socket: %m"); - /* Note that it is essential here that we explicitly choose the source IP address for this packet. This * 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, fd, LOOPBACK_IFINDEX, p->family, &p->sender, p->sender_port, &p->destination, reply); + r = manager_send(m, p->fd, p->ifindex, p->family, &p->sender, p->sender_port, &p->destination, reply); } if (r < 0) return log_debug_errno(r, "Failed to send reply packet: %m"); @@ -294,7 +294,7 @@ static int dns_stub_stream_complete(DnsStream *s, int error) { return 0; } -static void dns_stub_process_query(Manager *m, DnsStream *s, DnsPacket *p) { +static void dns_stub_process_query(Manager *m, DnsStream *s, DnsPacket *p, bool is_extra) { _cleanup_(dns_query_freep) DnsQuery *q = NULL; int r; @@ -302,8 +302,9 @@ static void dns_stub_process_query(Manager *m, DnsStream *s, DnsPacket *p) { assert(p); assert(p->protocol == DNS_PROTOCOL_DNS); - if (in_addr_is_localhost(p->family, &p->sender) <= 0 || - in_addr_is_localhost(p->family, &p->destination) <= 0) { + if (!is_extra && + (in_addr_is_localhost(p->family, &p->sender) <= 0 || + in_addr_is_localhost(p->family, &p->destination) <= 0)) { log_error("Got packet on unexpected IP range, refusing."); dns_stub_send_failure(m, s, p, DNS_RCODE_SERVFAIL, false); return; @@ -384,9 +385,8 @@ static void dns_stub_process_query(Manager *m, DnsStream *s, DnsPacket *p) { TAKE_PTR(q); } -static int on_dns_stub_packet(sd_event_source *s, int fd, uint32_t revents, void *userdata) { +static int on_dns_stub_packet_internal(sd_event_source *s, int fd, uint32_t revents, Manager *m, bool is_extra) { _cleanup_(dns_packet_unrefp) DnsPacket *p = NULL; - Manager *m = userdata; int r; r = manager_recv(m, fd, DNS_PROTOCOL_DNS, &p); @@ -396,27 +396,50 @@ static int on_dns_stub_packet(sd_event_source *s, int fd, uint32_t revents, void if (dns_packet_validate_query(p) > 0) { log_debug("Got DNS stub UDP query packet for id %u", DNS_PACKET_ID(p)); - dns_stub_process_query(m, NULL, p); + dns_stub_process_query(m, NULL, p, is_extra); } else log_debug("Invalid DNS stub UDP packet, ignoring."); return 0; } -static int set_dns_stub_common_socket_options(int fd) { +static int on_dns_stub_packet(sd_event_source *s, int fd, uint32_t revents, void *userdata) { + return on_dns_stub_packet_internal(s, fd, revents, userdata, false); +} + +static int on_dns_stub_packet_extra(sd_event_source *s, int fd, uint32_t revents, void *userdata) { + return on_dns_stub_packet_internal(s, fd, revents, userdata, true); +} + +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; - r = setsockopt_int(fd, IPPROTO_IP, IP_PKTINFO, true); - if (r < 0) - return r; + if (family == AF_INET) { + r = setsockopt_int(fd, IPPROTO_IP, IP_PKTINFO, true); + if (r < 0) + return r; - return setsockopt_int(fd, IPPROTO_IP, IP_RECVTTL, true); + 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) { @@ -428,14 +451,14 @@ static int manager_dns_stub_udp_fd(Manager *m) { _cleanup_close_ int fd = -1; int r; - if (m->dns_stub_udp_fd >= 0) - return m->dns_stub_udp_fd; + 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); + r = set_dns_stub_common_socket_options(fd, AF_INET); if (r < 0) return r; @@ -451,70 +474,84 @@ static int manager_dns_stub_udp_fd(Manager *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 m->dns_stub_udp_fd = TAKE_FD(fd); + 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; - if (l->fd >= 0) + if (l->udp_event_source) return 0; - fd = socket(socket_address_family(&l->address), SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 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; } - r = setsockopt_int(fd, IPPROTO_IP, IP_FREEBIND, true); + 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; - r = set_dns_stub_common_socket_options(fd); - if (r < 0) - goto fail; - - if (bind(fd, &l->address.sockaddr.sa, l->address.size) < 0) { + if (bind(fd, &sa.sa, SOCKADDR_LEN(sa)) < 0) { r = -errno; goto fail; } - r = sd_event_add_io(m->event, &l->dns_stub_extra_event_source, fd, EPOLLIN, on_dns_stub_packet, m); + r = sd_event_add_io(m->event, &l->udp_event_source, fd, EPOLLIN, on_dns_stub_packet_extra, m); if (r < 0) goto fail; - (void) sd_event_source_set_description(l->dns_stub_extra_event_source, "dns-stub-udp-extra"); + r = sd_event_source_set_io_fd_own(l->udp_event_source, true); + if (r < 0) + goto fail; - l->fd = TAKE_FD(fd); + (void) sd_event_source_set_description(l->udp_event_source, "dns-stub-udp-extra"); if (DEBUG_LOGGING) { - (void) sockaddr_pretty(&l->address.sockaddr.sa, FAMILY_ADDRESS_SIZE(l->address.sockaddr.sa.sa_family), true, true, &pretty); + (void) in_addr_port_to_string(l->family, &l->address, l->port, &pretty); log_debug("Listening on UDP socket %s.", strnull(pretty)); } - return 0; + return TAKE_FD(fd); - fail: - (void) sockaddr_pretty(&l->address.sockaddr.sa, FAMILY_ADDRESS_SIZE(l->address.sockaddr.sa.sa_family), true, true, &pretty); - if (r == -EADDRINUSE) - return log_warning_errno(r, - "Another process is already listening on UDP socket %s.\n" - "Turning off local DNS stub extra support.", strnull(pretty)); - if (r == -EPERM) - return log_warning_errno(r, - "Failed to listen on UDP socket %s: %m.\n" - "Turning off local DNS stub extra support.", strnull(pretty)); - - assert(r < 0); - - return log_warning_errno(r, "Failed to listen on UDP socket %s, ignoring: %m", strnull(pretty)); +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) { +static int on_dns_stub_stream_packet_internal(DnsStream *s, bool is_extra) { _cleanup_(dns_packet_unrefp) DnsPacket *p = NULL; assert(s); @@ -525,16 +562,23 @@ static int on_dns_stub_stream_packet(DnsStream *s) { if (dns_packet_validate_query(p) > 0) { log_debug("Got DNS stub TCP query packet for id %u", DNS_PACKET_ID(p)); - dns_stub_process_query(s->manager, s, p); + dns_stub_process_query(s->manager, s, p, is_extra); } else log_debug("Invalid DNS stub TCP packet, ignoring."); return 0; } -static int on_dns_stub_stream(sd_event_source *s, int fd, uint32_t revents, void *userdata) { +static int on_dns_stub_stream_packet(DnsStream *s) { + return on_dns_stub_stream_packet_internal(s, false); +} + +static int on_dns_stub_stream_packet_extra(DnsStream *s) { + return on_dns_stub_stream_packet_internal(s, true); +} + +static int on_dns_stub_stream_internal(sd_event_source *s, int fd, uint32_t revents, Manager *m, bool is_extra) { DnsStream *stream; - Manager *m = userdata; int cfd, r; cfd = accept4(fd, NULL, NULL, SOCK_NONBLOCK|SOCK_CLOEXEC); @@ -551,7 +595,7 @@ static int on_dns_stub_stream(sd_event_source *s, int fd, uint32_t revents, void return r; } - stream->on_packet = on_dns_stub_stream_packet; + stream->on_packet = is_extra ? on_dns_stub_stream_packet_extra : on_dns_stub_stream_packet; stream->complete = dns_stub_stream_complete; /* We let the reference to the stream dangle here, it will be dropped later by the complete callback. */ @@ -559,6 +603,14 @@ static int on_dns_stub_stream(sd_event_source *s, int fd, uint32_t revents, void return 0; } +static int on_dns_stub_stream(sd_event_source *s, int fd, uint32_t revents, void *userdata) { + return on_dns_stub_stream_internal(s, fd, revents, userdata, false); +} + +static int on_dns_stub_stream_extra(sd_event_source *s, int fd, uint32_t revents, void *userdata) { + return on_dns_stub_stream_internal(s, fd, revents, userdata, true); +} + static int manager_dns_stub_tcp_fd(Manager *m) { union sockaddr_union sa = { .in.sin_family = AF_INET, @@ -568,14 +620,14 @@ static int manager_dns_stub_tcp_fd(Manager *m) { _cleanup_close_ int fd = -1; int r; - if (m->dns_stub_tcp_fd >= 0) - return m->dns_stub_tcp_fd; + if (m->dns_stub_tcp_event_source) + return sd_event_source_get_io_fd(m->dns_stub_tcp_event_source); fd = socket(AF_INET, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0); if (fd < 0) return -errno; - r = set_dns_stub_common_socket_options(fd); + r = set_dns_stub_common_socket_options(fd, AF_INET); if (r < 0) return r; @@ -598,38 +650,58 @@ static int manager_dns_stub_tcp_fd(Manager *m) { if (r < 0) return r; + r = sd_event_source_set_io_fd_own(m->dns_stub_tcp_event_source, true); + if (r < 0) + return r; + (void) sd_event_source_set_description(m->dns_stub_tcp_event_source, "dns-stub-tcp"); - return m->dns_stub_tcp_fd = TAKE_FD(fd); + return TAKE_FD(fd); } static int manager_dns_stub_tcp_fd_extra(Manager *m, DNSStubListenerExtra *l) { _cleanup_free_ char *pretty = NULL; _cleanup_close_ int fd = -1; + union sockaddr_union sa; int r; - if (l->fd >= 0) - return 0; + if (l->tcp_event_source) + return sd_event_source_get_io_fd(l->tcp_event_source);; - fd = socket(socket_address_family(&l->address), SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 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_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0); if (fd < 0) { r = -errno; goto fail; } - r = set_dns_stub_common_socket_options(fd); + r = set_dns_stub_common_socket_options(fd, l->family); if (r < 0) goto fail; - r = setsockopt_int(fd, IPPROTO_IP, IP_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); + else + r = setsockopt_int(fd, IPPROTO_IPV6, IPV6_FREEBIND, true); if (r < 0) goto fail; - r = setsockopt_int(fd, IPPROTO_IP, IP_FREEBIND, true); - if (r < 0) - goto fail; - - if (bind(fd, &l->address.sockaddr.sa, l->address.size) < 0) { + if (bind(fd, &sa.sa, SOCKADDR_LEN(sa)) < 0) { r = -errno; goto fail; } @@ -639,35 +711,29 @@ static int manager_dns_stub_tcp_fd_extra(Manager *m, DNSStubListenerExtra *l) { goto fail; } - r = sd_event_add_io(m->event, &l->dns_stub_extra_event_source, fd, EPOLLIN, on_dns_stub_packet, m); + r = sd_event_add_io(m->event, &l->tcp_event_source, fd, EPOLLIN, on_dns_stub_stream_extra, m); if (r < 0) goto fail; - (void) sd_event_source_set_description(l->dns_stub_extra_event_source, "dns-stub-tcp-extra"); + r = sd_event_source_set_io_fd_own(l->tcp_event_source, true); + if (r < 0) + goto fail; - l->fd = TAKE_FD(fd); + (void) sd_event_source_set_description(l->tcp_event_source, "dns-stub-tcp-extra"); if (DEBUG_LOGGING) { - (void) sockaddr_pretty(&l->address.sockaddr.sa, FAMILY_ADDRESS_SIZE(l->address.sockaddr.sa.sa_family), true, true, &pretty); + (void) in_addr_port_to_string(l->family, &l->address, l->port, &pretty); log_debug("Listening on TCP socket %s.", strnull(pretty)); } - return 0; + return TAKE_FD(fd); - fail: - (void) sockaddr_pretty(&l->address.sockaddr.sa, FAMILY_ADDRESS_SIZE(l->address.sockaddr.sa.sa_family), true, true, &pretty); - if (r == -EADDRINUSE) - return log_warning_errno(r, - "Another process is already listening on TCP socket %s.\n" - "Turning off local DNS stub extra support.", strnull(pretty)); - if (r == -EPERM) - return log_warning_errno(r, - "Failed to listen on TCP socket %s: %m.\n" - "Turning off local DNS stub extra support.", strnull(pretty)); - - assert(r < 0); - - return log_warning_errno(r, "Failed to listen on TCP socket %s, ignoring: %m", strnull(pretty)); +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)); } int manager_dns_stub_start(Manager *m) { @@ -684,11 +750,11 @@ int manager_dns_stub_start(Manager *m) { m->dns_stub_listener_mode == DNS_STUB_LISTENER_TCP ? "TCP" : "UDP/TCP"); - if (IN_SET(m->dns_stub_listener_mode, DNS_STUB_LISTENER_YES, DNS_STUB_LISTENER_UDP)) + if (FLAGS_SET(m->dns_stub_listener_mode, DNS_STUB_LISTENER_UDP)) r = manager_dns_stub_udp_fd(m); if (r >= 0 && - IN_SET(m->dns_stub_listener_mode, DNS_STUB_LISTENER_YES, DNS_STUB_LISTENER_TCP)) { + FLAGS_SET(m->dns_stub_listener_mode, DNS_STUB_LISTENER_TCP)) { t = "TCP"; r = manager_dns_stub_tcp_fd(m); } @@ -710,16 +776,14 @@ int manager_dns_stub_start(Manager *m) { DNSStubListenerExtra *l; Iterator i; - log_debug("Creating stub listener extra using %s.", - m->dns_stub_listener_mode == DNS_STUB_LISTENER_UDP ? "UDP" : - m->dns_stub_listener_mode == DNS_STUB_LISTENER_TCP ? "TCP" : - "UDP/TCP"); + log_debug("Creating extra stub listeners."); - ORDERED_SET_FOREACH(l, m->dns_extra_stub_listeners, i) - if (l->mode == DNS_STUB_LISTENER_UDP) + ORDERED_SET_FOREACH(l, m->dns_extra_stub_listeners, i) { + if (FLAGS_SET(l->mode, DNS_STUB_LISTENER_UDP)) (void) manager_dns_stub_udp_fd_extra(m, l); - else + if (FLAGS_SET(l->mode, DNS_STUB_LISTENER_TCP)) (void) manager_dns_stub_tcp_fd_extra(m, l); + } } return 0; @@ -730,19 +794,4 @@ void manager_dns_stub_stop(Manager *m) { m->dns_stub_udp_event_source = sd_event_source_unref(m->dns_stub_udp_event_source); m->dns_stub_tcp_event_source = sd_event_source_unref(m->dns_stub_tcp_event_source); - - m->dns_stub_udp_fd = safe_close(m->dns_stub_udp_fd); - m->dns_stub_tcp_fd = safe_close(m->dns_stub_tcp_fd); -} - -void manager_dns_stub_stop_extra(Manager *m) { - DNSStubListenerExtra *l; - Iterator i; - - assert(m); - - ORDERED_SET_FOREACH(l, m->dns_extra_stub_listeners, i) { - l->dns_stub_extra_event_source = sd_event_source_unref(l->dns_stub_extra_event_source); - l->fd = safe_close(l->fd); - } } diff --git a/src/resolve/resolved-dns-stub.h b/src/resolve/resolved-dns-stub.h index e589df3831..96d65af152 100644 --- a/src/resolve/resolved-dns-stub.h +++ b/src/resolve/resolved-dns-stub.h @@ -3,8 +3,8 @@ #include "resolved-manager.h" -int dns_stub_extra_new(DNSStubListenerExtra **ret); +int dns_stub_listener_extra_new(DNSStubListenerExtra **ret); +DNSStubListenerExtra *dns_stub_listener_extra_free(DNSStubListenerExtra *p); void manager_dns_stub_stop(Manager *m); -void manager_dns_stub_stop_extra(Manager *m); int manager_dns_stub_start(Manager *m); diff --git a/src/resolve/resolved-manager.c b/src/resolve/resolved-manager.c index 5c09de0c34..ddd336b489 100644 --- a/src/resolve/resolved-manager.c +++ b/src/resolve/resolved-manager.c @@ -578,8 +578,6 @@ int manager_new(Manager **ret) { .llmnr_ipv6_tcp_fd = -1, .mdns_ipv4_fd = -1, .mdns_ipv6_fd = -1, - .dns_stub_udp_fd = -1, - .dns_stub_tcp_fd = -1, .hostname_fd = -1, .llmnr_support = DEFAULT_LLMNR_MODE, @@ -701,7 +699,6 @@ Manager *manager_free(Manager *m) { hashmap_free(m->links); hashmap_free(m->dns_transactions); - ordered_set_free(m->dns_extra_stub_listeners); sd_event_source_unref(m->network_event_source); sd_network_monitor_unref(m->network_monitor); @@ -714,7 +711,7 @@ Manager *manager_free(Manager *m) { manager_dns_stub_stop(m); manager_varlink_done(m); - manager_dns_stub_stop_extra(m); + ordered_set_free(m->dns_extra_stub_listeners); bus_verify_polkit_async_registry_free(m->polkit_registry); @@ -793,6 +790,7 @@ int manager_recv(Manager *m, int fd, DnsProtocol protocol, DnsPacket **ret) { p->size = (size_t) l; + p->fd = fd; p->family = sa.sa.sa_family; p->ipproto = IPPROTO_UDP; if (p->family == AF_INET) { diff --git a/src/resolve/resolved-manager.h b/src/resolve/resolved-manager.h index a3a2e08123..80665876b2 100644 --- a/src/resolve/resolved-manager.h +++ b/src/resolve/resolved-manager.h @@ -32,11 +32,14 @@ typedef struct EtcHosts { } EtcHosts; typedef struct DNSStubListenerExtra { - int fd; - DnsStubListenerMode mode; - SocketAddress address; - sd_event_source *dns_stub_extra_event_source; + + int family; + union in_addr_union address; + uint16_t port; + + sd_event_source *udp_event_source; + sd_event_source *tcp_event_source; } DNSStubListenerExtra; struct Manager { @@ -141,12 +144,9 @@ struct Manager { dev_t etc_hosts_dev; bool read_etc_hosts; - /* Local DNS stub on 127.0.0.53:53 */ - int dns_stub_udp_fd; - int dns_stub_tcp_fd; - OrderedSet *dns_extra_stub_listeners; + /* Local DNS stub on 127.0.0.53:53 */ sd_event_source *dns_stub_udp_event_source; sd_event_source *dns_stub_tcp_event_source; diff --git a/src/shared/socket-netlink.c b/src/shared/socket-netlink.c index 32e45985b4..6c121a4c9a 100644 --- a/src/shared/socket-netlink.c +++ b/src/shared/socket-netlink.c @@ -235,33 +235,6 @@ int socket_address_parse_and_warn(SocketAddress *a, const char *s) { return 0; } -int socket_addr_port_from_string_auto(const char *s, uint16_t default_port, SocketAddress *a) { - union in_addr_union address; - uint16_t port = 0; - int family, r; - - assert(a); - assert(s); - - r = in_addr_port_ifindex_name_from_string_auto(s, &family, &address, &port, NULL, NULL); - if (r < 0) - return r; - - if (family == AF_INET) { - memcpy(&a->sockaddr.in.sin_addr, &address.in.s_addr, sizeof(a->sockaddr.in.sin_addr)); - a->sockaddr.in.sin_family = AF_INET; - a->size = sizeof(struct sockaddr_in); - a->sockaddr.in.sin_port = port ? htobe16(port) : htobe16(default_port); - } else { - memcpy(&a->sockaddr.in6.sin6_addr, &address.in6, sizeof(a->sockaddr.in6.sin6_addr)); - a->sockaddr.in6.sin6_family = AF_INET6; - a->sockaddr.in6.sin6_port = port ? htobe16(port) : htobe16(default_port); - a->size = sizeof(struct sockaddr_in6); - } - - return 0; -} - int socket_address_parse_netlink(SocketAddress *a, const char *s) { _cleanup_free_ char *word = NULL; unsigned group = 0; @@ -482,6 +455,36 @@ 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 143fc8d41a..d019bb31c6 100644 --- a/src/shared/socket-netlink.h +++ b/src/shared/socket-netlink.h @@ -16,7 +16,6 @@ int make_socket_fd(int log_level, const char* address, int type, int flags); int socket_address_parse(SocketAddress *a, const char *s); int socket_address_parse_and_warn(SocketAddress *a, const char *s); int socket_address_parse_netlink(SocketAddress *a, const char *s); -int socket_addr_port_from_string_auto(const char *s, uint16_t default_port, SocketAddress *a); bool socket_address_is(const SocketAddress *a, const char *s, int type); bool socket_address_is_netlink(const SocketAddress *a, const char *s); @@ -34,6 +33,7 @@ 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 916bd35f0d..63e9800ec8 100644 --- a/src/test/test-in-addr-util.c +++ b/src/test/test-in-addr-util.c @@ -177,10 +177,163 @@ static void test_in_addr_random_prefix(void) { str = mfree(str); } +static void test_in_addr_is_null(void) { + union in_addr_union i = {}; + + log_info("/* %s */", __func__); + + assert_se(in_addr_is_null(AF_INET, &i) == true); + assert_se(in_addr_is_null(AF_INET6, &i) == true); + + i.in.s_addr = 0x1000000; + assert_se(in_addr_is_null(AF_INET, &i) == false); + assert_se(in_addr_is_null(AF_INET6, &i) == false); + + assert_se(in_addr_is_null(-1, &i) == -EAFNOSUPPORT); +} + +static void test_in_addr_prefix_intersect_one(unsigned f, const char *a, unsigned apl, const char *b, unsigned bpl, int result) { + union in_addr_union ua, ub; + + assert_se(in_addr_from_string(f, a, &ua) >= 0); + assert_se(in_addr_from_string(f, b, &ub) >= 0); + + assert_se(in_addr_prefix_intersect(f, &ua, apl, &ub, bpl) == result); +} + +static void test_in_addr_prefix_intersect(void) { + log_info("/* %s */", __func__); + + test_in_addr_prefix_intersect_one(AF_INET, "255.255.255.255", 32, "255.255.255.254", 32, 0); + test_in_addr_prefix_intersect_one(AF_INET, "255.255.255.255", 0, "255.255.255.255", 32, 1); + test_in_addr_prefix_intersect_one(AF_INET, "0.0.0.0", 0, "47.11.8.15", 32, 1); + + test_in_addr_prefix_intersect_one(AF_INET, "1.1.1.1", 24, "1.1.1.1", 24, 1); + test_in_addr_prefix_intersect_one(AF_INET, "2.2.2.2", 24, "1.1.1.1", 24, 0); + + test_in_addr_prefix_intersect_one(AF_INET, "1.1.1.1", 24, "1.1.1.127", 25, 1); + test_in_addr_prefix_intersect_one(AF_INET, "1.1.1.1", 24, "1.1.1.127", 26, 1); + test_in_addr_prefix_intersect_one(AF_INET, "1.1.1.1", 25, "1.1.1.127", 25, 1); + test_in_addr_prefix_intersect_one(AF_INET, "1.1.1.1", 25, "1.1.1.255", 25, 0); + + test_in_addr_prefix_intersect_one(AF_INET6, "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff", 128, "ffff:ffff:ffff:ffff:ffff:ffff:ffff:fffe", 128, 0); + test_in_addr_prefix_intersect_one(AF_INET6, "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff", 0, "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff", 128, 1); + test_in_addr_prefix_intersect_one(AF_INET6, "::", 0, "beef:beef:beef:beef:beef:beef:beef:beef", 128, 1); + + test_in_addr_prefix_intersect_one(AF_INET6, "1::2", 64, "1::2", 64, 1); + test_in_addr_prefix_intersect_one(AF_INET6, "2::2", 64, "1::2", 64, 0); + + test_in_addr_prefix_intersect_one(AF_INET6, "1::1", 120, "1::007f", 121, 1); + test_in_addr_prefix_intersect_one(AF_INET6, "1::1", 120, "1::007f", 122, 1); + test_in_addr_prefix_intersect_one(AF_INET6, "1::1", 121, "1::007f", 121, 1); + test_in_addr_prefix_intersect_one(AF_INET6, "1::1", 121, "1::00ff", 121, 0); +} + +static void test_in_addr_prefix_next_one(unsigned f, const char *before, unsigned pl, const char *after) { + union in_addr_union ubefore, uafter, t; + + assert_se(in_addr_from_string(f, before, &ubefore) >= 0); + + t = ubefore; + assert_se((in_addr_prefix_next(f, &t, pl) > 0) == !!after); + + if (after) { + assert_se(in_addr_from_string(f, after, &uafter) >= 0); + assert_se(in_addr_equal(f, &t, &uafter) > 0); + } +} + +static void test_in_addr_prefix_next(void) { + log_info("/* %s */", __func__); + + test_in_addr_prefix_next_one(AF_INET, "192.168.0.0", 24, "192.168.1.0"); + test_in_addr_prefix_next_one(AF_INET, "192.168.0.0", 16, "192.169.0.0"); + test_in_addr_prefix_next_one(AF_INET, "192.168.0.0", 20, "192.168.16.0"); + + test_in_addr_prefix_next_one(AF_INET, "0.0.0.0", 32, "0.0.0.1"); + test_in_addr_prefix_next_one(AF_INET, "255.255.255.255", 32, NULL); + test_in_addr_prefix_next_one(AF_INET, "255.255.255.0", 24, NULL); + + test_in_addr_prefix_next_one(AF_INET6, "4400::", 128, "4400::0001"); + test_in_addr_prefix_next_one(AF_INET6, "4400::", 120, "4400::0100"); + test_in_addr_prefix_next_one(AF_INET6, "4400::", 127, "4400::0002"); + test_in_addr_prefix_next_one(AF_INET6, "4400::", 8, "4500::"); + test_in_addr_prefix_next_one(AF_INET6, "4400::", 7, "4600::"); + + test_in_addr_prefix_next_one(AF_INET6, "::", 128, "::1"); + + test_in_addr_prefix_next_one(AF_INET6, "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff", 128, NULL); + test_in_addr_prefix_next_one(AF_INET6, "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ff00", 120, NULL); +} + +static void test_in_addr_prefix_nth_one(unsigned f, const char *before, unsigned pl, uint64_t nth, const char *after) { + union in_addr_union ubefore, uafter, t; + + assert_se(in_addr_from_string(f, before, &ubefore) >= 0); + + t = ubefore; + assert_se((in_addr_prefix_nth(f, &t, pl, nth) > 0) == !!after); + + if (after) { + assert_se(in_addr_from_string(f, after, &uafter) >= 0); + assert_se(in_addr_equal(f, &t, &uafter) > 0); + } +} + +static void test_in_addr_prefix_nth(void) { + log_info("/* %s */", __func__); + + test_in_addr_prefix_nth_one(AF_INET, "192.168.0.0", 24, 0, "192.168.0.0"); + test_in_addr_prefix_nth_one(AF_INET, "192.168.0.0", 24, 1, "192.168.1.0"); + test_in_addr_prefix_nth_one(AF_INET, "192.168.0.0", 24, 4, "192.168.4.0"); + test_in_addr_prefix_nth_one(AF_INET, "192.168.0.0", 25, 1, "192.168.0.128"); + test_in_addr_prefix_nth_one(AF_INET, "192.168.255.0", 25, 1, "192.168.255.128"); + test_in_addr_prefix_nth_one(AF_INET, "192.168.255.0", 24, 0, "192.168.255.0"); + test_in_addr_prefix_nth_one(AF_INET, "255.255.255.255", 32, 1, NULL); + test_in_addr_prefix_nth_one(AF_INET, "255.255.255.255", 0, 1, NULL); + + test_in_addr_prefix_nth_one(AF_INET6, "4400::", 8, 1, "4500::"); + test_in_addr_prefix_nth_one(AF_INET6, "4400::", 7, 1, "4600::"); + test_in_addr_prefix_nth_one(AF_INET6, "4400::", 64, 1, "4400:0:0:1::"); + test_in_addr_prefix_nth_one(AF_INET6, "4400::", 64, 2, "4400:0:0:2::"); + test_in_addr_prefix_nth_one(AF_INET6, "4400::", 64, 0xbad, "4400:0:0:0bad::"); + test_in_addr_prefix_nth_one(AF_INET6, "4400:0:0:ffff::", 64, 1, "4400:0:1::"); + test_in_addr_prefix_nth_one(AF_INET6, "4400::", 56, ((uint64_t)1<<48) -1, "44ff:ffff:ffff:ff00::"); + test_in_addr_prefix_nth_one(AF_INET6, "0000::", 8, 255, "ff00::"); + test_in_addr_prefix_nth_one(AF_INET6, "0000::", 8, 256, NULL); + test_in_addr_prefix_nth_one(AF_INET6, "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff", 128, 1, NULL); + test_in_addr_prefix_nth_one(AF_INET6, "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff", 0, 1, NULL); +} + +static void test_in_addr_to_string_one(int f, const char *addr) { + union in_addr_union ua; + _cleanup_free_ char *r = NULL; + + assert_se(in_addr_from_string(f, addr, &ua) >= 0); + assert_se(in_addr_to_string(f, &ua, &r) >= 0); + printf("test_in_addr_to_string_one: %s == %s\n", addr, r); + assert_se(streq(addr, r)); +} + +static void test_in_addr_to_string(void) { + log_info("/* %s */", __func__); + + test_in_addr_to_string_one(AF_INET, "192.168.0.1"); + test_in_addr_to_string_one(AF_INET, "10.11.12.13"); + test_in_addr_to_string_one(AF_INET6, "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff"); + test_in_addr_to_string_one(AF_INET6, "::1"); + test_in_addr_to_string_one(AF_INET6, "fe80::"); +} + int main(int argc, char *argv[]) { test_in_addr_prefix_from_string(); test_in_addr_random_prefix(); test_in_addr_prefix_to_string(); + test_in_addr_is_null(); + test_in_addr_prefix_intersect(); + test_in_addr_prefix_next(); + test_in_addr_prefix_nth(); + test_in_addr_to_string(); return 0; } diff --git a/src/test/test-socket-netlink.c b/src/test/test-socket-netlink.c index 4335d2eb6c..f86f123782 100644 --- a/src/test/test-socket-netlink.c +++ b/src/test/test-socket-netlink.c @@ -1,6 +1,7 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ #include "alloc-util.h" +#include "missing_network.h" #include "tests.h" #include "socket-netlink.h" #include "string-util.h" @@ -213,39 +214,136 @@ static void test_socket_address_is_netlink(void) { assert_se(!socket_address_is_netlink(&a, "route 1")); } -static void test_socket_addr_port_from_string_auto_one(const char *in, uint16_t port, int ret, int family, const char *expected) { - _cleanup_free_ char *out = NULL; - SocketAddress a; - int r; +static void test_in_addr_ifindex_to_string_one(int f, const char *a, int ifindex, const char *b) { + _cleanup_free_ char *r = NULL; + union in_addr_union ua, uuaa; + int ff, ifindex2; - r = socket_addr_port_from_string_auto(in, port, &a); - if (r >= 0) - assert_se(sockaddr_pretty(&a.sockaddr.sa, a.size, false, true, &out) >= 0); + assert_se(in_addr_from_string(f, a, &ua) >= 0); + assert_se(in_addr_ifindex_to_string(f, &ua, ifindex, &r) >= 0); + printf("test_in_addr_ifindex_to_string_one: %s == %s\n", b, r); + assert_se(streq(b, r)); - log_info("\"%s\" → %s → \"%s\" (expect \"%s\")", in, - r >= 0 ? "✓" : "✗", empty_to_dash(out), r >= 0 ? expected ?: in : "-"); - assert_se(r == ret); - if (r >= 0) { - assert_se(a.sockaddr.sa.sa_family == family); - assert_se(streq(out, expected ?: in)); - } + assert_se(in_addr_ifindex_from_string_auto(b, &ff, &uuaa, &ifindex2) >= 0); + assert_se(ff == f); + assert_se(in_addr_equal(f, &ua, &uuaa)); + assert_se(ifindex2 == ifindex || ifindex2 == 0); } -static void test_socket_addr_port_from_string_auto(void) { +static void test_in_addr_ifindex_to_string(void) { log_info("/* %s */", __func__); - test_socket_addr_port_from_string_auto_one("junk", 51, -EINVAL, 0, NULL); - test_socket_addr_port_from_string_auto_one("192.168.1.1", 53, 0, AF_INET, "192.168.1.1:53"); - test_socket_addr_port_from_string_auto_one(".168.1.1", 53, -EINVAL, 0, NULL); - test_socket_addr_port_from_string_auto_one("989.168.1.1", 53, -EINVAL, 0, NULL); + test_in_addr_ifindex_to_string_one(AF_INET, "192.168.0.1", 7, "192.168.0.1"); + test_in_addr_ifindex_to_string_one(AF_INET, "10.11.12.13", 9, "10.11.12.13"); + test_in_addr_ifindex_to_string_one(AF_INET6, "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff", 10, "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff"); + test_in_addr_ifindex_to_string_one(AF_INET6, "::1", 11, "::1"); + test_in_addr_ifindex_to_string_one(AF_INET6, "fe80::", 12, "fe80::%12"); + test_in_addr_ifindex_to_string_one(AF_INET6, "fe80::", 0, "fe80::"); + test_in_addr_ifindex_to_string_one(AF_INET6, "fe80::14", 12, "fe80::14%12"); + test_in_addr_ifindex_to_string_one(AF_INET6, "fe80::15", -7, "fe80::15"); + test_in_addr_ifindex_to_string_one(AF_INET6, "fe80::16", LOOPBACK_IFINDEX, "fe80::16%1"); +} - test_socket_addr_port_from_string_auto_one("[::1]", 53, -EINVAL, 0, NULL); - test_socket_addr_port_from_string_auto_one("[::1]8888", 53, -EINVAL, 0, NULL); - test_socket_addr_port_from_string_auto_one("2001:db8:3c4d:15::1a2f:1a2b", 53, 0, AF_INET6, "[2001:db8:3c4d:15::1a2f:1a2b]:53"); - test_socket_addr_port_from_string_auto_one("[2001:db8:3c4d:15::1a2f:1a2b]:2001", 53, 0, AF_INET6, "[2001:db8:3c4d:15::1a2f:1a2b]:2001"); - test_socket_addr_port_from_string_auto_one("[::1]:0", 53, -EINVAL, 0, NULL); - test_socket_addr_port_from_string_auto_one("[::1]:65536", 53, -ERANGE, 0, NULL); - test_socket_addr_port_from_string_auto_one("[a:b:1]:8888", 53, -EINVAL, 0, NULL); +static void test_in_addr_ifindex_from_string_auto(void) { + int family, ifindex; + union in_addr_union ua; + + log_info("/* %s */", __func__); + /* Most in_addr_ifindex_from_string_auto() invocations have already been tested above, but let's test some more */ + + assert_se(in_addr_ifindex_from_string_auto("fe80::17", &family, &ua, &ifindex) >= 0); + assert_se(family == AF_INET6); + assert_se(ifindex == 0); + + assert_se(in_addr_ifindex_from_string_auto("fe80::18%19", &family, &ua, &ifindex) >= 0); + assert_se(family == AF_INET6); + assert_se(ifindex == 19); + + assert_se(in_addr_ifindex_from_string_auto("fe80::18%lo", &family, &ua, &ifindex) >= 0); + assert_se(family == AF_INET6); + assert_se(ifindex == LOOPBACK_IFINDEX); + + assert_se(in_addr_ifindex_from_string_auto("fe80::19%thisinterfacecantexist", &family, &ua, &ifindex) == -ENODEV); +} + +static void test_in_addr_ifindex_name_from_string_auto_one(const char *a, const char *expected) { + int family, ifindex; + union in_addr_union ua; + _cleanup_free_ char *server_name = NULL; + + assert_se(in_addr_ifindex_name_from_string_auto(a, &family, &ua, &ifindex, &server_name) >= 0); + assert_se(streq_ptr(server_name, expected)); +} + +static void test_in_addr_ifindex_name_from_string_auto(void) { + log_info("/* %s */", __func__); + + test_in_addr_ifindex_name_from_string_auto_one("192.168.0.1", NULL); + test_in_addr_ifindex_name_from_string_auto_one("192.168.0.1#test.com", "test.com"); + test_in_addr_ifindex_name_from_string_auto_one("fe80::18%19", NULL); + 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; + union in_addr_union a; + uint16_t p; + int f, i; + + 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)); +} + +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); } int main(int argc, char *argv[]) { @@ -257,7 +355,12 @@ int main(int argc, char *argv[]) { test_socket_address_get_path(); test_socket_address_is(); test_socket_address_is_netlink(); - test_socket_addr_port_from_string_auto(); + + test_in_addr_ifindex_to_string(); + 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 b007dd6276..0bc713cb53 100644 --- a/src/test/test-socket-util.c +++ b/src/test/test-socket-util.c @@ -15,9 +15,7 @@ #include "io-util.h" #include "log.h" #include "macro.h" -#include "missing_network.h" #include "process-util.h" -#include "socket-netlink.h" #include "socket-util.h" #include "string-util.h" #include "tests.h" @@ -84,256 +82,6 @@ static void test_socket_print_unix(void) { test_socket_print_unix_one("\0\a\b\n\255", 6, "@\\a\\b\\n\\255\\000"); } -static void test_in_addr_is_null(void) { - union in_addr_union i = {}; - - log_info("/* %s */", __func__); - - assert_se(in_addr_is_null(AF_INET, &i) == true); - assert_se(in_addr_is_null(AF_INET6, &i) == true); - - i.in.s_addr = 0x1000000; - assert_se(in_addr_is_null(AF_INET, &i) == false); - assert_se(in_addr_is_null(AF_INET6, &i) == false); - - assert_se(in_addr_is_null(-1, &i) == -EAFNOSUPPORT); -} - -static void test_in_addr_prefix_intersect_one(unsigned f, const char *a, unsigned apl, const char *b, unsigned bpl, int result) { - union in_addr_union ua, ub; - - assert_se(in_addr_from_string(f, a, &ua) >= 0); - assert_se(in_addr_from_string(f, b, &ub) >= 0); - - assert_se(in_addr_prefix_intersect(f, &ua, apl, &ub, bpl) == result); -} - -static void test_in_addr_prefix_intersect(void) { - log_info("/* %s */", __func__); - - test_in_addr_prefix_intersect_one(AF_INET, "255.255.255.255", 32, "255.255.255.254", 32, 0); - test_in_addr_prefix_intersect_one(AF_INET, "255.255.255.255", 0, "255.255.255.255", 32, 1); - test_in_addr_prefix_intersect_one(AF_INET, "0.0.0.0", 0, "47.11.8.15", 32, 1); - - test_in_addr_prefix_intersect_one(AF_INET, "1.1.1.1", 24, "1.1.1.1", 24, 1); - test_in_addr_prefix_intersect_one(AF_INET, "2.2.2.2", 24, "1.1.1.1", 24, 0); - - test_in_addr_prefix_intersect_one(AF_INET, "1.1.1.1", 24, "1.1.1.127", 25, 1); - test_in_addr_prefix_intersect_one(AF_INET, "1.1.1.1", 24, "1.1.1.127", 26, 1); - test_in_addr_prefix_intersect_one(AF_INET, "1.1.1.1", 25, "1.1.1.127", 25, 1); - test_in_addr_prefix_intersect_one(AF_INET, "1.1.1.1", 25, "1.1.1.255", 25, 0); - - test_in_addr_prefix_intersect_one(AF_INET6, "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff", 128, "ffff:ffff:ffff:ffff:ffff:ffff:ffff:fffe", 128, 0); - test_in_addr_prefix_intersect_one(AF_INET6, "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff", 0, "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff", 128, 1); - test_in_addr_prefix_intersect_one(AF_INET6, "::", 0, "beef:beef:beef:beef:beef:beef:beef:beef", 128, 1); - - test_in_addr_prefix_intersect_one(AF_INET6, "1::2", 64, "1::2", 64, 1); - test_in_addr_prefix_intersect_one(AF_INET6, "2::2", 64, "1::2", 64, 0); - - test_in_addr_prefix_intersect_one(AF_INET6, "1::1", 120, "1::007f", 121, 1); - test_in_addr_prefix_intersect_one(AF_INET6, "1::1", 120, "1::007f", 122, 1); - test_in_addr_prefix_intersect_one(AF_INET6, "1::1", 121, "1::007f", 121, 1); - test_in_addr_prefix_intersect_one(AF_INET6, "1::1", 121, "1::00ff", 121, 0); -} - -static void test_in_addr_prefix_next_one(unsigned f, const char *before, unsigned pl, const char *after) { - union in_addr_union ubefore, uafter, t; - - assert_se(in_addr_from_string(f, before, &ubefore) >= 0); - - t = ubefore; - assert_se((in_addr_prefix_next(f, &t, pl) > 0) == !!after); - - if (after) { - assert_se(in_addr_from_string(f, after, &uafter) >= 0); - assert_se(in_addr_equal(f, &t, &uafter) > 0); - } -} - -static void test_in_addr_prefix_next(void) { - log_info("/* %s */", __func__); - - test_in_addr_prefix_next_one(AF_INET, "192.168.0.0", 24, "192.168.1.0"); - test_in_addr_prefix_next_one(AF_INET, "192.168.0.0", 16, "192.169.0.0"); - test_in_addr_prefix_next_one(AF_INET, "192.168.0.0", 20, "192.168.16.0"); - - test_in_addr_prefix_next_one(AF_INET, "0.0.0.0", 32, "0.0.0.1"); - test_in_addr_prefix_next_one(AF_INET, "255.255.255.255", 32, NULL); - test_in_addr_prefix_next_one(AF_INET, "255.255.255.0", 24, NULL); - - test_in_addr_prefix_next_one(AF_INET6, "4400::", 128, "4400::0001"); - test_in_addr_prefix_next_one(AF_INET6, "4400::", 120, "4400::0100"); - test_in_addr_prefix_next_one(AF_INET6, "4400::", 127, "4400::0002"); - test_in_addr_prefix_next_one(AF_INET6, "4400::", 8, "4500::"); - test_in_addr_prefix_next_one(AF_INET6, "4400::", 7, "4600::"); - - test_in_addr_prefix_next_one(AF_INET6, "::", 128, "::1"); - - test_in_addr_prefix_next_one(AF_INET6, "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff", 128, NULL); - test_in_addr_prefix_next_one(AF_INET6, "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ff00", 120, NULL); -} - -static void test_in_addr_prefix_nth_one(unsigned f, const char *before, unsigned pl, uint64_t nth, const char *after) { - union in_addr_union ubefore, uafter, t; - - assert_se(in_addr_from_string(f, before, &ubefore) >= 0); - - t = ubefore; - assert_se((in_addr_prefix_nth(f, &t, pl, nth) > 0) == !!after); - - if (after) { - assert_se(in_addr_from_string(f, after, &uafter) >= 0); - assert_se(in_addr_equal(f, &t, &uafter) > 0); - } -} - -static void test_in_addr_prefix_nth(void) { - log_info("/* %s */", __func__); - - test_in_addr_prefix_nth_one(AF_INET, "192.168.0.0", 24, 0, "192.168.0.0"); - test_in_addr_prefix_nth_one(AF_INET, "192.168.0.0", 24, 1, "192.168.1.0"); - test_in_addr_prefix_nth_one(AF_INET, "192.168.0.0", 24, 4, "192.168.4.0"); - test_in_addr_prefix_nth_one(AF_INET, "192.168.0.0", 25, 1, "192.168.0.128"); - test_in_addr_prefix_nth_one(AF_INET, "192.168.255.0", 25, 1, "192.168.255.128"); - test_in_addr_prefix_nth_one(AF_INET, "192.168.255.0", 24, 0, "192.168.255.0"); - test_in_addr_prefix_nth_one(AF_INET, "255.255.255.255", 32, 1, NULL); - test_in_addr_prefix_nth_one(AF_INET, "255.255.255.255", 0, 1, NULL); - - test_in_addr_prefix_nth_one(AF_INET6, "4400::", 8, 1, "4500::"); - test_in_addr_prefix_nth_one(AF_INET6, "4400::", 7, 1, "4600::"); - test_in_addr_prefix_nth_one(AF_INET6, "4400::", 64, 1, "4400:0:0:1::"); - test_in_addr_prefix_nth_one(AF_INET6, "4400::", 64, 2, "4400:0:0:2::"); - test_in_addr_prefix_nth_one(AF_INET6, "4400::", 64, 0xbad, "4400:0:0:0bad::"); - test_in_addr_prefix_nth_one(AF_INET6, "4400:0:0:ffff::", 64, 1, "4400:0:1::"); - test_in_addr_prefix_nth_one(AF_INET6, "4400::", 56, ((uint64_t)1<<48) -1, "44ff:ffff:ffff:ff00::"); - test_in_addr_prefix_nth_one(AF_INET6, "0000::", 8, 255, "ff00::"); - test_in_addr_prefix_nth_one(AF_INET6, "0000::", 8, 256, NULL); - test_in_addr_prefix_nth_one(AF_INET6, "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff", 128, 1, NULL); - test_in_addr_prefix_nth_one(AF_INET6, "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff", 0, 1, NULL); -} - -static void test_in_addr_to_string_one(int f, const char *addr) { - union in_addr_union ua; - _cleanup_free_ char *r = NULL; - - assert_se(in_addr_from_string(f, addr, &ua) >= 0); - assert_se(in_addr_to_string(f, &ua, &r) >= 0); - printf("test_in_addr_to_string_one: %s == %s\n", addr, r); - assert_se(streq(addr, r)); -} - -static void test_in_addr_to_string(void) { - log_info("/* %s */", __func__); - - test_in_addr_to_string_one(AF_INET, "192.168.0.1"); - test_in_addr_to_string_one(AF_INET, "10.11.12.13"); - test_in_addr_to_string_one(AF_INET6, "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff"); - test_in_addr_to_string_one(AF_INET6, "::1"); - test_in_addr_to_string_one(AF_INET6, "fe80::"); -} - -static void test_in_addr_ifindex_to_string_one(int f, const char *a, int ifindex, const char *b) { - _cleanup_free_ char *r = NULL; - union in_addr_union ua, uuaa; - int ff, ifindex2; - - assert_se(in_addr_from_string(f, a, &ua) >= 0); - assert_se(in_addr_ifindex_to_string(f, &ua, ifindex, &r) >= 0); - printf("test_in_addr_ifindex_to_string_one: %s == %s\n", b, r); - assert_se(streq(b, r)); - - assert_se(in_addr_ifindex_from_string_auto(b, &ff, &uuaa, &ifindex2) >= 0); - assert_se(ff == f); - assert_se(in_addr_equal(f, &ua, &uuaa)); - assert_se(ifindex2 == ifindex || ifindex2 == 0); -} - -static void test_in_addr_ifindex_to_string(void) { - log_info("/* %s */", __func__); - - test_in_addr_ifindex_to_string_one(AF_INET, "192.168.0.1", 7, "192.168.0.1"); - test_in_addr_ifindex_to_string_one(AF_INET, "10.11.12.13", 9, "10.11.12.13"); - test_in_addr_ifindex_to_string_one(AF_INET6, "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff", 10, "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff"); - test_in_addr_ifindex_to_string_one(AF_INET6, "::1", 11, "::1"); - test_in_addr_ifindex_to_string_one(AF_INET6, "fe80::", 12, "fe80::%12"); - test_in_addr_ifindex_to_string_one(AF_INET6, "fe80::", 0, "fe80::"); - test_in_addr_ifindex_to_string_one(AF_INET6, "fe80::14", 12, "fe80::14%12"); - test_in_addr_ifindex_to_string_one(AF_INET6, "fe80::15", -7, "fe80::15"); - test_in_addr_ifindex_to_string_one(AF_INET6, "fe80::16", LOOPBACK_IFINDEX, "fe80::16%1"); -} - -static void test_in_addr_ifindex_from_string_auto(void) { - int family, ifindex; - union in_addr_union ua; - - log_info("/* %s */", __func__); - /* Most in_addr_ifindex_from_string_auto() invocations have already been tested above, but let's test some more */ - - assert_se(in_addr_ifindex_from_string_auto("fe80::17", &family, &ua, &ifindex) >= 0); - assert_se(family == AF_INET6); - assert_se(ifindex == 0); - - assert_se(in_addr_ifindex_from_string_auto("fe80::18%19", &family, &ua, &ifindex) >= 0); - assert_se(family == AF_INET6); - assert_se(ifindex == 19); - - assert_se(in_addr_ifindex_from_string_auto("fe80::18%lo", &family, &ua, &ifindex) >= 0); - assert_se(family == AF_INET6); - assert_se(ifindex == LOOPBACK_IFINDEX); - - assert_se(in_addr_ifindex_from_string_auto("fe80::19%thisinterfacecantexist", &family, &ua, &ifindex) == -ENODEV); -} - -static void test_in_addr_ifindex_name_from_string_auto_one(const char *a, const char *expected) { - int family, ifindex; - union in_addr_union ua; - _cleanup_free_ char *server_name = NULL; - - assert_se(in_addr_ifindex_name_from_string_auto(a, &family, &ua, &ifindex, &server_name) >= 0); - assert_se(streq_ptr(server_name, expected)); -} - -static void test_in_addr_ifindex_name_from_string_auto(void) { - log_info("/* %s */", __func__); - - test_in_addr_ifindex_name_from_string_auto_one("192.168.0.1", NULL); - test_in_addr_ifindex_name_from_string_auto_one("192.168.0.1#test.com", "test.com"); - test_in_addr_ifindex_name_from_string_auto_one("fe80::18%19", NULL); - 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; - union in_addr_union a; - uint16_t p; - int f, i; - - 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)); -} - -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_sockaddr_equal(void) { union sockaddr_union a = { .in.sin_family = AF_INET, @@ -759,16 +507,6 @@ int main(int argc, char *argv[]) { test_socket_print_unix(); - test_in_addr_is_null(); - test_in_addr_prefix_intersect(); - test_in_addr_prefix_next(); - test_in_addr_prefix_nth(); - test_in_addr_to_string(); - test_in_addr_ifindex_to_string(); - 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_sockaddr_equal(); test_sockaddr_un_len();