Merge pull request #16947 from keszybz/socket-parsing-rework
Socket parsing rework
This commit is contained in:
commit
6ae05c9b14
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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)
|
||||
|
|
Loading…
Reference in New Issue