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();