Merge pull request #16947 from keszybz/socket-parsing-rework

Socket parsing rework
This commit is contained in:
Lennart Poettering 2020-09-10 16:47:37 +02:00 committed by GitHub
commit 6ae05c9b14
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 367 additions and 476 deletions

View File

@ -200,22 +200,24 @@
</para>
<para>If the address string is a string in the format
v.w.x.y:z, it is read as IPv4 specifier for listening on an
address v.w.x.y on a port z.</para>
<para>If the address string is a string in the format [x]:y,
it is read as IPv6 address x on a port y. Note that this might
make the service available via IPv4, too, depending on the
<varname>BindIPv6Only=</varname> setting (see below).
</para>
<literal><replaceable>v.w.x.y</replaceable>:<replaceable>z</replaceable></literal>, it is interpeted
as IPv4 address <replaceable>v.w.x.y</replaceable> and port <replaceable>z</replaceable>.</para>
<para>If the address string is a string in the format
<literal>vsock:x:y</literal>, it is read as CID <literal>x</literal> on
a port <literal>y</literal> address in the
<constant>AF_VSOCK</constant> family. The CID is a unique 32-bit
integer identifier in <constant>AF_VSOCK</constant> analogous to an IP
address. Specifying the CID is optional, and may be set to the empty
string.</para>
<literal>[<replaceable>x</replaceable>]:<replaceable>y</replaceable></literal>, it is interpreted as
IPv6 address <replaceable>x</replaceable> and port <replaceable>y</replaceable>. An optional
interface scope (interface name or number) may be specifed after a <literal>%</literal> symbol:
<literal>[<replaceable>x</replaceable>]:<replaceable>y</replaceable>%<replaceable>dev</replaceable></literal>.
Interface scopes are only useful with link-local addresses, because the kernel ignores them in other
cases. Note that if an address is specified as IPv6, it might still make the service available via
IPv4 too, depending on the <varname>BindIPv6Only=</varname> setting (see below).</para>
<para>If the address string is a string in the format
<literal>vsock:<replaceable>x</replaceable>:<replaceable>y</replaceable></literal>, it is read as CID
<replaceable>x</replaceable> on a port <replaceable>y</replaceable> address in the
<constant>AF_VSOCK</constant> family. The CID is a unique 32-bit integer identifier in
<constant>AF_VSOCK</constant> analogous to an IP address. Specifying the CID is optional, and may be
set to the empty string.</para>
<para>Note that <constant>SOCK_SEQPACKET</constant> (i.e.
<varname>ListenSequentialPacket=</varname>) is only available

View File

