Compare commits
8 Commits
86e443de2f
...
908dbc70d6
Author | SHA1 | Date |
---|---|---|
Zbigniew Jędrzejewski-Szmek | 908dbc70d6 | |
Lennart Poettering | 88fdff4e65 | |
Lennart Poettering | 7d81d85a05 | |
Lennart Poettering | 1e7a67ec22 | |
Lennart Poettering | 91e0b0640e | |
Lennart Poettering | 415df097fe | |
Susant Sahani | 1f05101fb6 | |
Susant Sahani | 1f1f3210c9 |
|
@ -269,6 +269,31 @@
|
||||||
in use.</para></listitem>
|
in use.</para></listitem>
|
||||||
</varlistentry>
|
</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>
|
<varlistentry>
|
||||||
<term><varname>ReadEtcHosts=</varname></term>
|
<term><varname>ReadEtcHosts=</varname></term>
|
||||||
<listitem><para>Takes a boolean argument. If <literal>yes</literal> (the default),
|
<listitem><para>Takes a boolean argument. If <literal>yes</literal> (the default),
|
||||||
|
|
|
@ -10,11 +10,13 @@
|
||||||
#include "resolved-dnssd.h"
|
#include "resolved-dnssd.h"
|
||||||
#include "resolved-manager.h"
|
#include "resolved-manager.h"
|
||||||
#include "resolved-dns-search-domain.h"
|
#include "resolved-dns-search-domain.h"
|
||||||
|
#include "resolved-dns-stub.h"
|
||||||
#include "dns-domain.h"
|
#include "dns-domain.h"
|
||||||
#include "socket-netlink.h"
|
#include "socket-netlink.h"
|
||||||
#include "specifier.h"
|
#include "specifier.h"
|
||||||
#include "string-table.h"
|
#include "string-table.h"
|
||||||
#include "string-util.h"
|
#include "string-util.h"
|
||||||
|
#include "strv.h"
|
||||||
#include "utf8.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");
|
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);
|
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) {
|
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;
|
||||||
union in_addr_union address;
|
union in_addr_union address;
|
||||||
|
@ -385,6 +432,111 @@ int config_parse_dnssd_txt(const char *unit, const char *filename, unsigned line
|
||||||
return 0;
|
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 manager_parse_config_file(Manager *m) {
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
|
|
|
@ -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_name);
|
||||||
CONFIG_PARSER_PROTOTYPE(config_parse_dnssd_service_type);
|
CONFIG_PARSER_PROTOTYPE(config_parse_dnssd_service_type);
|
||||||
CONFIG_PARSER_PROTOTYPE(config_parse_dnssd_txt);
|
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_;
|
const char* dns_stub_listener_mode_to_string(DnsStubListenerMode p) _const_;
|
||||||
DnsStubListenerMode dns_stub_listener_mode_from_string(const char *s) _pure_;
|
DnsStubListenerMode dns_stub_listener_mode_from_string(const char *s) _pure_;
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
#include "fd-util.h"
|
#include "fd-util.h"
|
||||||
#include "missing_network.h"
|
#include "missing_network.h"
|
||||||
#include "resolved-dns-stub.h"
|
#include "resolved-dns-stub.h"
|
||||||
|
#include "socket-netlink.h"
|
||||||
#include "socket-util.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,
|
/* 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_udp_fd(Manager *m);
|
||||||
static int manager_dns_stub_tcp_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(
|
static int dns_stub_make_reply_packet(
|
||||||
DnsPacket **p,
|
DnsPacket **p,
|
||||||
size_t max_size,
|
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;
|
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) {
|
static int manager_dns_stub_udp_fd(Manager *m) {
|
||||||
union sockaddr_union sa = {
|
union sockaddr_union sa = {
|
||||||
.in.sin_family = AF_INET,
|
.in.sin_family = AF_INET,
|
||||||
|
@ -402,15 +435,7 @@ static int manager_dns_stub_udp_fd(Manager *m) {
|
||||||
if (fd < 0)
|
if (fd < 0)
|
||||||
return -errno;
|
return -errno;
|
||||||
|
|
||||||
r = setsockopt_int(fd, SOL_SOCKET, SO_REUSEADDR, true);
|
r = set_dns_stub_common_socket_options(fd);
|
||||||
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)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
|
@ -431,6 +456,64 @@ static int manager_dns_stub_udp_fd(Manager *m) {
|
||||||
return m->dns_stub_udp_fd = TAKE_FD(fd);
|
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) {
|
static int on_dns_stub_stream_packet(DnsStream *s) {
|
||||||
_cleanup_(dns_packet_unrefp) DnsPacket *p = NULL;
|
_cleanup_(dns_packet_unrefp) DnsPacket *p = NULL;
|
||||||
|
|
||||||
|
@ -492,22 +575,14 @@ static int manager_dns_stub_tcp_fd(Manager *m) {
|
||||||
if (fd < 0)
|
if (fd < 0)
|
||||||
return -errno;
|
return -errno;
|
||||||
|
|
||||||
|
r = set_dns_stub_common_socket_options(fd);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
r = setsockopt_int(fd, IPPROTO_IP, IP_TTL, true);
|
r = setsockopt_int(fd, IPPROTO_IP, IP_TTL, true);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
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 */
|
/* Make sure no traffic from outside the local host can leak to onto this socket */
|
||||||
r = socket_bind_to_ifindex(fd, LOOPBACK_IFINDEX);
|
r = socket_bind_to_ifindex(fd, LOOPBACK_IFINDEX);
|
||||||
if (r < 0)
|
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);
|
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) {
|
int manager_dns_stub_start(Manager *m) {
|
||||||
const char *t = "UDP";
|
const char *t = "UDP";
|
||||||
int r = 0;
|
int r = 0;
|
||||||
|
@ -564,6 +706,22 @@ int manager_dns_stub_start(Manager *m) {
|
||||||
} else if (r < 0)
|
} else if (r < 0)
|
||||||
return log_error_errno(r, "Failed to listen on %s socket 127.0.0.53:53: %m", t);
|
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;
|
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_udp_fd = safe_close(m->dns_stub_udp_fd);
|
||||||
m->dns_stub_tcp_fd = safe_close(m->dns_stub_tcp_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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -3,5 +3,8 @@
|
||||||
|
|
||||||
#include "resolved-manager.h"
|
#include "resolved-manager.h"
|
||||||
|
|
||||||
|
int dns_stub_extra_new(DNSStubListenerExtra **ret);
|
||||||
|
|
||||||
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);
|
||||||
|
|
|
@ -29,3 +29,4 @@ Resolve.Cache, config_parse_dns_cache_mode, DNS_CACH
|
||||||
Resolve.DNSStubListener, config_parse_dns_stub_listener_mode, 0, offsetof(Manager, dns_stub_listener_mode)
|
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.ReadEtcHosts, config_parse_bool, 0, offsetof(Manager, read_etc_hosts)
|
||||||
Resolve.ResolveUnicastSingleLabel, config_parse_bool, 0, offsetof(Manager, resolve_unicast_single_label)
|
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)
|
||||||
|
|
|
@ -701,6 +701,7 @@ 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);
|
||||||
|
@ -713,6 +714,8 @@ 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);
|
||||||
|
|
||||||
bus_verify_polkit_async_registry_free(m->polkit_registry);
|
bus_verify_polkit_async_registry_free(m->polkit_registry);
|
||||||
|
|
||||||
sd_bus_flush_close_unref(m->bus);
|
sd_bus_flush_close_unref(m->bus);
|
||||||
|
|
|
@ -31,6 +31,14 @@ typedef struct EtcHosts {
|
||||||
Set *no_address;
|
Set *no_address;
|
||||||
} EtcHosts;
|
} EtcHosts;
|
||||||
|
|
||||||
|
typedef struct DNSStubListenerExtra {
|
||||||
|
int fd;
|
||||||
|
|
||||||
|
DnsStubListenerMode mode;
|
||||||
|
SocketAddress address;
|
||||||
|
sd_event_source *dns_stub_extra_event_source;
|
||||||
|
} DNSStubListenerExtra;
|
||||||
|
|
||||||
struct Manager {
|
struct Manager {
|
||||||
sd_event *event;
|
sd_event *event;
|
||||||
|
|
||||||
|
@ -137,6 +145,8 @@ struct Manager {
|
||||||
int dns_stub_udp_fd;
|
int dns_stub_udp_fd;
|
||||||
int dns_stub_tcp_fd;
|
int dns_stub_tcp_fd;
|
||||||
|
|
||||||
|
OrderedSet *dns_extra_stub_listeners;
|
||||||
|
|
||||||
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;
|
||||||
|
|
||||||
|
|
|
@ -235,6 +235,33 @@ 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;
|
||||||
|
|
|
@ -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(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);
|
||||||
|
|
|
@ -757,7 +757,8 @@ tests += [
|
||||||
librt,
|
librt,
|
||||||
libblkid,
|
libblkid,
|
||||||
libkmod,
|
libkmod,
|
||||||
libacl],
|
libacl,
|
||||||
|
libselinux],
|
||||||
'', 'manual', '-DLOG_REALM=LOG_REALM_UDEV'],
|
'', 'manual', '-DLOG_REALM=LOG_REALM_UDEV'],
|
||||||
|
|
||||||
[['src/test/test-id128.c'],
|
[['src/test/test-id128.c'],
|
||||||
|
|
|
@ -213,6 +213,41 @@ 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) {
|
||||||
|
_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[]) {
|
int main(int argc, char *argv[]) {
|
||||||
test_setup_logging(LOG_DEBUG);
|
test_setup_logging(LOG_DEBUG);
|
||||||
|
|
||||||
|
@ -222,6 +257,7 @@ 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();
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
#include "main-func.h"
|
#include "main-func.h"
|
||||||
#include "mkdir.h"
|
#include "mkdir.h"
|
||||||
|
#include "mount-util.h"
|
||||||
#include "namespace-util.h"
|
#include "namespace-util.h"
|
||||||
#include "selinux-util.h"
|
#include "selinux-util.h"
|
||||||
#include "signal-util.h"
|
#include "signal-util.h"
|
||||||
|
@ -43,11 +44,11 @@ static int fake_filesystems(void) {
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_error_errno(r, "Failed to detach mount namespace: %m");
|
return log_error_errno(r, "Failed to detach mount namespace: %m");
|
||||||
|
|
||||||
for (size_t i = 0; i < ELEMENTSOF(fakefss); i++)
|
for (size_t i = 0; i < ELEMENTSOF(fakefss); i++) {
|
||||||
if (mount(fakefss[i].src, fakefss[i].target, NULL, MS_BIND, NULL) < 0) {
|
r = mount_verbose(fakefss[i].ignore_mount_error ? LOG_NOTICE : LOG_ERR,
|
||||||
log_full_errno(fakefss[i].ignore_mount_error ? LOG_DEBUG : LOG_ERR, errno, "%s: %m", fakefss[i].error);
|
fakefss[i].src, fakefss[i].target, NULL, MS_BIND, NULL);
|
||||||
if (!fakefss[i].ignore_mount_error)
|
if (r < 0 && !fakefss[i].ignore_mount_error)
|
||||||
return -errno;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -62,20 +63,24 @@ static int run(int argc, char *argv[]) {
|
||||||
|
|
||||||
test_setup_logging(LOG_INFO);
|
test_setup_logging(LOG_INFO);
|
||||||
|
|
||||||
if (!IN_SET(argc, 2, 3)) {
|
if (!IN_SET(argc, 2, 3))
|
||||||
log_error("This program needs one or two arguments, %d given", argc - 1);
|
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
|
||||||
return -EINVAL;
|
"This program needs one or two arguments, %d given", argc - 1);
|
||||||
}
|
|
||||||
|
|
||||||
r = fake_filesystems();
|
r = fake_filesystems();
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
|
/* Let's make sure the test runs with selinux assumed disabled. */
|
||||||
|
#if HAVE_SELINUX
|
||||||
|
fini_selinuxmnt();
|
||||||
|
#endif
|
||||||
|
mac_selinux_retest();
|
||||||
|
|
||||||
if (argc == 2) {
|
if (argc == 2) {
|
||||||
if (!streq(argv[1], "check")) {
|
if (!streq(argv[1], "check"))
|
||||||
log_error("Unknown argument: %s", argv[1]);
|
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
|
||||||
return -EINVAL;
|
"Unknown argument: %s", argv[1]);
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -91,7 +96,8 @@ static int run(int argc, char *argv[]) {
|
||||||
|
|
||||||
assert_se(udev_rules_load(&rules, RESOLVE_NAME_EARLY) == 0);
|
assert_se(udev_rules_load(&rules, RESOLVE_NAME_EARLY) == 0);
|
||||||
|
|
||||||
const char *syspath = strjoina("/sys", devpath);
|
const char *syspath;
|
||||||
|
syspath = strjoina("/sys", devpath);
|
||||||
r = device_new_from_synthetic_event(&dev, syspath, action);
|
r = device_new_from_synthetic_event(&dev, syspath, action);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_debug_errno(r, "Failed to open device '%s'", devpath);
|
return log_debug_errno(r, "Failed to open device '%s'", devpath);
|
||||||
|
|
|
@ -385,6 +385,7 @@ DNSLifetimeSec=
|
||||||
DNSSEC=
|
DNSSEC=
|
||||||
DNSSECNegativeTrustAnchors=
|
DNSSECNegativeTrustAnchors=
|
||||||
DNSStubListener=
|
DNSStubListener=
|
||||||
|
DNSStubListenerExtra=
|
||||||
DUIDRawData=
|
DUIDRawData=
|
||||||
DUIDType=
|
DUIDType=
|
||||||
DefaultLeaseTimeSec=
|
DefaultLeaseTimeSec=
|
||||||
|
|
Loading…
Reference in New Issue