1
0
mirror of https://github.com/systemd/systemd.git synced 2024-10-28 20:25:38 +03:00

Merge pull request #16951 from yuwata/resolve-follow-ups-for-extra-dns-stub-listener

resolve: follow-ups for extra DNS stub listener
This commit is contained in:
Zbigniew Jędrzejewski-Szmek 2020-09-05 15:55:22 +02:00 committed by GitHub
commit ad161cd6bb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
17 changed files with 594 additions and 598 deletions

View File

@ -271,27 +271,27 @@
<varlistentry> <varlistentry>
<term><varname>DNSStubListenerExtra=</varname></term> <term><varname>DNSStubListenerExtra=</varname></term>
<listitem><para>Takes an IPv4 or IPv6 address to listen on. The address may optionally be prefixed by <literal>:</literal> and <listitem><para>Takes an IPv4 or IPv6 address to listen on. The address may be optionally
a protocol name (<literal>udp</literal> or <literal>tcp</literal>). When an IPv6 address is specified with a port number, then the prefixed with a protocol name (<literal>udp</literal> or <literal>tcp</literal>) separated with
address must be in the square brackets. This option can be specified multiple times. If an empty string is assigned, then the all <literal>:</literal>. If the protocol is not specified, the service will listen on both UDP and
previous assignments are cleared. It may also be optionally suffixed by a numeric port number with separator <literal>:</literal>. TCP. It may be also optionally suffixed by a numeric port number with separator
If the protocol is not specified, the service will listen on both <literal>UDP</literal> and <literal>TCP</literal>. If the port is not <literal>:</literal>. When an IPv6 address is specified with a port number, then the address
specified, then the service takes port as 53. This option may be used multiple times. Note that this is independent of the must be in the square brackets. If the port is not specified, then the service uses port 53.
primary DNS stub configured with <varname>DNSStubListener=</varname>, and only configures <emphasis>additional</emphasis> Note that this is independent of the primary DNS stub configured with
sockets to listen on. Defaults to unset.</para> <varname>DNSStubListener=</varname>, and only configures <emphasis>additional</emphasis>
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.</para>
<para>If the string in the format <literal>udp</literal>:[<replaceable>x</replaceable>]:<replaceable>y</replaceable>, <para>Examples:
it is read as protocol <literal>udp</literal> and IPv6 address x on a port y.</para> <programlisting>DNSStubListenerExtra=192.168.10.10
DNSStubListenerExtra=2001:db8:0:f102::10
<para>If the string in the format [<replaceable>x</replaceable>]:<replaceable>y</replaceable>, it is read as both protocol DNSStubListenerExtra=192.168.10.11:9953
<literal>udp</literal> and <literal>tcp</literal>, IPv6 address x on a port y.</para> DNSStubListenerExtra=[2001:db8:0:f102::11]:9953
DNSStubListenerExtra=tcp:192.168.10.12
<para>If the string in the format <replaceable>x</replaceable>, it is read as protocol both <literal>udp</literal> and DNSStubListenerExtra=udp:2001:db8:0:f102::12
<literal>tcp</literal>, IPv6/IPv4 address x on a port 53.</para> DNSStubListenerExtra=tcp:192.168.10.13:9953
DNSStubListenerExtra=udp:[2001:db8:0:f102::13]:9953</programlisting>
<para>If the string in the format <literal>udp</literal>:<replaceable>x</replaceable>:<replaceable>y</replaceable>, </para></listitem>
it is read as protocol <literal>udp</literal> and IPv4 address x on a port y.</para>
</listitem>
</varlistentry> </varlistentry>
<varlistentry> <varlistentry>

View File

@ -402,46 +402,6 @@ int in_addr_prefix_to_string(int family, const union in_addr_union *u, unsigned
return 0; 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) { 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; _cleanup_free_ char *ip_str = NULL, *x = NULL;
int r; int r;

View File

@ -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_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_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_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); 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(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); int in_addr_from_string_auto(const char *s, int *ret_family, union in_addr_union *ret);

View File