@ -68,7 +68,7 @@ int socket_address_verify(const SocketAddress *a, bool strict) {
if (a->sockaddr.in.sin_port == 0)
return -EINVAL;
if (!IN_SET(a->type, SOCK_STREAM, SOCK_DGRAM))
if (!IN_SET(a->type, 0, SOCK_STREAM, SOCK_DGRAM))
return -EINVAL;
return 0;
@ -80,7 +80,7 @@ int socket_address_verify(const SocketAddress *a, bool strict) {
if (a->sockaddr.in6.sin6_port == 0)
return -EINVAL;
if (!IN_SET(a->type, SOCK_STREAM, SOCK_DGRAM))
if (!IN_SET(a->type, 0, SOCK_STREAM, SOCK_DGRAM))
return -EINVAL;
return 0;
@ -114,7 +114,7 @@ int socket_address_verify(const SocketAddress *a, bool strict) {
}
}
if (!IN_SET(a->type, SOCK_STREAM, SOCK_DGRAM, SOCK_SEQPACKET))
if (!IN_SET(a->type, 0, SOCK_STREAM, SOCK_DGRAM, SOCK_SEQPACKET))
return -EINVAL;
return 0;
@ -124,7 +124,7 @@ int socket_address_verify(const SocketAddress *a, bool strict) {
if (a->size != sizeof(struct sockaddr_nl))
return -EINVAL;
if (!IN_SET(a->type, SOCK_RAW, SOCK_DGRAM))
if (!IN_SET(a->type, 0, SOCK_RAW, SOCK_DGRAM))
return -EINVAL;
return 0;
@ -133,7 +133,7 @@ int socket_address_verify(const SocketAddress *a, bool strict) {
if (a->size != sizeof(struct sockaddr_vm))
return -EINVAL;
if (!IN_SET(a->type, SOCK_STREAM, SOCK_DGRAM))
if (!IN_SET(a->type, 0, SOCK_STREAM, SOCK_DGRAM))
return -EINVAL;
return 0;
@ -399,19 +399,23 @@ int sockaddr_pretty(
if (r < 0)
return -ENOMEM;
} else {
char a[INET6_ADDRSTRLEN];
char a[INET6_ADDRSTRLEN], ifname[IF_NAMESIZE + 1];
inet_ntop(AF_INET6, &sa->in6.sin6_addr, a, sizeof(a));
if (sa->in6.sin6_scope_id != 0)
format_ifname_full(sa->in6.sin6_scope_id, ifname, FORMAT_IFNAME_IFINDEX);
if (include_port) {
r = asprintf(&p,
"[%s]:%u",
"[%s]:%u%s%s",
a,
be16toh(sa->in6.sin6_port));
be16toh(sa->in6.sin6_port),
sa->in6.sin6_scope_id != 0 ? "%" : "",
sa->in6.sin6_scope_id != 0 ? ifname : "");
if (r < 0)
return -ENOMEM;
} else {
p = strdup(a);
p = sa->in6.sin6_scope_id != 0 ? strjoin(a, "%", ifname) : strdup(a);
if (!p)
return -ENOMEM;
}
@ -686,17 +690,19 @@ static const char* const ip_tos_table[] = {
DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(ip_tos, int, 0xff);
bool ifname_valid_full(const char *p, bool alternative) {
bool ifname_valid_full(const char *p, IfnameValidFlags flags) {
bool numeric = true;
/* Checks whether a network interface name is valid. This is inspired by dev_valid_name() in the kernel sources
* but slightly stricter, as we only allow non-control, non-space ASCII characters in the interface name. We
* also don't permit names that only container numbers, to avoid confusion with numeric interface indexes. */
assert(!(flags & ~_IFNAME_VALID_ALL));
if (isempty(p))
return false;
if (alternative) {
if (flags & IFNAME_VALID_ALTERNATIVE) {
if (strlen(p) >= ALTIFNAMSIZ)
return false;
} else {
@ -707,22 +713,27 @@ bool ifname_valid_full(const char *p, bool alternative) {
if (dot_or_dot_dot(p))
return false;
while (*p) {
if ((unsigned char) *p >= 127U)
for (const char *t = p; *t; t++) {
if ((unsigned char) *t >= 127U)
return false;
if ((unsigned char) *p <= 32U)
if ((unsigned char) *t <= 32U)
return false;
if (IN_SET(*p, ':', '/'))
if (IN_SET(*t, ':', '/'))
return false;
numeric = numeric && (*p >= '0' && *p <= '9');
p++;
numeric = numeric && (*t >= '0' && *t <= '9');
}
if (numeric)
return false;
if (numeric) {
if (!(flags & IFNAME_VALID_NUMERIC))
return false;
/* Verify that the number is well-formatted and in range. */
if (parse_ifindex(p) < 0)
return false;
}
return true;
}
@ -1107,12 +1118,10 @@ int sockaddr_un_set_path(struct sockaddr_un *ret, const char *path) {
* reference paths in the abstract namespace that include NUL bytes in the name. */
l = strlen(path);
if (l == 0)
if (l < 2)
return -EINVAL;
if (!IN_SET(path[0], '/', '@'))
return -EINVAL;
if (path[1] == 0)
return -EINVAL;
/* Don't allow paths larger than the space in sockaddr_un. Note that we are a tiny bit more restrictive than
* the kernel is: we insist on NUL termination (both for abstract namespace and regular file system socket

View File

@ -130,9 +130,14 @@ static inline int fd_inc_rcvbuf(int fd, size_t n) {
int ip_tos_to_string_alloc(int i, char **s);
int ip_tos_from_string(const char *s);
bool ifname_valid_full(const char *p, bool alternative);
typedef enum {
IFNAME_VALID_ALTERNATIVE = 1 << 0,
IFNAME_VALID_NUMERIC = 1 << 1,
_IFNAME_VALID_ALL = IFNAME_VALID_ALTERNATIVE | IFNAME_VALID_NUMERIC,
} IfnameValidFlags;
bool ifname_valid_full(const char *p, IfnameValidFlags flags);
static inline bool ifname_valid(const char *p) {
return ifname_valid_full(p, false);
return ifname_valid_full(p, 0);
}
bool address_label_valid(const char *p);

View File

@ -39,7 +39,7 @@ Match.Type, config_parse_match_strv,
Match.WLANInterfaceType, config_parse_match_strv, 0, offsetof(Network, match_wlan_iftype)
Match.SSID, config_parse_match_strv, 0, offsetof(Network, match_ssid)
Match.BSSID, config_parse_hwaddrs, 0, offsetof(Network, match_bssid)
Match.Name, config_parse_match_ifnames, 1, offsetof(Network, match_name)
Match.Name, config_parse_match_ifnames, IFNAME_VALID_ALTERNATIVE, offsetof(Network, match_name)
Match.Property, config_parse_match_property, 0, offsetof(Network, match_property)
Match.Host, config_parse_net_condition, CONDITION_HOST, offsetof(Network, conditions)
Match.Virtualization, config_parse_net_condition, CONDITION_VIRTUALIZATION, offsetof(Network, conditions)

View File

@ -35,9 +35,6 @@ static int manager_add_dns_server_by_string(Manager *m, DnsServerType type, cons
if (r < 0)
return r;
if (IN_SET(port, 53, 853))
port = 0;
/* Silently filter out 0.0.0.0 and 127.0.0.53 (our own stub DNS listener) */
if (!dns_server_address_valid(family, &address))
return 0;
@ -50,12 +47,8 @@ static int manager_add_dns_server_by_string(Manager *m, DnsServerType type, cons
/* Filter out duplicates */
s = dns_server_find(manager_get_first_dns_server(m, type), family, &address, port, ifindex, server_name);
if (s) {
/*
* Drop the marker. This is used to find the servers
* that ceased to exist, see
* manager_mark_dns_servers() and
* manager_flush_marked_dns_servers().
*/
/* Drop the marker. This is used to find the servers that ceased to exist, see
* manager_mark_dns_servers() and manager_flush_marked_dns_servers(). */
dns_server_move_back_and_unmark(s);
return 0;
}
@ -447,7 +440,7 @@ int config_parse_dns_stub_listener_extra(
}
}
r = in_addr_port_from_string_auto(p, &stub->family, &stub->address, &stub->port);
r = in_addr_port_ifindex_name_from_string_auto(p, &stub->family, &stub->address, &stub->port, NULL, NULL);
if (r < 0) {
log_syntax(unit, LOG_WARNING, filename, line, r,
"Failed to parse address in %s=%s, ignoring assignment: %m",

View File

@ -15,7 +15,7 @@
* IP and UDP header sizes */
#define ADVERTISE_DATAGRAM_SIZE_MAX (65536U-14U-20U-8U)
static int manager_dns_stub_udp_fd_extra(Manager *m, DnsStubListenerExtra *l);
static int manager_dns_stub_fd_extra(Manager *m, DnsStubListenerExtra *l, int type);
static void dns_stub_listener_extra_hash_func(const DnsStubListenerExtra *a, struct siphash *state) {
assert(a);
@ -217,7 +217,7 @@ static int dns_stub_send(
* is because otherwise the kernel will choose it automatically based on the routing table and will
* thus pick 127.0.0.1 rather than 127.0.0.53. */
r = manager_send(m,
manager_dns_stub_udp_fd_extra(m, l),
manager_dns_stub_fd_extra(m, l, SOCK_DGRAM),
l ? p->ifindex : LOOPBACK_IFINDEX, /* force loopback iface if this is the main listener stub */
p->family, &p->sender, p->sender_port, &p->destination,
reply);
@ -477,151 +477,6 @@ static int on_dns_stub_packet_extra(sd_event_source *s, int fd, uint32_t revents
return on_dns_stub_packet_internal(s, fd, revents, l->manager, l);
}
static int set_dns_stub_common_socket_options(int fd, int family) {
int r;
assert(fd >= 0);
assert(IN_SET(family, AF_INET, AF_INET6));
r = setsockopt_int(fd, SOL_SOCKET, SO_REUSEADDR, true);
if (r < 0)
return r;
if (family == AF_INET) {
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;
} 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) {
union sockaddr_union sa = {
.in.sin_family = AF_INET,
.in.sin_port = htobe16(53),
.in.sin_addr.s_addr = htobe32(INADDR_DNS_STUB),
};
_cleanup_close_ int fd = -1;
int r;
if (m->dns_stub_udp_event_source)
return sd_event_source_get_io_fd(m->dns_stub_udp_event_source);
fd = socket(AF_INET, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
if (fd < 0)
return -errno;
r = set_dns_stub_common_socket_options(fd, AF_INET);
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)
return r;
if (bind(fd, &sa.sa, sizeof(sa.in)) < 0)
return -errno;
r = sd_event_add_io(m->event, &m->dns_stub_udp_event_source, fd, EPOLLIN, on_dns_stub_packet, m);
if (r < 0)
return r;
r = sd_event_source_set_io_fd_own(m->dns_stub_udp_event_source, true);
if (r < 0)
return r;
(void) sd_event_source_set_description(m->dns_stub_udp_event_source, "dns-stub-udp");
return TAKE_FD(fd);
}
static int manager_dns_stub_udp_fd_extra(Manager *m, DnsStubListenerExtra *l) {
_cleanup_free_ char *pretty = NULL;
_cleanup_close_ int fd = -1;
union sockaddr_union sa;
int r;
assert(m);
if (!l)
return manager_dns_stub_udp_fd(m);
if (l->udp_event_source)
return 0;
if (l->family == AF_INET)
sa = (union sockaddr_union) {
.in.sin_family = l->family,
.in.sin_port = htobe16(l->port != 0 ? l->port : 53U),
.in.sin_addr = l->address.in,
};
else
sa = (union sockaddr_union) {
.in6.sin6_family = l->family,
.in6.sin6_port = htobe16(l->port != 0 ? l->port : 53U),
.in6.sin6_addr = l->address.in6,
};
fd = socket(l->family, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
if (fd < 0) {
r = -errno;
goto fail;
}
if (l->family == AF_INET) {
r = setsockopt_int(fd, IPPROTO_IP, IP_FREEBIND, true);
if (r < 0)
goto fail;
}
r = set_dns_stub_common_socket_options(fd, l->family);
if (r < 0)
goto fail;
if (bind(fd, &sa.sa, SOCKADDR_LEN(sa)) < 0) {
r = -errno;
goto fail;
}
r = sd_event_add_io(m->event, &l->udp_event_source, fd, EPOLLIN, on_dns_stub_packet_extra, l);
if (r < 0)
goto fail;
r = sd_event_source_set_io_fd_own(l->udp_event_source, true);
if (r < 0)
goto fail;
(void) sd_event_source_set_description(l->udp_event_source, "dns-stub-udp-extra");
if (DEBUG_LOGGING) {
(void) in_addr_port_to_string(l->family, &l->address, l->port, &pretty);
log_debug("Listening on UDP socket %s.", strnull(pretty));
}
return TAKE_FD(fd);
fail:
assert(r < 0);
(void) in_addr_port_to_string(l->family, &l->address, l->port, &pretty);
if (r == -EADDRINUSE)
return log_warning_errno(r, "Another process is already listening on UDP socket %s: %m", strnull(pretty));
return log_warning_errno(r, "Failed to listen on UDP socket %s: %m", strnull(pretty));
}
static int on_dns_stub_stream_packet(DnsStream *s) {
_cleanup_(dns_packet_unrefp) DnsPacket *p = NULL;
@ -678,7 +533,38 @@ static int on_dns_stub_stream_extra(sd_event_source *s, int fd, uint32_t revents
return on_dns_stub_stream_internal(s, fd, revents, l->manager, l);
}
static int manager_dns_stub_tcp_fd(Manager *m) {
static int set_dns_stub_common_socket_options(int fd, int family) {
int r;
assert(fd >= 0);
assert(IN_SET(family, AF_INET, AF_INET6));
r = setsockopt_int(fd, SOL_SOCKET, SO_REUSEADDR, true);
if (r < 0)
return r;
if (family == AF_INET) {
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;
} 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_fd(Manager *m, int type) {
union sockaddr_union sa = {
.in.sin_family = AF_INET,
.in.sin_addr.s_addr = htobe32(INADDR_DNS_STUB),
@ -687,10 +573,13 @@ static int manager_dns_stub_tcp_fd(Manager *m) {
_cleanup_close_ int fd = -1;
int r;
if (m->dns_stub_tcp_event_source)
return sd_event_source_get_io_fd(m->dns_stub_tcp_event_source);
assert(IN_SET(type, SOCK_DGRAM, SOCK_STREAM));
fd = socket(AF_INET, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
sd_event_source **event_source = type == SOCK_DGRAM ? &m->dns_stub_udp_event_source : &m->dns_stub_tcp_event_source;
if (*event_source)
return sd_event_source_get_io_fd(*event_source);
fd = socket(AF_INET, type | SOCK_CLOEXEC | SOCK_NONBLOCK, 0);
if (fd < 0)
return -errno;
@ -698,42 +587,53 @@ static int manager_dns_stub_tcp_fd(Manager *m) {
if (r < 0)
return r;
r = setsockopt_int(fd, IPPROTO_IP, IP_TTL, 1);
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)
return r;
r = setsockopt_int(fd, IPPROTO_IP, IP_TTL, 1);
if (r < 0)
return r;
if (bind(fd, &sa.sa, sizeof(sa.in)) < 0)
return -errno;
if (listen(fd, SOMAXCONN) < 0)
if (type == SOCK_STREAM &&
listen(fd, SOMAXCONN) < 0)
return -errno;
r = sd_event_add_io(m->event, &m->dns_stub_tcp_event_source, fd, EPOLLIN, on_dns_stub_stream, m);
r = sd_event_add_io(m->event, event_source, fd, EPOLLIN,
type == SOCK_DGRAM ? on_dns_stub_packet : on_dns_stub_stream,
m);
if (r < 0)
return r;
r = sd_event_source_set_io_fd_own(m->dns_stub_tcp_event_source, true);
r = sd_event_source_set_io_fd_own(*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(*event_source,
type == SOCK_DGRAM ? "dns-stub-udp" : "dns-stub-tcp");
return TAKE_FD(fd);
}
static int manager_dns_stub_tcp_fd_extra(Manager *m, DnsStubListenerExtra *l) {
static int manager_dns_stub_fd_extra(Manager *m, DnsStubListenerExtra *l, int type) {
_cleanup_free_ char *pretty = NULL;
_cleanup_close_ int fd = -1;
union sockaddr_union sa;
int r;
if (l->tcp_event_source)
return sd_event_source_get_io_fd(l->tcp_event_source);;
assert(m);
assert(IN_SET(type, SOCK_DGRAM, SOCK_STREAM));
if (!l)
return manager_dns_stub_fd(m, type);
sd_event_source **event_source = type == SOCK_DGRAM ? &l->udp_event_source : &l->tcp_event_source;
if (*event_source)
return sd_event_source_get_io_fd(*event_source);
if (l->family == AF_INET)
sa = (union sockaddr_union) {
@ -748,7 +648,7 @@ static int manager_dns_stub_tcp_fd_extra(Manager *m, DnsStubListenerExtra *l) {
.in6.sin6_addr = l->address.in6,
};
fd = socket(l->family, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
fd = socket(l->family, type | SOCK_CLOEXEC | SOCK_NONBLOCK, 0);
if (fd < 0) {
r = -errno;
goto fail;
@ -758,8 +658,8 @@ static int manager_dns_stub_tcp_fd_extra(Manager *m, DnsStubListenerExtra *l) {
if (r < 0)
goto fail;
/* 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. */
/* 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);
@ -773,24 +673,30 @@ static int manager_dns_stub_tcp_fd_extra(Manager *m, DnsStubListenerExtra *l) {
goto fail;
}
if (listen(fd, SOMAXCONN) < 0) {
if (type == SOCK_STREAM &&
listen(fd, SOMAXCONN) < 0) {
r = -errno;
goto fail;
}
r = sd_event_add_io(m->event, &l->tcp_event_source, fd, EPOLLIN, on_dns_stub_stream_extra, l);
r = sd_event_add_io(m->event, event_source, fd, EPOLLIN,
type == SOCK_DGRAM ? on_dns_stub_packet_extra : on_dns_stub_stream_extra,
l);
if (r < 0)
goto fail;
r = sd_event_source_set_io_fd_own(l->tcp_event_source, true);
r = sd_event_source_set_io_fd_own(*event_source, true);
if (r < 0)
goto fail;
(void) sd_event_source_set_description(l->tcp_event_source, "dns-stub-tcp-extra");
(void) sd_event_source_set_description(*event_source,
type == SOCK_DGRAM ? "dns-stub-udp-extra" : "dns-stub-tcp-extra");
if (DEBUG_LOGGING) {
(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 %s socket %s.",
type == SOCK_DGRAM ? "UDP" : "TCP",
strnull(pretty));
}
return TAKE_FD(fd);
@ -798,9 +704,11 @@ static int manager_dns_stub_tcp_fd_extra(Manager *m, DnsStubListenerExtra *l) {
fail:
assert(r < 0);
(void) in_addr_port_to_string(l->family, &l->address, l->port, &pretty);
if (r == -EADDRINUSE)
return log_warning_errno(r, "Another process is already listening on TCP socket %s: %m", strnull(pretty));
return log_warning_errno(r, "Failed to listen on TCP socket %s: %m", strnull(pretty));
return log_warning_errno(r,
r == -EADDRINUSE ? "Another process is already listening on %s socket %s: %m" :
"Failed to listen on %s socket %s: %m",
type == SOCK_DGRAM ? "UDP" : "TCP",
strnull(pretty));
}
int manager_dns_stub_start(Manager *m) {
@ -818,23 +726,21 @@ int manager_dns_stub_start(Manager *m) {
"UDP/TCP");
if (FLAGS_SET(m->dns_stub_listener_mode, DNS_STUB_LISTENER_UDP))
r = manager_dns_stub_udp_fd(m);
r = manager_dns_stub_fd(m, SOCK_DGRAM);
if (r >= 0 &&
FLAGS_SET(m->dns_stub_listener_mode, DNS_STUB_LISTENER_TCP)) {
t = "TCP";
r = manager_dns_stub_tcp_fd(m);
r = manager_dns_stub_fd(m, SOCK_STREAM);
}
if (IN_SET(r, -EADDRINUSE, -EPERM)) {
if (r == -EADDRINUSE)
log_warning_errno(r,
"Another process is already listening on %s socket 127.0.0.53:53.\n"
"Turning off local DNS stub support.", t);
else
log_warning_errno(r,
"Failed to listen on %s socket 127.0.0.53:53: %m.\n"
"Turning off local DNS stub support.", t);
log_warning_errno(r,
r == -EADDRINUSE ? "Another process is already listening on %s socket 127.0.0.53:53.\n"
"Turning off local DNS stub support." :
"Failed to listen on %s socket 127.0.0.53:53: %m.\n"
"Turning off local DNS stub support.",
t);
manager_dns_stub_stop(m);
} else if (r < 0)
return log_error_errno(r, "Failed to listen on %s socket 127.0.0.53:53: %m", t);
@ -846,9 +752,9 @@ int manager_dns_stub_start(Manager *m) {
ORDERED_SET_FOREACH(l, m->dns_extra_stub_listeners) {
if (FLAGS_SET(l->mode, DNS_STUB_LISTENER_UDP))
(void) manager_dns_stub_udp_fd_extra(m, l);
(void) manager_dns_stub_fd_extra(m, l, SOCK_DGRAM);
if (FLAGS_SET(l->mode, DNS_STUB_LISTENER_TCP))
(void) manager_dns_stub_tcp_fd_extra(m, l);
(void) manager_dns_stub_fd_extra(m, l, SOCK_STREAM);
}
}

View File

@ -62,75 +62,23 @@ int socket_address_parse(SocketAddress *a, const char *s) {
assert(a);
assert(s);
*a = (SocketAddress) {
.type = SOCK_STREAM,
};
if (IN_SET(*s, '/', '@')) {
/* AF_UNIX socket */
struct sockaddr_un un;
if (*s == '[') {
uint16_t port;
/* IPv6 in [x:.....:z]:p notation */
e = strchr(s+1, ']');
if (!e)
return -EINVAL;
n = strndup(s+1, e-s-1);
if (!n)
return -ENOMEM;
errno = 0;
if (inet_pton(AF_INET6, n, &a->sockaddr.in6.sin6_addr) <= 0)
return errno_or_else(EINVAL);
e++;
if (*e != ':')
return -EINVAL;
e++;
r = parse_ip_port(e, &port);
r = sockaddr_un_set_path(&un, s);
if (r < 0)
return r;
a->sockaddr.in6.sin6_family = AF_INET6;
a->sockaddr.in6.sin6_port = htobe16(port);
a->size = sizeof(struct sockaddr_in6);
} else if (*s == '/') {
/* AF_UNIX socket */
size_t l;
l = strlen(s);
if (l >= sizeof(a->sockaddr.un.sun_path)) /* Note that we refuse non-NUL-terminated sockets when
* parsing (the kernel itself is less strict here in what it
* accepts) */
return -EINVAL;
a->sockaddr.un.sun_family = AF_UNIX;
memcpy(a->sockaddr.un.sun_path, s, l);
a->size = offsetof(struct sockaddr_un, sun_path) + l + 1;
} else if (*s == '@') {
/* Abstract AF_UNIX socket */
size_t l;
l = strlen(s+1);
if (l >= sizeof(a->sockaddr.un.sun_path) - 1) /* Note that we refuse non-NUL-terminated sockets here
* when parsing, even though abstract namespace sockets
* explicitly allow embedded NUL bytes and don't consider
* them special. But it's simply annoying to debug such
* sockets. */
return -EINVAL;
a->sockaddr.un.sun_family = AF_UNIX;
memcpy(a->sockaddr.un.sun_path+1, s+1, l);
a->size = offsetof(struct sockaddr_un, sun_path) + 1 + l;
*a = (SocketAddress) {
.sockaddr.un = un,
.size = r,
};
} else if (startswith(s, "vsock:")) {
/* AF_VSOCK socket in vsock:cid:port notation */
const char *cid_start = s + STRLEN("vsock:");
unsigned port;
unsigned port, cid;
e = strchr(cid_start, ':');
if (!e)
@ -144,72 +92,82 @@ int socket_address_parse(SocketAddress *a, const char *s) {
if (!n)
return -ENOMEM;
if (!isempty(n)) {
r = safe_atou(n, &a->sockaddr.vm.svm_cid);
if (isempty(n))
cid = VMADDR_CID_ANY;
else {
r = safe_atou(n, &cid);
if (r < 0)
return r;
} else
a->sockaddr.vm.svm_cid = VMADDR_CID_ANY;
}
a->sockaddr.vm.svm_family = AF_VSOCK;
a->sockaddr.vm.svm_port = port;
a->size = sizeof(struct sockaddr_vm);
*a = (SocketAddress) {
.sockaddr.vm = {
.svm_cid = cid,
.svm_family = AF_VSOCK,
.svm_port = port,
},
.size = sizeof(struct sockaddr_vm),
};
} else {
uint16_t port;
e = strchr(s, ':');
if (e) {
r = parse_ip_port(e + 1, &port);
if (r < 0)
return r;
n = strndup(s, e-s);
if (!n)
return -ENOMEM;
/* IPv4 in w.x.y.z:p notation? */
r = inet_pton(AF_INET, n, &a->sockaddr.in.sin_addr);
if (r < 0)
return -errno;
if (r > 0) {
/* Gotcha, it's a traditional IPv4 address */
a->sockaddr.in.sin_family = AF_INET;
a->sockaddr.in.sin_port = htobe16(port);
a->size = sizeof(struct sockaddr_in);
} else {
int idx;
/* Uh, our last resort, an interface name */
idx = resolve_ifname(NULL, n);
if (idx < 0)
return idx;
a->sockaddr.in6.sin6_family = AF_INET6;
a->sockaddr.in6.sin6_port = htobe16(port);
a->sockaddr.in6.sin6_scope_id = idx;
a->sockaddr.in6.sin6_addr = in6addr_any;
a->size = sizeof(struct sockaddr_in6);
}
} else {
r = parse_ip_port(s, &port);
if (r == -ERANGE)
return r; /* Valid port syntax, but the numerical value is wrong for a port. */
if (r >= 0) {
/* Just a port */
r = parse_ip_port(s, &port);
if (socket_ipv6_is_supported())
*a = (SocketAddress) {
.sockaddr.in6 = {
.sin6_family = AF_INET6,
.sin6_port = htobe16(port),
.sin6_addr = in6addr_any,
},
.size = sizeof(struct sockaddr_in6),
};
else
*a = (SocketAddress) {
.sockaddr.in = {
.sin_family = AF_INET,
.sin_port = htobe16(port),
.sin_addr.s_addr = INADDR_ANY,
},
.size = sizeof(struct sockaddr_in),
};
} else {
union in_addr_union address;
int family, ifindex;
r = in_addr_port_ifindex_name_from_string_auto(s, &family, &address, &port, &ifindex, NULL);
if (r < 0)
return r;
if (socket_ipv6_is_supported()) {
a->sockaddr.in6.sin6_family = AF_INET6;
a->sockaddr.in6.sin6_port = htobe16(port);
a->sockaddr.in6.sin6_addr = in6addr_any;
a->size = sizeof(struct sockaddr_in6);
} else {
a->sockaddr.in.sin_family = AF_INET;
a->sockaddr.in.sin_port = htobe16(port);
a->sockaddr.in.sin_addr.s_addr = INADDR_ANY;
a->size = sizeof(struct sockaddr_in);
}
if (port == 0) /* No port, no go. */
return -EINVAL;
if (family == AF_INET)
*a = (SocketAddress) {
.sockaddr.in = {
.sin_family = AF_INET,
.sin_addr = address.in,
.sin_port = htobe16(port),
},
.size = sizeof(struct sockaddr_in),
};
else if (family == AF_INET6)
*a = (SocketAddress) {
.sockaddr.in6 = {
.sin6_family = AF_INET6,
.sin6_addr = address.in6,
.sin6_port = htobe16(port),
.sin6_scope_id = ifindex,
},
.size = sizeof(struct sockaddr_in6),
};
else
assert_not_reached("Family quarrel");
}
}
@ -243,10 +201,6 @@ int socket_address_parse_netlink(SocketAddress *a, const char *s) {
assert(a);
assert(s);
*a = (SocketAddress) {
.type = SOCK_RAW,
};
r = extract_first_word(&s, &word, NULL, 0);
if (r < 0)
return r;
@ -263,12 +217,13 @@ int socket_address_parse_netlink(SocketAddress *a, const char *s) {
return r;
}
a->sockaddr.nl.nl_family = AF_NETLINK;
a->sockaddr.nl.nl_groups = group;
a->type = SOCK_RAW;
a->size = sizeof(struct sockaddr_nl);
a->protocol = family;
*a = (SocketAddress) {
.type = SOCK_RAW,
.sockaddr.nl.nl_family = AF_NETLINK,
.sockaddr.nl.nl_groups = group,
.protocol = family,
.size = sizeof(struct sockaddr_nl),
};
return 0;
}
@ -345,10 +300,14 @@ int in_addr_port_ifindex_name_from_string_auto(
/* This accepts the following:
* 192.168.0.1:53#example.com
* [2001:4860:4860::8888]:53%eth0#example.com */
/* if ret_port is NULL, then strings with port cannot be specified.
* Also, if ret_server_name is NULL, then server_name cannot be specified. */
* [2001:4860:4860::8888]:53%eth0#example.com
*
* If ret_port is NULL, then the port cannot be specified.
* If ret_ifindex is NULL, then the interface index cannot be specified.
* If ret_server_name is NULL, then server_name cannot be specified.
*
* ret_family is always AF_INET or AF_INET6.
*/
m = strchr(s, '#');
if (m) {
@ -369,15 +328,19 @@ int in_addr_port_ifindex_name_from_string_auto(
m = strchr(s, '%');
if (m) {
if (!ret_ifindex)
return -EINVAL;
if (isempty(m + 1))
return -EINVAL;
if (ret_ifindex) {
/* If we shall return the interface index, try to parse it */
ifindex = resolve_interface(NULL, m + 1);
if (ifindex < 0)
return ifindex;
}
if (!ifname_valid_full(m + 1, IFNAME_VALID_ALTERNATIVE | IFNAME_VALID_NUMERIC))
return -EINVAL; /* We want to return -EINVAL for syntactically invalid names,
* and -ENODEV for valid but nonexistent interfaces. */
ifindex = resolve_interface(NULL, m + 1);
if (ifindex < 0)
return ifindex;
s = buf2 = strndup(s, m - s);
if (!buf2)
@ -455,36 +418,6 @@ int in_addr_port_ifindex_name_from_string_auto(
return r;
}
int in_addr_port_from_string_auto(
const char *s,
int *ret_family,
union in_addr_union *ret_address,
uint16_t *ret_port) {
union in_addr_union addr;
int family, ifindex, r;
uint16_t port;
assert(s);
r = in_addr_port_ifindex_name_from_string_auto(s, &family, &addr, &port, &ifindex, NULL);
if (r < 0)
return r;
/* This does not accept interface specified. */
if (ifindex != 0)
return -EINVAL;
if (ret_family)
*ret_family = family;
if (ret_address)
*ret_address = addr;
if (ret_port)
*ret_port = port;
return r;
}
struct in_addr_full *in_addr_full_free(struct in_addr_full *a) {
if (!a)
return NULL;

View File

@ -33,7 +33,6 @@ static inline int in_addr_ifindex_name_from_string_auto(const char *s, int *fami
static inline int in_addr_ifindex_from_string_auto(const char *s, int *family, union in_addr_union *ret, int *ifindex) {
return in_addr_ifindex_name_from_string_auto(s, family, ret, ifindex, NULL);
}
int in_addr_port_from_string_auto(const char *s, int *ret_family, union in_addr_union *ret_address, uint16_t *ret_port);
struct in_addr_full {
int family;

View File

@ -58,6 +58,8 @@ static void test_in_addr_prefix_from_string_one(
}
static void test_in_addr_prefix_from_string(void) {
log_info("/* %s */", __func__);
test_in_addr_prefix_from_string_one("", AF_INET, -EINVAL, NULL, 0, -EINVAL, 0, -EINVAL, 0);
test_in_addr_prefix_from_string_one("/", AF_INET, -EINVAL, NULL, 0, -EINVAL, 0, -EINVAL, 0);
test_in_addr_prefix_from_string_one("/8", AF_INET, -EINVAL, NULL, 0, -EINVAL, 0, -EINVAL, 0);
@ -90,7 +92,7 @@ static void test_in_addr_prefix_to_string_valid(int family, const char *p) {
union in_addr_union u;
unsigned char l;
log_info("/* %s */", p);
log_info("%s: %s", __func__, p);
assert_se(in_addr_prefix_from_string(p, family, &u, &l) >= 0);
assert_se(in_addr_prefix_to_string(family, &u, l, &str) >= 0);
@ -102,7 +104,7 @@ static void test_in_addr_prefix_to_string_unoptimized(int family, const char *p)
union in_addr_union u1, u2;
unsigned char len1, len2;
log_info("/* %s */", p);
log_info("%s: %s", __func__, p);
assert_se(in_addr_prefix_from_string(p, family, &u1, &len1) >= 0);
assert_se(in_addr_prefix_to_string(family, &u1, len1, &str1) >= 0);
@ -115,6 +117,8 @@ static void test_in_addr_prefix_to_string_unoptimized(int family, const char *p)
}
static void test_in_addr_prefix_to_string(void) {
log_info("/* %s */", __func__);
test_in_addr_prefix_to_string_valid(AF_INET, "0.0.0.0/32");
test_in_addr_prefix_to_string_valid(AF_INET, "1.2.3.4/0");
test_in_addr_prefix_to_string_valid(AF_INET, "1.2.3.4/24");
@ -137,6 +141,8 @@ static void test_in_addr_random_prefix(void) {
_cleanup_free_ char *str = NULL;
union in_addr_union a;
log_info("/* %s */", __func__);
assert_se(in_addr_from_string(AF_INET, "192.168.10.1", &a) >= 0);
assert_se(in_addr_random_prefix(AF_INET, &a, 31, 32) >= 0);

View File

@ -12,11 +12,20 @@ static void test_socket_address_parse_one(const char *in, int ret, int family, c
int r;
r = socket_address_parse(&a, in);
if (r >= 0)
assert_se(socket_address_print(&a, &out) >= 0);
if (r >= 0) {
r = socket_address_print(&a, &out);
if (r < 0)
log_error_errno(r, "Printing failed for \"%s\": %m", in);
assert(r >= 0);
assert_se(a.type == 0);
}
log_info("\"%s\" → %s → \"%s\" (expect \"%s\")", in,
r >= 0 ? "" : "", empty_to_dash(out), r >= 0 ? expected ?: in : "-");
log_info("\"%s\" → %s %d → \"%s\" (expect %d / \"%s\")",
in,
r >= 0 ? "" : "", r,
empty_to_dash(out),
ret,
ret >= 0 ? expected ?: in : "-");
assert_se(r == ret);
if (r >= 0) {
assert_se(a.sockaddr.sa.sa_family == family);
@ -50,14 +59,24 @@ static void test_socket_address_parse(void) {
test_socket_address_parse_one("[::1]:0", -EINVAL, 0, NULL);
test_socket_address_parse_one("[::1]:65536", -ERANGE, 0, NULL);
test_socket_address_parse_one("[a:b:1]:8888", -EINVAL, 0, NULL);
test_socket_address_parse_one("[::1]%lo:1234", -EINVAL, 0, NULL);
test_socket_address_parse_one("[::1]%lo:0", -EINVAL, 0, NULL);
test_socket_address_parse_one("[::1]%lo", -EINVAL, 0, NULL);
test_socket_address_parse_one("[::1]%lo%lo:1234", -EINVAL, 0, NULL);
test_socket_address_parse_one("[::1]% lo:1234", -EINVAL, 0, NULL);
test_socket_address_parse_one("8888", 0, default_family, "[::]:8888");
test_socket_address_parse_one("[2001:0db8:0000:85a3:0000:0000:ac1f:8001]:8888", 0, AF_INET6,
"[2001:db8:0:85a3::ac1f:8001]:8888");
test_socket_address_parse_one("[::1]:8888", 0, AF_INET6, NULL);
test_socket_address_parse_one("[::1]:1234%lo", 0, AF_INET6, NULL);
test_socket_address_parse_one("[::1]:0%lo", -EINVAL, 0, NULL);
test_socket_address_parse_one("[::1]%lo", -EINVAL, 0, NULL);
test_socket_address_parse_one("[::1]:1234%lo%lo", -ENODEV, 0, NULL);
test_socket_address_parse_one("[::1]:1234%xxxxasdf", -ENODEV, 0, NULL);
test_socket_address_parse_one("192.168.1.254:8888", 0, AF_INET, NULL);
test_socket_address_parse_one("/foo/bar", 0, AF_UNIX, NULL);
test_socket_address_parse_one("/", 0, AF_UNIX, NULL);
test_socket_address_parse_one("/", -EINVAL, 0, NULL);
test_socket_address_parse_one("@abstract", 0, AF_UNIX, NULL);
{
@ -198,9 +217,13 @@ static void test_socket_address_is(void) {
log_info("/* %s */", __func__);
assert_se(socket_address_parse(&a, "192.168.1.1:8888") >= 0);
assert_se(socket_address_is(&a, "192.168.1.1:8888", SOCK_STREAM));
assert_se( socket_address_is(&a, "192.168.1.1:8888", 0 /* unspecified yet */));
assert_se(!socket_address_is(&a, "route", 0));
assert_se(!socket_address_is(&a, "route", SOCK_STREAM));
assert_se(!socket_address_is(&a, "192.168.1.1:8888", SOCK_RAW));
assert_se(!socket_address_is(&a, "192.168.1.1:8888", SOCK_STREAM));
a.type = SOCK_STREAM;
assert_se( socket_address_is(&a, "192.168.1.1:8888", SOCK_STREAM));
}
static void test_socket_address_is_netlink(void) {
@ -209,7 +232,7 @@ static void test_socket_address_is_netlink(void) {
log_info("/* %s */", __func__);
assert_se(socket_address_parse_netlink(&a, "route 10") >= 0);
assert_se(socket_address_is_netlink(&a, "route 10"));
assert_se( socket_address_is_netlink(&a, "route 10"));
assert_se(!socket_address_is_netlink(&a, "192.168.1.1:8888"));
assert_se(!socket_address_is_netlink(&a, "route 1"));
}
@ -284,66 +307,83 @@ static void test_in_addr_ifindex_name_from_string_auto(void) {
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;
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, const char *str_repr) {
union in_addr_union a;
uint16_t p;
int f, i;
char *fake;
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));
log_info("%s: %s", __func__, str);
{
_cleanup_free_ char *name = NULL, *x = NULL;
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_repr ?: str, x));
}
if (port > 0)
assert_se(in_addr_port_ifindex_name_from_string_auto(str, &f, &a, NULL, &i, &fake) == -EINVAL);
else {
_cleanup_free_ char *name = NULL, *x = NULL;
assert_se(in_addr_port_ifindex_name_from_string_auto(str, &f, &a, NULL, &i, &name) == 0);
assert_se(family == f);
assert_se(ifindex == i);
assert_se(streq_ptr(server_name, name));
assert_se(in_addr_port_ifindex_name_to_string(f, &a, 0, i, name, &x) >= 0);
assert_se(streq(str_repr ?: str, x));
}
if (ifindex > 0)
assert_se(in_addr_port_ifindex_name_from_string_auto(str, &f, &a, &p, NULL, &fake) == -EINVAL);
else {
_cleanup_free_ char *name = NULL, *x = NULL;
assert_se(in_addr_port_ifindex_name_from_string_auto(str, &f, &a, &p, NULL, &name) == 0);
assert_se(family == f);
assert_se(port == p);
assert_se(streq_ptr(server_name, name));
assert_se(in_addr_port_ifindex_name_to_string(f, &a, p, 0, name, &x) >= 0);
assert_se(streq(str_repr ?: str, x));
}
if (server_name)
assert_se(in_addr_port_ifindex_name_from_string_auto(str, &f, &a, &p, &i, NULL) == -EINVAL);
else {
_cleanup_free_ char *x = NULL;
assert_se(in_addr_port_ifindex_name_from_string_auto(str, &f, &a, &p, &i, NULL) == 0);
assert_se(family == f);
assert_se(port == p);
assert_se(ifindex == i);
assert_se(in_addr_port_ifindex_name_to_string(f, &a, p, i, NULL, &x) >= 0);
assert_se(streq(str_repr ?: 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);
test_in_addr_port_ifindex_name_from_string_auto_one("192.168.0.1", AF_INET, 0, 0, NULL, NULL);
test_in_addr_port_ifindex_name_from_string_auto_one("192.168.0.1#test.com", AF_INET, 0, 0, "test.com", NULL);
test_in_addr_port_ifindex_name_from_string_auto_one("192.168.0.1:53", AF_INET, 53, 0, NULL, NULL);
test_in_addr_port_ifindex_name_from_string_auto_one("192.168.0.1:53#example.com", AF_INET, 53, 0, "example.com", NULL);
test_in_addr_port_ifindex_name_from_string_auto_one("fe80::18", AF_INET6, 0, 0, NULL, NULL);
test_in_addr_port_ifindex_name_from_string_auto_one("fe80::18#hoge.com", AF_INET6, 0, 0, "hoge.com", NULL);
test_in_addr_port_ifindex_name_from_string_auto_one("fe80::18%19", AF_INET6, 0, 19, NULL, NULL);
test_in_addr_port_ifindex_name_from_string_auto_one("fe80::18%lo", AF_INET6, 0, 1, NULL, "fe80::18%1");
test_in_addr_port_ifindex_name_from_string_auto_one("[fe80::18]:53", AF_INET6, 53, 0, NULL, NULL);
test_in_addr_port_ifindex_name_from_string_auto_one("[fe80::18]:53%19", AF_INET6, 53, 19, NULL, NULL);
test_in_addr_port_ifindex_name_from_string_auto_one("[fe80::18]:53%lo", AF_INET6, 53, 1, NULL, "[fe80::18]:53%1");
test_in_addr_port_ifindex_name_from_string_auto_one("fe80::18%19#hoge.com", AF_INET6, 0, 19, "hoge.com", NULL);
test_in_addr_port_ifindex_name_from_string_auto_one("[fe80::18]:53#hoge.com", AF_INET6, 53, 0, "hoge.com", NULL);
test_in_addr_port_ifindex_name_from_string_auto_one("[fe80::18]:53%19", AF_INET6, 53, 19, NULL, NULL);
test_in_addr_port_ifindex_name_from_string_auto_one("[fe80::18]:53%19#hoge.com", AF_INET6, 53, 19, "hoge.com", NULL);
test_in_addr_port_ifindex_name_from_string_auto_one("[fe80::18]:53%lo", AF_INET6, 53, 1, NULL, "[fe80::18]:53%1");
test_in_addr_port_ifindex_name_from_string_auto_one("[fe80::18]:53%lo#hoge.com", AF_INET6, 53, 1, "hoge.com", "[fe80::18]:53%1#hoge.com");
}
int main(int argc, char *argv[]) {
@ -360,7 +400,6 @@ int main(int argc, char *argv[]) {
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;
}

View File

@ -26,13 +26,13 @@ assert_cc(SUN_PATH_LEN == 108);
static void test_ifname_valid(void) {
log_info("/* %s */", __func__);
assert(ifname_valid("foo"));
assert(ifname_valid("eth0"));
assert( ifname_valid("foo"));
assert( ifname_valid("eth0"));
assert(!ifname_valid("0"));
assert(!ifname_valid("99"));
assert(ifname_valid("a99"));
assert(ifname_valid("99a"));
assert( ifname_valid("a99"));
assert( ifname_valid("99a"));
assert(!ifname_valid(NULL));
assert(!ifname_valid(""));
@ -44,9 +44,13 @@ static void test_ifname_valid(void) {
assert(ifname_valid("foo.bar"));
assert(!ifname_valid("x:y"));
assert(ifname_valid("xxxxxxxxxxxxxxx"));
assert(!ifname_valid("xxxxxxxxxxxxxxxx"));
assert(ifname_valid_full("xxxxxxxxxxxxxxxx", true));
assert( ifname_valid_full("xxxxxxxxxxxxxxx", 0));
assert(!ifname_valid_full("xxxxxxxxxxxxxxxx", 0));
assert( ifname_valid_full("xxxxxxxxxxxxxxxx", IFNAME_VALID_ALTERNATIVE));
assert( ifname_valid_full("xxxxxxxxxxxxxxxx", IFNAME_VALID_ALTERNATIVE));
assert(!ifname_valid_full("999", IFNAME_VALID_ALTERNATIVE));
assert( ifname_valid_full("999", IFNAME_VALID_ALTERNATIVE | IFNAME_VALID_NUMERIC));
assert(!ifname_valid_full("0", IFNAME_VALID_ALTERNATIVE | IFNAME_VALID_NUMERIC));
}
static void test_socket_print_unix_one(const char *in, size_t len_in, const char *expected) {
@ -504,17 +508,11 @@ int main(int argc, char *argv[]) {
test_setup_logging(LOG_DEBUG);
test_ifname_valid();
test_socket_print_unix();
test_sockaddr_equal();
test_sockaddr_un_len();
test_in_addr_is_multicast();
test_getpeercred_getpeergroups();
test_passfd_read();
test_passfd_contents_read();
test_receive_nopassfd();

View File

@ -7,6 +7,7 @@ _Pragma("GCC diagnostic ignored \"-Wimplicit-fallthrough\"")
#include "ethtool-util.h"
#include "link-config.h"
#include "network-internal.h"
#include "socket-util.h"
%}
struct ConfigPerfItem;
%null_strings
@ -36,7 +37,7 @@ Link.MACAddressPolicy, config_parse_mac_address_policy, 0,
Link.MACAddress, config_parse_hwaddr, 0, offsetof(link_config, mac)
Link.NamePolicy, config_parse_name_policy, 0, offsetof(link_config, name_policy)
Link.Name, config_parse_ifname, 0, offsetof(link_config, name)
Link.AlternativeName, config_parse_ifnames, 1, offsetof(link_config, alternative_names)
Link.AlternativeName, config_parse_ifnames, IFNAME_VALID_ALTERNATIVE, offsetof(link_config, alternative_names)
Link.AlternativeNamesPolicy, config_parse_alternative_names_policy, 0, offsetof(link_config, alternative_names_policy)
Link.Alias, config_parse_ifalias, 0, offsetof(link_config, alias)
Link.MTUBytes, config_parse_mtu, AF_UNSPEC, offsetof(link_config, mtu)