Merge pull request #16044 from ssahani/resolved-interface

systemd-resolved: allow configurable bind address
This commit is contained in:
Zbigniew Jędrzejewski-Szmek 2020-09-03 19:06:05 +02:00 committed by GitHub
commit 908dbc70d6
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
12 changed files with 462 additions and 32 deletions

View file

@ -269,6 +269,31 @@
in use.</para></listitem>
</varlistentry>
<varlistentry>
<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
a protocol name (<literal>udp</literal> or <literal>tcp</literal>). 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 <literal>:</literal>.
If the protocol is not specified, the service will listen on both <literal>UDP</literal> and <literal>TCP</literal>. 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 <varname>DNSStubListener=</varname>, and only configures <emphasis>additional</emphasis>
sockets to listen on. Defaults to unset.</para>
<para>If the string in the format <literal>udp</literal>:[<replaceable>x</replaceable>]:<replaceable>y</replaceable>,
it is read as protocol <literal>udp</literal> and IPv6 address x on a port y.</para>
<para>If the string in the format [<replaceable>x</replaceable>]:<replaceable>y</replaceable>, it is read as both protocol
<literal>udp</literal> and <literal>tcp</literal>, IPv6 address x on a port y.</para>
<para>If the string in the format <replaceable>x</replaceable>, it is read as protocol both <literal>udp</literal> and
<literal>tcp</literal>, IPv6/IPv4 address x on a port 53.</para>
<para>If the string in the format <literal>udp</literal>:<replaceable>x</replaceable>:<replaceable>y</replaceable>,
it is read as protocol <literal>udp</literal> and IPv4 address x on a port y.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><varname>ReadEtcHosts=</varname></term>
<listitem><para>Takes a boolean argument. If <literal>yes</literal> (the default),

View file