@ -63,6 +63,10 @@ struct sockaddr_vm {
#define IP_TRANSPARENT 19 #define IP_TRANSPARENT 19
#endif #endif
#ifndef IPV6_FREEBIND
#define IPV6_FREEBIND 78
#endif
/* linux/sockios.h */ /* linux/sockios.h */
#ifndef SIOCGSKNS #ifndef SIOCGSKNS
#define SIOCGSKNS 0x894C #define SIOCGSKNS 0x894C

View File

@ -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); \ 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 socket_ioctl_fd(void);
int sockaddr_un_set_path(struct sockaddr_un *ret, const char *path); int sockaddr_un_set_path(struct sockaddr_un *ret, const char *path);

View File

@ -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); 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) { static void dns_stub_listener_extra_hash_func(const DNSStubListenerExtra *a, struct siphash *state) {
unsigned port;
assert(a); assert(a);
siphash24_compress(&a->mode, sizeof(a->mode), state); siphash24_compress(&a->mode, sizeof(a->mode), state);
siphash24_compress(&socket_address_family(&a->address), sizeof(a->address.type), state); siphash24_compress(&a->family, sizeof(a->family), state);
siphash24_compress(&a->address, FAMILY_ADDRESS_SIZE(socket_address_family(&a->address)), state); siphash24_compress(&a->address, FAMILY_ADDRESS_SIZE(a->family), state);
siphash24_compress(&a->port, sizeof(a->port), state);
(void) sockaddr_port(&a->address.sockaddr.sa, &port);
siphash24_compress(&port, sizeof(port), state);
} }
static int dns_stub_listener_extra_compare_func(const DNSStubListenerExtra *a, const DNSStubListenerExtra *b) { static int dns_stub_listener_extra_compare_func(const DNSStubListenerExtra *a, const DNSStubListenerExtra *b) {
unsigned p, q;
int r; int r;
assert(a); assert(a);
@ -53,18 +48,15 @@ static int dns_stub_listener_extra_compare_func(const DNSStubListenerExtra *a, c
if (r != 0) if (r != 0)
return r; return r;
r = CMP(socket_address_family(&a->address), socket_address_family(&b->address)); r = CMP(a->family, b->family);
if (r != 0) if (r != 0)
return r; 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) if (r != 0)
return r; return r;
(void) sockaddr_port(&a->address.sockaddr.sa, &p); return CMP(a->port, b->port);
(void) sockaddr_port(&b->address.sockaddr.sa, &q);
return CMP(p, q);
} }
DEFINE_PRIVATE_HASH_OPS_WITH_KEY_DESTRUCTOR( DEFINE_PRIVATE_HASH_OPS_WITH_KEY_DESTRUCTOR(
@ -72,7 +64,7 @@ DEFINE_PRIVATE_HASH_OPS_WITH_KEY_DESTRUCTOR(
DNSStubListenerExtra, DNSStubListenerExtra,
dns_stub_listener_extra_hash_func, dns_stub_listener_extra_hash_func,
dns_stub_listener_extra_compare_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) { static int manager_add_dns_server_by_string(Manager *m, DnsServerType type, const char *word) {
_cleanup_free_ char *server_name = NULL; _cleanup_free_ char *server_name = NULL;
@ -444,10 +436,8 @@ int config_parse_dns_stub_listener_extra(
void *data, void *data,
void *userdata) { void *userdata) {
_cleanup_free_ DNSStubListenerExtra *udp = NULL, *tcp = NULL; _cleanup_free_ DNSStubListenerExtra *stub = NULL;
_cleanup_free_ char *word = NULL;
Manager *m = userdata; Manager *m = userdata;
bool both = false;
const char *p; const char *p;
int r; int r;
@ -461,78 +451,41 @@ int config_parse_dns_stub_listener_extra(
return 0; return 0;
} }
p = rvalue; r = dns_stub_listener_extra_new(&stub);
r = extract_first_word(&p, &word, ":", 0); if (r < 0)
if (r == -ENOMEM)
return log_oom(); 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, 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; return 0;
} }
/* First look for udp/tcp. If not specified then turn both TCP and UDP */ r = ordered_set_ensure_put(&m->dns_extra_stub_listeners, &dns_stub_listener_extra_hash_ops, stub);
if (!STR_IN_SET(word, "tcp", "udp")) { if (r == -ENOMEM)
both = true; return log_oom();
p = rvalue; 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) { TAKE_PTR(stub);
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);
return 0; return 0;
} }

View File

@ -7,9 +7,9 @@ typedef enum DnsStubListenerMode DnsStubListenerMode;
enum DnsStubListenerMode { enum DnsStubListenerMode {
DNS_STUB_LISTENER_NO, DNS_STUB_LISTENER_NO,
DNS_STUB_LISTENER_UDP, DNS_STUB_LISTENER_UDP = 1 << 0,
DNS_STUB_LISTENER_TCP, DNS_STUB_LISTENER_TCP = 1 << 1,
DNS_STUB_LISTENER_YES, DNS_STUB_LISTENER_YES = DNS_STUB_LISTENER_UDP | DNS_STUB_LISTENER_TCP,
_DNS_STUB_LISTENER_MODE_MAX, _DNS_STUB_LISTENER_MODE_MAX,
_DNS_STUB_LISTENER_MODE_INVALID = -1 _DNS_STUB_LISTENER_MODE_INVALID = -1
}; };

View File

@ -66,6 +66,7 @@ struct DnsPacket {
DnsResourceRecord *opt; DnsResourceRecord *opt;
/* Packet reception metadata */ /* Packet reception metadata */
int fd; /* Used by UDP extra DNS stub listners */
int ifindex; int ifindex;
int family, ipproto; int family, ipproto;
union in_addr_union sender, destination; union in_addr_union sender, destination;

View File

@ -1,8 +1,11 @@
/* SPDX-License-Identifier: LGPL-2.1+ */ /* SPDX-License-Identifier: LGPL-2.1+ */
#include <net/if_arp.h>
#include "errno-util.h" #include "errno-util.h"
#include "fd-util.h" #include "fd-util.h"
#include "missing_network.h" #include "missing_network.h"
#include "missing_socket.h"
#include "resolved-dns-stub.h" #include "resolved-dns-stub.h"
#include "socket-netlink.h" #include "socket-netlink.h"
#include "socket-util.h" #include "socket-util.h"
@ -11,25 +14,28 @@
* IP and UDP header sizes */ * IP and UDP header sizes */
#define ADVERTISE_DATAGRAM_SIZE_MAX (65536U-14U-20U-8U) #define ADVERTISE_DATAGRAM_SIZE_MAX (65536U-14U-20U-8U)
static int manager_dns_stub_udp_fd(Manager *m); int dns_stub_listener_extra_new(DNSStubListenerExtra **ret) {
static int manager_dns_stub_tcp_fd(Manager *m);
int dns_stub_extra_new(DNSStubListenerExtra **ret) {
DNSStubListenerExtra *l; DNSStubListenerExtra *l;
l = new(DNSStubListenerExtra, 1); l = new0(DNSStubListenerExtra, 1);
if (!l) if (!l)
return -ENOMEM; return -ENOMEM;
*l = (DNSStubListenerExtra) {
.fd = -1,
};
*ret = TAKE_PTR(l); *ret = TAKE_PTR(l);
return 0; 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( static int dns_stub_make_reply_packet(
DnsPacket **p, DnsPacket **p,
size_t max_size, size_t max_size,
@ -155,17 +161,11 @@ static int dns_stub_send(Manager *m, DnsStream *s, DnsPacket *p, DnsPacket *repl
if (s) if (s)
r = dns_stream_write_packet(s, reply); r = dns_stream_write_packet(s, reply);
else { 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 /* 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 * 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. */ * 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) if (r < 0)
return log_debug_errno(r, "Failed to send reply packet: %m"); 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; 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; _cleanup_(dns_query_freep) DnsQuery *q = NULL;
int r; int r;
@ -302,8 +302,9 @@ static void dns_stub_process_query(Manager *m, DnsStream *s, DnsPacket *p) {
assert(p); assert(p);
assert(p->protocol == DNS_PROTOCOL_DNS); assert(p->protocol == DNS_PROTOCOL_DNS);
if (in_addr_is_localhost(p->family, &p->sender) <= 0 || if (!is_extra &&
in_addr_is_localhost(p->family, &p->destination) <= 0) { (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."); log_error("Got packet on unexpected IP range, refusing.");
dns_stub_send_failure(m, s, p, DNS_RCODE_SERVFAIL, false); dns_stub_send_failure(m, s, p, DNS_RCODE_SERVFAIL, false);
return; return;
@ -384,9 +385,8 @@ static void dns_stub_process_query(Manager *m, DnsStream *s, DnsPacket *p) {
TAKE_PTR(q); 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; _cleanup_(dns_packet_unrefp) DnsPacket *p = NULL;
Manager *m = userdata;
int r; int r;
r = manager_recv(m, fd, DNS_PROTOCOL_DNS, &p); 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) { if (dns_packet_validate_query(p) > 0) {
log_debug("Got DNS stub UDP query packet for id %u", DNS_PACKET_ID(p)); 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 } else
log_debug("Invalid DNS stub UDP packet, ignoring."); log_debug("Invalid DNS stub UDP packet, ignoring.");
return 0; 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; int r;
assert(fd >= 0); assert(fd >= 0);
assert(IN_SET(family, AF_INET, AF_INET6));
r = setsockopt_int(fd, SOL_SOCKET, SO_REUSEADDR, true); r = setsockopt_int(fd, SOL_SOCKET, SO_REUSEADDR, true);
if (r < 0) if (r < 0)
return r; return r;
r = setsockopt_int(fd, IPPROTO_IP, IP_PKTINFO, true); if (family == AF_INET) {
if (r < 0) r = setsockopt_int(fd, IPPROTO_IP, IP_PKTINFO, true);
return r; 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) { 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; _cleanup_close_ int fd = -1;
int r; int r;
if (m->dns_stub_udp_fd >= 0) if (m->dns_stub_udp_event_source)
return m->dns_stub_udp_fd; return sd_event_source_get_io_fd(m->dns_stub_udp_event_source);
fd = socket(AF_INET, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0); fd = socket(AF_INET, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
if (fd < 0) if (fd < 0)
return -errno; return -errno;
r = set_dns_stub_common_socket_options(fd); r = set_dns_stub_common_socket_options(fd, AF_INET);
if (r < 0) if (r < 0)
return r; return r;
@ -451,70 +474,84 @@ static int manager_dns_stub_udp_fd(Manager *m) {
if (r < 0) if (r < 0)
return r; 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"); (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) { static int manager_dns_stub_udp_fd_extra(Manager *m, DNSStubListenerExtra *l) {
_cleanup_free_ char *pretty = NULL; _cleanup_free_ char *pretty = NULL;
_cleanup_close_ int fd = -1; _cleanup_close_ int fd = -1;
union sockaddr_union sa;
int r; int r;
if (l->fd >= 0) if (l->udp_event_source)
return 0; 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) { if (fd < 0) {
r = -errno; r = -errno;
goto fail; 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) if (r < 0)
goto fail; goto fail;
r = set_dns_stub_common_socket_options(fd); if (bind(fd, &sa.sa, SOCKADDR_LEN(sa)) < 0) {
if (r < 0)
goto fail;
if (bind(fd, &l->address.sockaddr.sa, l->address.size) < 0) {
r = -errno; r = -errno;
goto fail; 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) if (r < 0)
goto fail; 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) { 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)); log_debug("Listening on UDP socket %s.", strnull(pretty));
} }
return 0; return TAKE_FD(fd);
fail: fail:
(void) sockaddr_pretty(&l->address.sockaddr.sa, FAMILY_ADDRESS_SIZE(l->address.sockaddr.sa.sa_family), true, true, &pretty); assert(r < 0);
if (r == -EADDRINUSE) (void) in_addr_port_to_string(l->family, &l->address, l->port, &pretty);
return log_warning_errno(r, if (r == -EADDRINUSE)
"Another process is already listening on UDP socket %s.\n" return log_warning_errno(r, "Another process is already listening on UDP socket %s: %m", strnull(pretty));
"Turning off local DNS stub extra support.", strnull(pretty)); return log_warning_errno(r, "Failed to listen on UDP socket %s: %m", 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));
} }
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; _cleanup_(dns_packet_unrefp) DnsPacket *p = NULL;
assert(s); assert(s);
@ -525,16 +562,23 @@ static int on_dns_stub_stream_packet(DnsStream *s) {
if (dns_packet_validate_query(p) > 0) { if (dns_packet_validate_query(p) > 0) {
log_debug("Got DNS stub TCP query packet for id %u", DNS_PACKET_ID(p)); 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 } else
log_debug("Invalid DNS stub TCP packet, ignoring."); log_debug("Invalid DNS stub TCP packet, ignoring.");
return 0; 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; DnsStream *stream;
Manager *m = userdata;
int cfd, r; int cfd, r;
cfd = accept4(fd, NULL, NULL, SOCK_NONBLOCK|SOCK_CLOEXEC); 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; 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; stream->complete = dns_stub_stream_complete;
/* We let the reference to the stream dangle here, it will be dropped later by the complete callback. */ /* 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; 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) { static int manager_dns_stub_tcp_fd(Manager *m) {
union sockaddr_union sa = { union sockaddr_union sa = {
.in.sin_family = AF_INET, .in.sin_family = AF_INET,
@ -568,14 +620,14 @@ static int manager_dns_stub_tcp_fd(Manager *m) {
_cleanup_close_ int fd = -1; _cleanup_close_ int fd = -1;
int r; int r;
if (m->dns_stub_tcp_fd >= 0) if (m->dns_stub_tcp_event_source)
return m->dns_stub_tcp_fd; return sd_event_source_get_io_fd(m->dns_stub_tcp_event_source);
fd = socket(AF_INET, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0); fd = socket(AF_INET, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
if (fd < 0) if (fd < 0)
return -errno; return -errno;
r = set_dns_stub_common_socket_options(fd); r = set_dns_stub_common_socket_options(fd, AF_INET);
if (r < 0) if (r < 0)
return r; return r;
@ -598,38 +650,58 @@ static int manager_dns_stub_tcp_fd(Manager *m) {
if (r < 0) if (r < 0)
return r; 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"); (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) { static int manager_dns_stub_tcp_fd_extra(Manager *m, DNSStubListenerExtra *l) {
_cleanup_free_ char *pretty = NULL; _cleanup_free_ char *pretty = NULL;
_cleanup_close_ int fd = -1; _cleanup_close_ int fd = -1;
union sockaddr_union sa;
int r; int r;
if (l->fd >= 0) if (l->tcp_event_source)
return 0; 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) { if (fd < 0) {
r = -errno; r = -errno;
goto fail; goto fail;
} }
r = set_dns_stub_common_socket_options(fd); r = set_dns_stub_common_socket_options(fd, l->family);
if (r < 0) if (r < 0)
goto fail; 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) if (r < 0)
goto fail; goto fail;
r = setsockopt_int(fd, IPPROTO_IP, IP_FREEBIND, true); if (bind(fd, &sa.sa, SOCKADDR_LEN(sa)) < 0) {
if (r < 0)
goto fail;
if (bind(fd, &l->address.sockaddr.sa, l->address.size) < 0) {
r = -errno; r = -errno;
goto fail; goto fail;
} }
@ -639,35 +711,29 @@ static int manager_dns_stub_tcp_fd_extra(Manager *m, DNSStubListenerExtra *l) {
goto fail; 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) if (r < 0)
goto fail; 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) { 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)); log_debug("Listening on TCP socket %s.", strnull(pretty));
} }
return 0; return TAKE_FD(fd);
fail: fail:
(void) sockaddr_pretty(&l->address.sockaddr.sa, FAMILY_ADDRESS_SIZE(l->address.sockaddr.sa.sa_family), true, true, &pretty); assert(r < 0);
if (r == -EADDRINUSE) (void) in_addr_port_to_string(l->family, &l->address, l->port, &pretty);
return log_warning_errno(r, if (r == -EADDRINUSE)
"Another process is already listening on TCP socket %s.\n" return log_warning_errno(r, "Another process is already listening on TCP socket %s: %m", strnull(pretty));
"Turning off local DNS stub extra support.", strnull(pretty)); return log_warning_errno(r, "Failed to listen on TCP socket %s: %m", 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));
} }
int manager_dns_stub_start(Manager *m) { 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" : m->dns_stub_listener_mode == DNS_STUB_LISTENER_TCP ? "TCP" :
"UDP/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); r = manager_dns_stub_udp_fd(m);
if (r >= 0 && 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"; t = "TCP";
r = manager_dns_stub_tcp_fd(m); r = manager_dns_stub_tcp_fd(m);
} }
@ -710,16 +776,14 @@ int manager_dns_stub_start(Manager *m) {
DNSStubListenerExtra *l; DNSStubListenerExtra *l;
Iterator i; Iterator i;
log_debug("Creating stub listener extra using %s.", log_debug("Creating extra stub listeners.");
m->dns_stub_listener_mode == DNS_STUB_LISTENER_UDP ? "UDP" :
m->dns_stub_listener_mode == DNS_STUB_LISTENER_TCP ? "TCP" :
"UDP/TCP");
ORDERED_SET_FOREACH(l, m->dns_extra_stub_listeners, i) ORDERED_SET_FOREACH(l, m->dns_extra_stub_listeners, i) {
if (l->mode == DNS_STUB_LISTENER_UDP) if (FLAGS_SET(l->mode, DNS_STUB_LISTENER_UDP))
(void) manager_dns_stub_udp_fd_extra(m, l); (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); (void) manager_dns_stub_tcp_fd_extra(m, l);
}
} }
return 0; 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_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_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);
}
} }

View File

@ -3,8 +3,8 @@
#include "resolved-manager.h" #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(Manager *m);
void manager_dns_stub_stop_extra(Manager *m);
int manager_dns_stub_start(Manager *m); int manager_dns_stub_start(Manager *m);

View File

@ -578,8 +578,6 @@ int manager_new(Manager **ret) {
.llmnr_ipv6_tcp_fd = -1, .llmnr_ipv6_tcp_fd = -1,
.mdns_ipv4_fd = -1, .mdns_ipv4_fd = -1,
.mdns_ipv6_fd = -1, .mdns_ipv6_fd = -1,
.dns_stub_udp_fd = -1,
.dns_stub_tcp_fd = -1,
.hostname_fd = -1, .hostname_fd = -1,
.llmnr_support = DEFAULT_LLMNR_MODE, .llmnr_support = DEFAULT_LLMNR_MODE,
@ -701,7 +699,6 @@ Manager *manager_free(Manager *m) {
hashmap_free(m->links); hashmap_free(m->links);
hashmap_free(m->dns_transactions); hashmap_free(m->dns_transactions);
ordered_set_free(m->dns_extra_stub_listeners);
sd_event_source_unref(m->network_event_source); sd_event_source_unref(m->network_event_source);
sd_network_monitor_unref(m->network_monitor); sd_network_monitor_unref(m->network_monitor);
@ -714,7 +711,7 @@ Manager *manager_free(Manager *m) {
manager_dns_stub_stop(m); manager_dns_stub_stop(m);
manager_varlink_done(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); 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->size = (size_t) l;
p->fd = fd;
p->family = sa.sa.sa_family; p->family = sa.sa.sa_family;
p->ipproto = IPPROTO_UDP; p->ipproto = IPPROTO_UDP;
if (p->family == AF_INET) { if (p->family == AF_INET) {

View File

@ -32,11 +32,14 @@ typedef struct EtcHosts {
} EtcHosts; } EtcHosts;
typedef struct DNSStubListenerExtra { typedef struct DNSStubListenerExtra {
int fd;
DnsStubListenerMode mode; 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; } DNSStubListenerExtra;
struct Manager { struct Manager {
@ -141,12 +144,9 @@ struct Manager {
dev_t etc_hosts_dev; dev_t etc_hosts_dev;
bool read_etc_hosts; 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; 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_udp_event_source;
sd_event_source *dns_stub_tcp_event_source; sd_event_source *dns_stub_tcp_event_source;

View File

@ -235,33 +235,6 @@ int socket_address_parse_and_warn(SocketAddress *a, const char *s) {
return 0; 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) { int socket_address_parse_netlink(SocketAddress *a, const char *s) {
_cleanup_free_ char *word = NULL; _cleanup_free_ char *word = NULL;
unsigned group = 0; unsigned group = 0;
@ -482,6 +455,36 @@ int in_addr_port_ifindex_name_from_string_auto(
return r; 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) { struct in_addr_full *in_addr_full_free(struct in_addr_full *a) {
if (!a) if (!a)
return NULL; return NULL;

View File

@ -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(SocketAddress *a, const char *s);
int socket_address_parse_and_warn(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_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(const SocketAddress *a, const char *s, int type);
bool socket_address_is_netlink(const SocketAddress *a, const char *s); 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) { 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); 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 { struct in_addr_full {
int family; int family;

View File

@ -177,10 +177,163 @@ static void test_in_addr_random_prefix(void) {
str = mfree(str); 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[]) { int main(int argc, char *argv[]) {
test_in_addr_prefix_from_string(); test_in_addr_prefix_from_string();
test_in_addr_random_prefix(); test_in_addr_random_prefix();
test_in_addr_prefix_to_string(); 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; return 0;
} }

View File

@ -1,6 +1,7 @@
/* SPDX-License-Identifier: LGPL-2.1+ */ /* SPDX-License-Identifier: LGPL-2.1+ */
#include "alloc-util.h" #include "alloc-util.h"
#include "missing_network.h"
#include "tests.h" #include "tests.h"
#include "socket-netlink.h" #include "socket-netlink.h"
#include "string-util.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")); 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) { static void test_in_addr_ifindex_to_string_one(int f, const char *a, int ifindex, const char *b) {
_cleanup_free_ char *out = NULL; _cleanup_free_ char *r = NULL;
SocketAddress a; union in_addr_union ua, uuaa;
int r; int ff, ifindex2;
r = socket_addr_port_from_string_auto(in, port, &a); assert_se(in_addr_from_string(f, a, &ua) >= 0);
if (r >= 0) assert_se(in_addr_ifindex_to_string(f, &ua, ifindex, &r) >= 0);
assert_se(sockaddr_pretty(&a.sockaddr.sa, a.size, false, true, &out) >= 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, assert_se(in_addr_ifindex_from_string_auto(b, &ff, &uuaa, &ifindex2) >= 0);
r >= 0 ? "" : "", empty_to_dash(out), r >= 0 ? expected ?: in : "-"); assert_se(ff == f);
assert_se(r == ret); assert_se(in_addr_equal(f, &ua, &uuaa));
if (r >= 0) { assert_se(ifindex2 == ifindex || ifindex2 == 0);
assert_se(a.sockaddr.sa.sa_family == family);
assert_se(streq(out, expected ?: in));
}
} }
static void test_socket_addr_port_from_string_auto(void) { static void test_in_addr_ifindex_to_string(void) {
log_info("/* %s */", __func__); log_info("/* %s */", __func__);
test_socket_addr_port_from_string_auto_one("junk", 51, -EINVAL, 0, NULL); test_in_addr_ifindex_to_string_one(AF_INET, "192.168.0.1", 7, "192.168.0.1");
test_socket_addr_port_from_string_auto_one("192.168.1.1", 53, 0, AF_INET, "192.168.1.1:53"); test_in_addr_ifindex_to_string_one(AF_INET, "10.11.12.13", 9, "10.11.12.13");
test_socket_addr_port_from_string_auto_one(".168.1.1", 53, -EINVAL, 0, NULL); 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_socket_addr_port_from_string_auto_one("989.168.1.1", 53, -EINVAL, 0, NULL); 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); static void test_in_addr_ifindex_from_string_auto(void) {
test_socket_addr_port_from_string_auto_one("[::1]8888", 53, -EINVAL, 0, NULL); int family, ifindex;
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"); union in_addr_union ua;
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); log_info("/* %s */", __func__);
test_socket_addr_port_from_string_auto_one("[::1]:65536", 53, -ERANGE, 0, NULL); /* Most in_addr_ifindex_from_string_auto() invocations have already been tested above, but let's test some more */
test_socket_addr_port_from_string_auto_one("[a:b:1]:8888", 53, -EINVAL, 0, NULL);
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[]) { int main(int argc, char *argv[]) {
@ -257,7 +355,12 @@ int main(int argc, char *argv[]) {
test_socket_address_get_path(); test_socket_address_get_path();
test_socket_address_is(); test_socket_address_is();
test_socket_address_is_netlink(); 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; return 0;
} }

View File

@ -15,9 +15,7 @@
#include "io-util.h" #include "io-util.h"
#include "log.h" #include "log.h"
#include "macro.h" #include "macro.h"
#include "missing_network.h"
#include "process-util.h" #include "process-util.h"
#include "socket-netlink.h"
#include "socket-util.h" #include "socket-util.h"
#include "string-util.h" #include "string-util.h"
#include "tests.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"); 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) { static void test_sockaddr_equal(void) {
union sockaddr_union a = { union sockaddr_union a = {
.in.sin_family = AF_INET, .in.sin_family = AF_INET,
@ -759,16 +507,6 @@ int main(int argc, char *argv[]) {
test_socket_print_unix(); 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_equal();
test_sockaddr_un_len(); test_sockaddr_un_len();