@ -10,11 +10,13 @@
#include "resolved-dnssd.h"
#include "resolved-manager.h"
#include "resolved-dns-search-domain.h"
#include "resolved-dns-stub.h"
#include "dns-domain.h"
#include "socket-netlink.h"
#include "specifier.h"
#include "string-table.h"
#include "string-util.h"
#include "strv.h"
#include "utf8.h"
DEFINE_CONFIG_PARSE_ENUM(config_parse_dns_stub_listener_mode, dns_stub_listener_mode, DnsStubListenerMode, "Failed to parse DNS stub listener mode setting");
@ -27,6 +29,51 @@ 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);
}
static int dns_stub_listener_extra_compare_func(const DNSStubListenerExtra *a, const DNSStubListenerExtra *b) {
unsigned p, q;
int r;
assert(a);
assert(b);
r = CMP(a->mode, b->mode);
if (r != 0)
return r;
r = CMP(socket_address_family(&a->address), socket_address_family(&b->address));
if (r != 0)
return r;
r = memcmp(&a->address, &b->address, FAMILY_ADDRESS_SIZE(socket_address_family(&a->address)));
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);
}
DEFINE_PRIVATE_HASH_OPS_WITH_KEY_DESTRUCTOR(
dns_stub_listener_extra_hash_ops,
DNSStubListenerExtra,
dns_stub_listener_extra_hash_func,
dns_stub_listener_extra_compare_func,
free);
static int manager_add_dns_server_by_string(Manager *m, DnsServerType type, const char *word) {
_cleanup_free_ char *server_name = NULL;
union in_addr_union address;
@ -385,6 +432,111 @@ int config_parse_dnssd_txt(const char *unit, const char *filename, unsigned line
return 0;
}
int config_parse_dns_stub_listener_extra(
const char *unit,
const char *filename,
unsigned line,
const char *section,
unsigned section_line,
const char *lvalue,
int ltype,
const char *rvalue,
void *data,
void *userdata) {
_cleanup_free_ DNSStubListenerExtra *udp = NULL, *tcp = NULL;
_cleanup_free_ char *word = NULL;
Manager *m = userdata;
bool both = false;
const char *p;
int r;
assert(filename);
assert(lvalue);
assert(rvalue);
assert(data);
if (isempty(rvalue)) {
m->dns_extra_stub_listeners = ordered_set_free(m->dns_extra_stub_listeners);
return 0;
}
p = rvalue;
r = extract_first_word(&p, &word, ":", 0);
if (r == -ENOMEM)
return log_oom();
if (r <= 0) {
log_syntax(unit, LOG_WARNING, filename, line, r,
"Invalid DNSStubListenExtra='%s', ignoring assignment", 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;
}
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);
return 0;
}
int manager_parse_config_file(Manager *m) {
int r;

View file

@ -30,6 +30,7 @@ CONFIG_PARSER_PROTOTYPE(config_parse_dns_stub_listener_mode);
CONFIG_PARSER_PROTOTYPE(config_parse_dnssd_service_name);
CONFIG_PARSER_PROTOTYPE(config_parse_dnssd_service_type);
CONFIG_PARSER_PROTOTYPE(config_parse_dnssd_txt);
CONFIG_PARSER_PROTOTYPE(config_parse_dns_stub_listener_extra);
const char* dns_stub_listener_mode_to_string(DnsStubListenerMode p) _const_;
DnsStubListenerMode dns_stub_listener_mode_from_string(const char *s) _pure_;

View file

@ -4,6 +4,7 @@
#include "fd-util.h"
#include "missing_network.h"
#include "resolved-dns-stub.h"
#include "socket-netlink.h"
#include "socket-util.h"
/* The MTU of the loopback device is 64K on Linux, advertise that as maximum datagram size, but subtract the Ethernet,
@ -13,6 +14,22 @@
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) {
DNSStubListenerExtra *l;
l = new(DNSStubListenerExtra, 1);
if (!l)
return -ENOMEM;
*l = (DNSStubListenerExtra) {
.fd = -1,
};
*ret = TAKE_PTR(l);
return 0;
}
static int dns_stub_make_reply_packet(
DnsPacket **p,
size_t max_size,
@ -386,6 +403,22 @@ static int on_dns_stub_packet(sd_event_source *s, int fd, uint32_t revents, void
return 0;
}
static int set_dns_stub_common_socket_options(int fd) {
int r;
assert(fd >= 0);
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;
return setsockopt_int(fd, IPPROTO_IP, IP_RECVTTL, true);
}
static int manager_dns_stub_udp_fd(Manager *m) {
union sockaddr_union sa = {
.in.sin_family = AF_INET,
@ -402,15 +435,7 @@ static int manager_dns_stub_udp_fd(Manager *m) {
if (fd < 0)
return -errno;
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;
r = setsockopt_int(fd, IPPROTO_IP, IP_RECVTTL, true);
r = set_dns_stub_common_socket_options(fd);
if (r < 0)
return r;
@ -431,6 +456,64 @@ static int manager_dns_stub_udp_fd(Manager *m) {
return m->dns_stub_udp_fd = 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;
int r;
if (l->fd >= 0)
return 0;
fd = socket(socket_address_family(&l->address), SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
if (fd < 0) {
r = -errno;
goto fail;
}
r = setsockopt_int(fd, IPPROTO_IP, IP_FREEBIND, true);
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) {
r = -errno;
goto fail;
}
r = sd_event_add_io(m->event, &l->dns_stub_extra_event_source, fd, EPOLLIN, on_dns_stub_packet, m);
if (r < 0)
goto fail;
(void) sd_event_source_set_description(l->dns_stub_extra_event_source, "dns-stub-udp-extra");
l->fd = TAKE_FD(fd);
if (DEBUG_LOGGING) {
(void) sockaddr_pretty(&l->address.sockaddr.sa, FAMILY_ADDRESS_SIZE(l->address.sockaddr.sa.sa_family), true, true, &pretty);
log_debug("Listening on UDP socket %s.", strnull(pretty));
}
return 0;
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));
}
static int on_dns_stub_stream_packet(DnsStream *s) {
_cleanup_(dns_packet_unrefp) DnsPacket *p = NULL;
@ -492,22 +575,14 @@ static int manager_dns_stub_tcp_fd(Manager *m) {
if (fd < 0)
return -errno;
r = set_dns_stub_common_socket_options(fd);
if (r < 0)
return r;
r = setsockopt_int(fd, IPPROTO_IP, IP_TTL, true);
if (r < 0)
return r;
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;
r = setsockopt_int(fd, IPPROTO_IP, IP_RECVTTL, true);
if (r < 0)
return r;
/* Make sure no traffic from outside the local host can leak to onto this socket */
r = socket_bind_to_ifindex(fd, LOOPBACK_IFINDEX);
if (r < 0)
@ -528,6 +603,73 @@ static int manager_dns_stub_tcp_fd(Manager *m) {
return m->dns_stub_tcp_fd = 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;
int r;
if (l->fd >= 0)
return 0;
fd = socket(socket_address_family(&l->address), SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
if (fd < 0) {
r = -errno;
goto fail;
}
r = set_dns_stub_common_socket_options(fd);
if (r < 0)
goto fail;
r = setsockopt_int(fd, IPPROTO_IP, IP_TTL, 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) {
r = -errno;
goto fail;
}
if (listen(fd, SOMAXCONN) < 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);
if (r < 0)
goto fail;
(void) sd_event_source_set_description(l->dns_stub_extra_event_source, "dns-stub-tcp-extra");
l->fd = TAKE_FD(fd);
if (DEBUG_LOGGING) {
(void) sockaddr_pretty(&l->address.sockaddr.sa, FAMILY_ADDRESS_SIZE(l->address.sockaddr.sa.sa_family), true, true, &pretty);
log_debug("Listening on TCP socket %s.", strnull(pretty));
}
return 0;
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));
}
int manager_dns_stub_start(Manager *m) {
const char *t = "UDP";
int r = 0;
@ -564,6 +706,22 @@ int manager_dns_stub_start(Manager *m) {
} else if (r < 0)
return log_error_errno(r, "Failed to listen on %s socket 127.0.0.53:53: %m", t);
if (!ordered_set_isempty(m->dns_extra_stub_listeners)) {
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");
ORDERED_SET_FOREACH(l, m->dns_extra_stub_listeners, i)
if (l->mode == DNS_STUB_LISTENER_UDP)
(void) manager_dns_stub_udp_fd_extra(m, l);
else
(void) manager_dns_stub_tcp_fd_extra(m, l);
}
return 0;
}
@ -576,3 +734,15 @@ void manager_dns_stub_stop(Manager *m) {
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,5 +3,8 @@
#include "resolved-manager.h"
int dns_stub_extra_new(DNSStubListenerExtra **ret);
void manager_dns_stub_stop(Manager *m);
void manager_dns_stub_stop_extra(Manager *m);
int manager_dns_stub_start(Manager *m);

View file

@ -18,14 +18,15 @@ struct ConfigPerfItem;
%struct-type
%includes
%%
Resolve.DNS, config_parse_dns_servers, DNS_SERVER_SYSTEM, 0
Resolve.FallbackDNS, config_parse_dns_servers, DNS_SERVER_FALLBACK, 0
Resolve.Domains, config_parse_search_domains, 0, 0
Resolve.LLMNR, config_parse_resolve_support, 0, offsetof(Manager, llmnr_support)
Resolve.MulticastDNS, config_parse_resolve_support, 0, offsetof(Manager, mdns_support)
Resolve.DNSSEC, config_parse_dnssec_mode, 0, offsetof(Manager, dnssec_mode)
Resolve.DNSOverTLS, config_parse_dns_over_tls_mode, 0, offsetof(Manager, dns_over_tls_mode)
Resolve.Cache, config_parse_dns_cache_mode, DNS_CACHE_MODE_YES, offsetof(Manager, enable_cache)
Resolve.DNSStubListener, config_parse_dns_stub_listener_mode, 0, offsetof(Manager, dns_stub_listener_mode)
Resolve.ReadEtcHosts, config_parse_bool, 0, offsetof(Manager, read_etc_hosts)
Resolve.ResolveUnicastSingleLabel, config_parse_bool, 0, offsetof(Manager, resolve_unicast_single_label)
Resolve.DNS, config_parse_dns_servers, DNS_SERVER_SYSTEM, 0
Resolve.FallbackDNS, config_parse_dns_servers, DNS_SERVER_FALLBACK, 0
Resolve.Domains, config_parse_search_domains, 0, 0
Resolve.LLMNR, config_parse_resolve_support, 0, offsetof(Manager, llmnr_support)
Resolve.MulticastDNS, config_parse_resolve_support, 0, offsetof(Manager, mdns_support)
Resolve.DNSSEC, config_parse_dnssec_mode, 0, offsetof(Manager, dnssec_mode)
Resolve.DNSOverTLS, config_parse_dns_over_tls_mode, 0, offsetof(Manager, dns_over_tls_mode)
Resolve.Cache, config_parse_dns_cache_mode, DNS_CACHE_MODE_YES, offsetof(Manager, enable_cache)
Resolve.DNSStubListener, config_parse_dns_stub_listener_mode, 0, offsetof(Manager, dns_stub_listener_mode)
Resolve.ReadEtcHosts, config_parse_bool, 0, offsetof(Manager, read_etc_hosts)
Resolve.ResolveUnicastSingleLabel, config_parse_bool, 0, offsetof(Manager, resolve_unicast_single_label)
Resolve.DNSStubListenerExtra, config_parse_dns_stub_listener_extra, 0, offsetof(Manager, dns_extra_stub_listeners)

View file

@ -701,6 +701,7 @@ 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);
@ -713,6 +714,8 @@ Manager *manager_free(Manager *m) {
manager_dns_stub_stop(m);
manager_varlink_done(m);
manager_dns_stub_stop_extra(m);
bus_verify_polkit_async_registry_free(m->polkit_registry);
sd_bus_flush_close_unref(m->bus);

View file

@ -31,6 +31,14 @@ typedef struct EtcHosts {
Set *no_address;
} EtcHosts;
typedef struct DNSStubListenerExtra {
int fd;
DnsStubListenerMode mode;
SocketAddress address;
sd_event_source *dns_stub_extra_event_source;
} DNSStubListenerExtra;
struct Manager {
sd_event *event;
@ -137,6 +145,8 @@ struct Manager {
int dns_stub_udp_fd;
int dns_stub_tcp_fd;
OrderedSet *dns_extra_stub_listeners;
sd_event_source *dns_stub_udp_event_source;
sd_event_source *dns_stub_tcp_event_source;

View file

@ -235,6 +235,33 @@ 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;

View file

@ -16,6 +16,7 @@ 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);

View file

@ -213,6 +213,41 @@ 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;
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);
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));
}
}
static void test_socket_addr_port_from_string_auto(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_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);
}
int main(int argc, char *argv[]) {
test_setup_logging(LOG_DEBUG);
@ -222,6 +257,7 @@ 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();
return 0;
}

View file

@ -385,6 +385,7 @@ DNSLifetimeSec=
DNSSEC=
DNSSECNegativeTrustAnchors=
DNSStubListener=
DNSStubListenerExtra=
DUIDRawData=
DUIDType=
DefaultLeaseTimeSec=