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>
|
||||||
|
|
||||||
<para>If the address string is a string in the format
|
<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
|
<literal><replaceable>v.w.x.y</replaceable>:<replaceable>z</replaceable></literal>, it is interpeted
|
||||||
address v.w.x.y on a port z.</para>
|
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 [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>
|
|
||||||
|
|
||||||
<para>If the address string is a string in the format
|
<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
|
<literal>[<replaceable>x</replaceable>]:<replaceable>y</replaceable></literal>, it is interpreted as
|
||||||
a port <literal>y</literal> address in the
|
IPv6 address <replaceable>x</replaceable> and port <replaceable>y</replaceable>. An optional
|
||||||
<constant>AF_VSOCK</constant> family. The CID is a unique 32-bit
|
interface scope (interface name or number) may be specifed after a <literal>%</literal> symbol:
|
||||||
integer identifier in <constant>AF_VSOCK</constant> analogous to an IP
|
<literal>[<replaceable>x</replaceable>]:<replaceable>y</replaceable>%<replaceable>dev</replaceable></literal>.
|
||||||
address. Specifying the CID is optional, and may be set to the empty
|
Interface scopes are only useful with link-local addresses, because the kernel ignores them in other
|
||||||
string.</para>
|
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.
|
<para>Note that <constant>SOCK_SEQPACKET</constant> (i.e.
|
||||||
<varname>ListenSequentialPacket=</varname>) is only available
|
<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)
|
if (a->sockaddr.in.sin_port == 0)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
if (!IN_SET(a->type, SOCK_STREAM, SOCK_DGRAM))
|
if (!IN_SET(a->type, 0, SOCK_STREAM, SOCK_DGRAM))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -80,7 +80,7 @@ int socket_address_verify(const SocketAddress *a, bool strict) {
|
||||||
if (a->sockaddr.in6.sin6_port == 0)
|
if (a->sockaddr.in6.sin6_port == 0)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
if (!IN_SET(a->type, SOCK_STREAM, SOCK_DGRAM))
|
if (!IN_SET(a->type, 0, SOCK_STREAM, SOCK_DGRAM))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
return 0;
|
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 -EINVAL;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -124,7 +124,7 @@ int socket_address_verify(const SocketAddress *a, bool strict) {
|
||||||
if (a->size != sizeof(struct sockaddr_nl))
|
if (a->size != sizeof(struct sockaddr_nl))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
if (!IN_SET(a->type, SOCK_RAW, SOCK_DGRAM))
|
if (!IN_SET(a->type, 0, SOCK_RAW, SOCK_DGRAM))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -133,7 +133,7 @@ int socket_address_verify(const SocketAddress *a, bool strict) {
|
||||||
if (a->size != sizeof(struct sockaddr_vm))
|
if (a->size != sizeof(struct sockaddr_vm))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
if (!IN_SET(a->type, SOCK_STREAM, SOCK_DGRAM))
|
if (!IN_SET(a->type, 0, SOCK_STREAM, SOCK_DGRAM))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -399,19 +399,23 @@ int sockaddr_pretty(
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
} else {
|
} else {
|
||||||
char a[INET6_ADDRSTRLEN];
|
char a[INET6_ADDRSTRLEN], ifname[IF_NAMESIZE + 1];
|
||||||
|
|
||||||
inet_ntop(AF_INET6, &sa->in6.sin6_addr, a, sizeof(a));
|
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) {
|
if (include_port) {
|
||||||
r = asprintf(&p,
|
r = asprintf(&p,
|
||||||
"[%s]:%u",
|
"[%s]:%u%s%s",
|
||||||
a,
|
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)
|
if (r < 0)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
} else {
|
} else {
|
||||||
p = strdup(a);
|
p = sa->in6.sin6_scope_id != 0 ? strjoin(a, "%", ifname) : strdup(a);
|
||||||
if (!p)
|
if (!p)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
}
|
}
|
||||||
|
@ -686,17 +690,19 @@ static const char* const ip_tos_table[] = {
|
||||||
|
|
||||||
DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(ip_tos, int, 0xff);
|
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;
|
bool numeric = true;
|
||||||
|
|
||||||
/* Checks whether a network interface name is valid. This is inspired by dev_valid_name() in the kernel sources
|
/* 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
|
* 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. */
|
* also don't permit names that only container numbers, to avoid confusion with numeric interface indexes. */
|
||||||
|
|
||||||
|
assert(!(flags & ~_IFNAME_VALID_ALL));
|
||||||
|
|
||||||
if (isempty(p))
|
if (isempty(p))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (alternative) {
|
if (flags & IFNAME_VALID_ALTERNATIVE) {
|
||||||
if (strlen(p) >= ALTIFNAMSIZ)
|
if (strlen(p) >= ALTIFNAMSIZ)
|
||||||
return false;
|
return false;
|
||||||
} else {
|
} else {
|
||||||
|
@ -707,22 +713,27 @@ bool ifname_valid_full(const char *p, bool alternative) {
|
||||||
if (dot_or_dot_dot(p))
|
if (dot_or_dot_dot(p))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
while (*p) {
|
for (const char *t = p; *t; t++) {
|
||||||
if ((unsigned char) *p >= 127U)
|
if ((unsigned char) *t >= 127U)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if ((unsigned char) *p <= 32U)
|
if ((unsigned char) *t <= 32U)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (IN_SET(*p, ':', '/'))
|
if (IN_SET(*t, ':', '/'))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
numeric = numeric && (*p >= '0' && *p <= '9');
|
numeric = numeric && (*t >= '0' && *t <= '9');
|
||||||
p++;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (numeric)
|
if (numeric) {
|
||||||
return false;
|
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;
|
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. */
|
* reference paths in the abstract namespace that include NUL bytes in the name. */
|
||||||
|
|
||||||
l = strlen(path);
|
l = strlen(path);
|
||||||
if (l == 0)
|
if (l < 2)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
if (!IN_SET(path[0], '/', '@'))
|
if (!IN_SET(path[0], '/', '@'))
|
||||||
return -EINVAL;
|
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
|
/* 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
|
* 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_to_string_alloc(int i, char **s);
|
||||||
int ip_tos_from_string(const 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) {
|
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);
|
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.WLANInterfaceType, config_parse_match_strv, 0, offsetof(Network, match_wlan_iftype)
|
||||||
Match.SSID, config_parse_match_strv, 0, offsetof(Network, match_ssid)
|
Match.SSID, config_parse_match_strv, 0, offsetof(Network, match_ssid)
|
||||||
Match.BSSID, config_parse_hwaddrs, 0, offsetof(Network, match_bssid)
|
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.Property, config_parse_match_property, 0, offsetof(Network, match_property)
|
||||||
Match.Host, config_parse_net_condition, CONDITION_HOST, offsetof(Network, conditions)
|
Match.Host, config_parse_net_condition, CONDITION_HOST, offsetof(Network, conditions)
|
||||||
Match.Virtualization, config_parse_net_condition, CONDITION_VIRTUALIZATION, 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)
|
if (r < 0)
|
||||||
return r;
|
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) */
|
/* Silently filter out 0.0.0.0 and 127.0.0.53 (our own stub DNS listener) */
|
||||||
if (!dns_server_address_valid(family, &address))
|
if (!dns_server_address_valid(family, &address))
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -50,12 +47,8 @@ static int manager_add_dns_server_by_string(Manager *m, DnsServerType type, cons
|
||||||
/* Filter out duplicates */
|
/* Filter out duplicates */
|
||||||
s = dns_server_find(manager_get_first_dns_server(m, type), family, &address, port, ifindex, server_name);
|
s = dns_server_find(manager_get_first_dns_server(m, type), family, &address, port, ifindex, server_name);
|
||||||
if (s) {
|
if (s) {
|
||||||
/*
|
/* Drop the marker. This is used to find the servers that ceased to exist, see
|
||||||
* Drop the marker. This is used to find the servers
|
* manager_mark_dns_servers() and manager_flush_marked_dns_servers(). */
|
||||||
* that ceased to exist, see
|
|
||||||
* manager_mark_dns_servers() and
|
|
||||||
* manager_flush_marked_dns_servers().
|
|
||||||
*/
|
|
||||||
dns_server_move_back_and_unmark(s);
|
dns_server_move_back_and_unmark(s);
|
||||||
return 0;
|
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) {
|
if (r < 0) {
|
||||||
log_syntax(unit, LOG_WARNING, filename, line, r,
|
log_syntax(unit, LOG_WARNING, filename, line, r,
|
||||||
"Failed to parse address in %s=%s, ignoring assignment: %m",
|
"Failed to parse address in %s=%s, ignoring assignment: %m",
|
||||||
|
|
|
@ -15,7 +15,7 @@
|
||||||
* IP and UDP header sizes */
|
* IP and UDP header sizes */
|
||||||
#define ADVERTISE_DATAGRAM_SIZE_MAX (65536U-14U-20U-8U)
|
#define ADVERTISE_DATAGRAM_SIZE_MAX (65536U-14U-20U-8U)
|
||||||
|
|
||||||
static int manager_dns_stub_udp_fd_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) {
|
static void dns_stub_listener_extra_hash_func(const DnsStubListenerExtra *a, struct siphash *state) {
|
||||||
assert(a);
|
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
|
* is because otherwise the kernel will choose it automatically based on the routing table and will
|
||||||
* thus pick 127.0.0.1 rather than 127.0.0.53. */
|
* thus pick 127.0.0.1 rather than 127.0.0.53. */
|
||||||
r = manager_send(m,
|
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 */
|
l ? p->ifindex : LOOPBACK_IFINDEX, /* force loopback iface if this is the main listener stub */
|
||||||
p->family, &p->sender, p->sender_port, &p->destination,
|
p->family, &p->sender, p->sender_port, &p->destination,
|
||||||
reply);
|
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);
|
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) {
|
static int on_dns_stub_stream_packet(DnsStream *s) {
|
||||||
_cleanup_(dns_packet_unrefp) DnsPacket *p = NULL;
|
_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);
|
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 = {
|
union sockaddr_union sa = {
|
||||||
.in.sin_family = AF_INET,
|
.in.sin_family = AF_INET,
|
||||||
.in.sin_addr.s_addr = htobe32(INADDR_DNS_STUB),
|
.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;
|
_cleanup_close_ int fd = -1;
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
if (m->dns_stub_tcp_event_source)
|
assert(IN_SET(type, SOCK_DGRAM, SOCK_STREAM));
|
||||||
return sd_event_source_get_io_fd(m->dns_stub_tcp_event_source);
|
|
||||||
|
|
||||||
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)
|
if (fd < 0)
|
||||||
return -errno;
|
return -errno;
|
||||||
|
|
||||||
|
@ -698,42 +587,53 @@ static int manager_dns_stub_tcp_fd(Manager *m) {
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
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 */
|
/* Make sure no traffic from outside the local host can leak to onto this socket */
|
||||||
r = socket_bind_to_ifindex(fd, LOOPBACK_IFINDEX);
|
r = socket_bind_to_ifindex(fd, LOOPBACK_IFINDEX);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
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)
|
if (bind(fd, &sa.sa, sizeof(sa.in)) < 0)
|
||||||
return -errno;
|
return -errno;
|
||||||
|
|
||||||
if (listen(fd, SOMAXCONN) < 0)
|
if (type == SOCK_STREAM &&
|
||||||
|
listen(fd, SOMAXCONN) < 0)
|
||||||
return -errno;
|
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)
|
if (r < 0)
|
||||||
return r;
|
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)
|
if (r < 0)
|
||||||
return r;
|
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);
|
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_free_ char *pretty = NULL;
|
||||||
_cleanup_close_ int fd = -1;
|
_cleanup_close_ int fd = -1;
|
||||||
union sockaddr_union sa;
|
union sockaddr_union sa;
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
if (l->tcp_event_source)
|
assert(m);
|
||||||
return sd_event_source_get_io_fd(l->tcp_event_source);;
|
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)
|
if (l->family == AF_INET)
|
||||||
sa = (union sockaddr_union) {
|
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,
|
.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) {
|
if (fd < 0) {
|
||||||
r = -errno;
|
r = -errno;
|
||||||
goto fail;
|
goto fail;
|
||||||
|
@ -758,8 +658,8 @@ static int manager_dns_stub_tcp_fd_extra(Manager *m, DnsStubListenerExtra *l) {
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
/* Do not set IP_TTL for extra DNS stub listners, as the address may not be local and in that
|
/* Do not set IP_TTL for extra DNS stub listners, as the address may not be local and in that case
|
||||||
* case people may want ttl > 1. */
|
* people may want ttl > 1. */
|
||||||
|
|
||||||
if (l->family == AF_INET)
|
if (l->family == AF_INET)
|
||||||
r = setsockopt_int(fd, IPPROTO_IP, IP_FREEBIND, true);
|
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;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (listen(fd, SOMAXCONN) < 0) {
|
if (type == SOCK_STREAM &&
|
||||||
|
listen(fd, SOMAXCONN) < 0) {
|
||||||
r = -errno;
|
r = -errno;
|
||||||
goto fail;
|
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)
|
if (r < 0)
|
||||||
goto fail;
|
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)
|
if (r < 0)
|
||||||
goto fail;
|
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) {
|
if (DEBUG_LOGGING) {
|
||||||
(void) in_addr_port_to_string(l->family, &l->address, l->port, &pretty);
|
(void) in_addr_port_to_string(l->family, &l->address, l->port, &pretty);
|
||||||
log_debug("Listening on TCP socket %s.", strnull(pretty));
|
log_debug("Listening on %s socket %s.",
|
||||||
|
type == SOCK_DGRAM ? "UDP" : "TCP",
|
||||||
|
strnull(pretty));
|
||||||
}
|
}
|
||||||
|
|
||||||
return TAKE_FD(fd);
|
return TAKE_FD(fd);
|
||||||
|
@ -798,9 +704,11 @@ static int manager_dns_stub_tcp_fd_extra(Manager *m, DnsStubListenerExtra *l) {
|
||||||
fail:
|
fail:
|
||||||
assert(r < 0);
|
assert(r < 0);
|
||||||
(void) in_addr_port_to_string(l->family, &l->address, l->port, &pretty);
|
(void) in_addr_port_to_string(l->family, &l->address, l->port, &pretty);
|
||||||
if (r == -EADDRINUSE)
|
return log_warning_errno(r,
|
||||||
return log_warning_errno(r, "Another process is already listening on TCP socket %s: %m", strnull(pretty));
|
r == -EADDRINUSE ? "Another process is already listening on %s socket %s: %m" :
|
||||||
return log_warning_errno(r, "Failed to listen on TCP socket %s: %m", strnull(pretty));
|
"Failed to listen on %s socket %s: %m",
|
||||||
|
type == SOCK_DGRAM ? "UDP" : "TCP",
|
||||||
|
strnull(pretty));
|
||||||
}
|
}
|
||||||
|
|
||||||
int manager_dns_stub_start(Manager *m) {
|
int manager_dns_stub_start(Manager *m) {
|
||||||
|
@ -818,23 +726,21 @@ int manager_dns_stub_start(Manager *m) {
|
||||||
"UDP/TCP");
|
"UDP/TCP");
|
||||||
|
|
||||||
if (FLAGS_SET(m->dns_stub_listener_mode, DNS_STUB_LISTENER_UDP))
|
if (FLAGS_SET(m->dns_stub_listener_mode, DNS_STUB_LISTENER_UDP))
|
||||||
r = manager_dns_stub_udp_fd(m);
|
r = manager_dns_stub_fd(m, SOCK_DGRAM);
|
||||||
|
|
||||||
if (r >= 0 &&
|
if (r >= 0 &&
|
||||||
FLAGS_SET(m->dns_stub_listener_mode, DNS_STUB_LISTENER_TCP)) {
|
FLAGS_SET(m->dns_stub_listener_mode, DNS_STUB_LISTENER_TCP)) {
|
||||||
t = "TCP";
|
t = "TCP";
|
||||||
r = manager_dns_stub_tcp_fd(m);
|
r = manager_dns_stub_fd(m, SOCK_STREAM);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (IN_SET(r, -EADDRINUSE, -EPERM)) {
|
if (IN_SET(r, -EADDRINUSE, -EPERM)) {
|
||||||
if (r == -EADDRINUSE)
|
log_warning_errno(r,
|
||||||
log_warning_errno(r,
|
r == -EADDRINUSE ? "Another process is already listening on %s socket 127.0.0.53:53.\n"
|
||||||
"Another process is already listening on %s socket 127.0.0.53:53.\n"
|
"Turning off local DNS stub support." :
|
||||||
"Turning off local DNS stub support.", t);
|
"Failed to listen on %s socket 127.0.0.53:53: %m.\n"
|
||||||
else
|
"Turning off local DNS stub support.",
|
||||||
log_warning_errno(r,
|
t);
|
||||||
"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);
|
manager_dns_stub_stop(m);
|
||||||
} else if (r < 0)
|
} else if (r < 0)
|
||||||
return log_error_errno(r, "Failed to listen on %s socket 127.0.0.53:53: %m", t);
|
return log_error_errno(r, "Failed to listen on %s socket 127.0.0.53:53: %m", t);
|
||||||
|
@ -846,9 +752,9 @@ int manager_dns_stub_start(Manager *m) {
|
||||||
|
|
||||||
ORDERED_SET_FOREACH(l, m->dns_extra_stub_listeners) {
|
ORDERED_SET_FOREACH(l, m->dns_extra_stub_listeners) {
|
||||||
if (FLAGS_SET(l->mode, DNS_STUB_LISTENER_UDP))
|
if (FLAGS_SET(l->mode, DNS_STUB_LISTENER_UDP))
|
||||||
(void) manager_dns_stub_udp_fd_extra(m, l);
|
(void) manager_dns_stub_fd_extra(m, l, SOCK_DGRAM);
|
||||||
if (FLAGS_SET(l->mode, DNS_STUB_LISTENER_TCP))
|
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(a);
|
||||||
assert(s);
|
assert(s);
|
||||||
|
|
||||||
*a = (SocketAddress) {
|
if (IN_SET(*s, '/', '@')) {
|
||||||
.type = SOCK_STREAM,
|
/* AF_UNIX socket */
|
||||||
};
|
struct sockaddr_un un;
|
||||||
|
|
||||||
if (*s == '[') {
|
r = sockaddr_un_set_path(&un, 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);
|
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
a->sockaddr.in6.sin6_family = AF_INET6;
|
*a = (SocketAddress) {
|
||||||
a->sockaddr.in6.sin6_port = htobe16(port);
|
.sockaddr.un = un,
|
||||||
a->size = sizeof(struct sockaddr_in6);
|
.size = r,
|
||||||
|
};
|
||||||
} 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;
|
|
||||||
|
|
||||||
} else if (startswith(s, "vsock:")) {
|
} else if (startswith(s, "vsock:")) {
|
||||||
/* AF_VSOCK socket in vsock:cid:port notation */
|
/* AF_VSOCK socket in vsock:cid:port notation */
|
||||||
const char *cid_start = s + STRLEN("vsock:");
|
const char *cid_start = s + STRLEN("vsock:");
|
||||||
unsigned port;
|
unsigned port, cid;
|
||||||
|
|
||||||
e = strchr(cid_start, ':');
|
e = strchr(cid_start, ':');
|
||||||
if (!e)
|
if (!e)
|
||||||
|
@ -144,72 +92,82 @@ int socket_address_parse(SocketAddress *a, const char *s) {
|
||||||
if (!n)
|
if (!n)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
if (!isempty(n)) {
|
if (isempty(n))
|
||||||
r = safe_atou(n, &a->sockaddr.vm.svm_cid);
|
cid = VMADDR_CID_ANY;
|
||||||
|
else {
|
||||||
|
r = safe_atou(n, &cid);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
} else
|
}
|
||||||
a->sockaddr.vm.svm_cid = VMADDR_CID_ANY;
|
|
||||||
|
|
||||||
a->sockaddr.vm.svm_family = AF_VSOCK;
|
*a = (SocketAddress) {
|
||||||
a->sockaddr.vm.svm_port = port;
|
.sockaddr.vm = {
|
||||||
a->size = sizeof(struct sockaddr_vm);
|
.svm_cid = cid,
|
||||||
|
.svm_family = AF_VSOCK,
|
||||||
|
.svm_port = port,
|
||||||
|
},
|
||||||
|
.size = sizeof(struct sockaddr_vm),
|
||||||
|
};
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
uint16_t port;
|
uint16_t port;
|
||||||
|
|
||||||
e = strchr(s, ':');
|
r = parse_ip_port(s, &port);
|
||||||
if (e) {
|
if (r == -ERANGE)
|
||||||
r = parse_ip_port(e + 1, &port);
|
return r; /* Valid port syntax, but the numerical value is wrong for a port. */
|
||||||
if (r < 0)
|
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 {
|
|
||||||
|
|
||||||
/* Just a port */
|
/* 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)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
if (socket_ipv6_is_supported()) {
|
if (port == 0) /* No port, no go. */
|
||||||
a->sockaddr.in6.sin6_family = AF_INET6;
|
return -EINVAL;
|
||||||
a->sockaddr.in6.sin6_port = htobe16(port);
|
|
||||||
a->sockaddr.in6.sin6_addr = in6addr_any;
|
if (family == AF_INET)
|
||||||
a->size = sizeof(struct sockaddr_in6);
|
*a = (SocketAddress) {
|
||||||
} else {
|
.sockaddr.in = {
|
||||||
a->sockaddr.in.sin_family = AF_INET;
|
.sin_family = AF_INET,
|
||||||
a->sockaddr.in.sin_port = htobe16(port);
|
.sin_addr = address.in,
|
||||||
a->sockaddr.in.sin_addr.s_addr = INADDR_ANY;
|
.sin_port = htobe16(port),
|
||||||
a->size = sizeof(struct sockaddr_in);
|
},
|
||||||
}
|
.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(a);
|
||||||
assert(s);
|
assert(s);
|
||||||
|
|
||||||
*a = (SocketAddress) {
|
|
||||||
.type = SOCK_RAW,
|
|
||||||
};
|
|
||||||
|
|
||||||
r = extract_first_word(&s, &word, NULL, 0);
|
r = extract_first_word(&s, &word, NULL, 0);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
@ -263,12 +217,13 @@ int socket_address_parse_netlink(SocketAddress *a, const char *s) {
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
a->sockaddr.nl.nl_family = AF_NETLINK;
|
*a = (SocketAddress) {
|
||||||
a->sockaddr.nl.nl_groups = group;
|
.type = SOCK_RAW,
|
||||||
|
.sockaddr.nl.nl_family = AF_NETLINK,
|
||||||
a->type = SOCK_RAW;
|
.sockaddr.nl.nl_groups = group,
|
||||||
a->size = sizeof(struct sockaddr_nl);
|
.protocol = family,
|
||||||
a->protocol = family;
|
.size = sizeof(struct sockaddr_nl),
|
||||||
|
};
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -345,10 +300,14 @@ int in_addr_port_ifindex_name_from_string_auto(
|
||||||
|
|
||||||
/* This accepts the following:
|
/* This accepts the following:
|
||||||
* 192.168.0.1:53#example.com
|
* 192.168.0.1:53#example.com
|
||||||
* [2001:4860:4860::8888]:53%eth0#example.com */
|
* [2001:4860:4860::8888]:53%eth0#example.com
|
||||||
|
*
|
||||||
/* if ret_port is NULL, then strings with port cannot be specified.
|
* If ret_port is NULL, then the port cannot be specified.
|
||||||
* Also, if ret_server_name is NULL, then server_name 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, '#');
|
m = strchr(s, '#');
|
||||||
if (m) {
|
if (m) {
|
||||||
|
@ -369,15 +328,19 @@ int in_addr_port_ifindex_name_from_string_auto(
|
||||||
|
|
||||||
m = strchr(s, '%');
|
m = strchr(s, '%');
|
||||||
if (m) {
|
if (m) {
|
||||||
|
if (!ret_ifindex)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
if (isempty(m + 1))
|
if (isempty(m + 1))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
if (ret_ifindex) {
|
if (!ifname_valid_full(m + 1, IFNAME_VALID_ALTERNATIVE | IFNAME_VALID_NUMERIC))
|
||||||
/* If we shall return the interface index, try to parse it */
|
return -EINVAL; /* We want to return -EINVAL for syntactically invalid names,
|
||||||
ifindex = resolve_interface(NULL, m + 1);
|
* and -ENODEV for valid but nonexistent interfaces. */
|
||||||
if (ifindex < 0)
|
|
||||||
return ifindex;
|
ifindex = resolve_interface(NULL, m + 1);
|
||||||
}
|
if (ifindex < 0)
|
||||||
|
return ifindex;
|
||||||
|
|
||||||
s = buf2 = strndup(s, m - s);
|
s = buf2 = strndup(s, m - s);
|
||||||
if (!buf2)
|
if (!buf2)
|
||||||
|
@ -455,36 +418,6 @@ int in_addr_port_ifindex_name_from_string_auto(
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
int in_addr_port_from_string_auto(
|
|
||||||
const char *s,
|
|
||||||
int *ret_family,
|
|
||||||
union in_addr_union *ret_address,
|
|
||||||
uint16_t *ret_port) {
|
|
||||||
|
|
||||||
union in_addr_union addr;
|
|
||||||
int family, ifindex, r;
|
|
||||||
uint16_t port;
|
|
||||||
|
|
||||||
assert(s);
|
|
||||||
|
|
||||||
r = in_addr_port_ifindex_name_from_string_auto(s, &family, &addr, &port, &ifindex, NULL);
|
|
||||||
if (r < 0)
|
|
||||||
return r;
|
|
||||||
|
|
||||||
/* This does not accept interface specified. */
|
|
||||||
if (ifindex != 0)
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
if (ret_family)
|
|
||||||
*ret_family = family;
|
|
||||||
if (ret_address)
|
|
||||||
*ret_address = addr;
|
|
||||||
if (ret_port)
|
|
||||||
*ret_port = port;
|
|
||||||
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct in_addr_full *in_addr_full_free(struct in_addr_full *a) {
|
struct in_addr_full *in_addr_full_free(struct in_addr_full *a) {
|
||||||
if (!a)
|
if (!a)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
|
@ -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) {
|
static inline int in_addr_ifindex_from_string_auto(const char *s, int *family, union in_addr_union *ret, int *ifindex) {
|
||||||
return in_addr_ifindex_name_from_string_auto(s, family, ret, ifindex, NULL);
|
return in_addr_ifindex_name_from_string_auto(s, family, ret, ifindex, NULL);
|
||||||
}
|
}
|
||||||
int in_addr_port_from_string_auto(const char *s, int *ret_family, union in_addr_union *ret_address, uint16_t *ret_port);
|
|
||||||
|
|
||||||
struct in_addr_full {
|
struct in_addr_full {
|
||||||
int family;
|
int family;
|
||||||
|
|
|
@ -58,6 +58,8 @@ static void test_in_addr_prefix_from_string_one(
|
||||||
}
|
}
|
||||||
|
|
||||||
static void test_in_addr_prefix_from_string(void) {
|
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("/", 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);
|
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;
|
union in_addr_union u;
|
||||||
unsigned char l;
|
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_from_string(p, family, &u, &l) >= 0);
|
||||||
assert_se(in_addr_prefix_to_string(family, &u, l, &str) >= 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;
|
union in_addr_union u1, u2;
|
||||||
unsigned char len1, len2;
|
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_from_string(p, family, &u1, &len1) >= 0);
|
||||||
assert_se(in_addr_prefix_to_string(family, &u1, len1, &str1) >= 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) {
|
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, "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/0");
|
||||||
test_in_addr_prefix_to_string_valid(AF_INET, "1.2.3.4/24");
|
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;
|
_cleanup_free_ char *str = NULL;
|
||||||
union in_addr_union a;
|
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_from_string(AF_INET, "192.168.10.1", &a) >= 0);
|
||||||
|
|
||||||
assert_se(in_addr_random_prefix(AF_INET, &a, 31, 32) >= 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;
|
int r;
|
||||||
|
|
||||||
r = socket_address_parse(&a, in);
|
r = socket_address_parse(&a, in);
|
||||||
if (r >= 0)
|
if (r >= 0) {
|
||||||
assert_se(socket_address_print(&a, &out) >= 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,
|
log_info("\"%s\" → %s %d → \"%s\" (expect %d / \"%s\")",
|
||||||
r >= 0 ? "✓" : "✗", empty_to_dash(out), r >= 0 ? expected ?: in : "-");
|
in,
|
||||||
|
r >= 0 ? "✓" : "✗", r,
|
||||||
|
empty_to_dash(out),
|
||||||
|
ret,
|
||||||
|
ret >= 0 ? expected ?: in : "-");
|
||||||
assert_se(r == ret);
|
assert_se(r == ret);
|
||||||
if (r >= 0) {
|
if (r >= 0) {
|
||||||
assert_se(a.sockaddr.sa.sa_family == family);
|
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]:0", -EINVAL, 0, NULL);
|
||||||
test_socket_address_parse_one("[::1]:65536", -ERANGE, 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("[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("8888", 0, default_family, "[::]:8888");
|
||||||
test_socket_address_parse_one("[2001:0db8:0000:85a3:0000:0000:ac1f:8001]:8888", 0, AF_INET6,
|
test_socket_address_parse_one("[2001:0db8:0000:85a3:0000:0000:ac1f:8001]:8888", 0, AF_INET6,
|
||||||
"[2001:db8:0:85a3::ac1f:8001]:8888");
|
"[2001:db8:0:85a3::ac1f:8001]:8888");
|
||||||
test_socket_address_parse_one("[::1]:8888", 0, AF_INET6, NULL);
|
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("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("/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);
|
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__);
|
log_info("/* %s */", __func__);
|
||||||
|
|
||||||
assert_se(socket_address_parse(&a, "192.168.1.1:8888") >= 0);
|
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, "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_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) {
|
static void test_socket_address_is_netlink(void) {
|
||||||
|
@ -209,7 +232,7 @@ static void test_socket_address_is_netlink(void) {
|
||||||
log_info("/* %s */", __func__);
|
log_info("/* %s */", __func__);
|
||||||
|
|
||||||
assert_se(socket_address_parse_netlink(&a, "route 10") >= 0);
|
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, "192.168.1.1:8888"));
|
||||||
assert_se(!socket_address_is_netlink(&a, "route 1"));
|
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");
|
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) {
|
static void test_in_addr_port_ifindex_name_from_string_auto_one(const char *str, int family, uint16_t port, int ifindex,
|
||||||
_cleanup_free_ char *name = NULL, *x = NULL;
|
const char *server_name, const char *str_repr) {
|
||||||
union in_addr_union a;
|
union in_addr_union a;
|
||||||
uint16_t p;
|
uint16_t p;
|
||||||
int f, i;
|
int f, i;
|
||||||
|
char *fake;
|
||||||
|
|
||||||
assert_se(in_addr_port_ifindex_name_from_string_auto(str, &f, &a, &p, &i, &name) >= 0);
|
log_info("%s: %s", __func__, str);
|
||||||
assert_se(family == f);
|
|
||||||
assert_se(port == p);
|
{
|
||||||
assert_se(ifindex == i);
|
_cleanup_free_ char *name = NULL, *x = NULL;
|
||||||
assert_se(streq_ptr(server_name, name));
|
assert_se(in_addr_port_ifindex_name_from_string_auto(str, &f, &a, &p, &i, &name) == 0);
|
||||||
assert_se(in_addr_port_ifindex_name_to_string(f, &a, p, i, name, &x) >= 0);
|
assert_se(family == f);
|
||||||
assert_se(streq(str, x));
|
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) {
|
static void test_in_addr_port_ifindex_name_from_string_auto(void) {
|
||||||
log_info("/* %s */", __func__);
|
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", 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");
|
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);
|
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");
|
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);
|
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");
|
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);
|
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]:53", AF_INET6, 53, 0, 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%19#hoge.com", AF_INET6, 0, 19, "hoge.com");
|
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#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, NULL);
|
||||||
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%lo", AF_INET6, 53, 1, NULL, "[fe80::18]:53%1");
|
||||||
test_in_addr_port_ifindex_name_from_string_auto_one("[fe80::18]:53%19#hoge.com", AF_INET6, 53, 19, "hoge.com");
|
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);
|
||||||
static void test_in_addr_port_from_string_auto_one(const char *str, int family, const char *address_string, uint16_t port) {
|
test_in_addr_port_ifindex_name_from_string_auto_one("[fe80::18]:53%19#hoge.com", AF_INET6, 53, 19, "hoge.com", NULL);
|
||||||
union in_addr_union a, b;
|
test_in_addr_port_ifindex_name_from_string_auto_one("[fe80::18]:53%lo", AF_INET6, 53, 1, NULL, "[fe80::18]:53%1");
|
||||||
uint16_t p;
|
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 f;
|
|
||||||
|
|
||||||
assert_se(in_addr_port_from_string_auto(str, &f, &a, &p) >= 0);
|
|
||||||
assert_se(family == f);
|
|
||||||
assert_se(port == p);
|
|
||||||
assert_se(in_addr_from_string(family, address_string, &b) >= 0);
|
|
||||||
assert_se(in_addr_equal(family, &a, &b) == 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void test_in_addr_port_from_string_auto(void) {
|
|
||||||
log_info("/* %s */", __func__);
|
|
||||||
|
|
||||||
assert_se(in_addr_port_from_string_auto("192.168.0.1#test.com", NULL, NULL, NULL) < 0);
|
|
||||||
assert_se(in_addr_port_from_string_auto("192.168.0.1:53#example.com", NULL, NULL, NULL) < 0);
|
|
||||||
assert_se(in_addr_port_from_string_auto("fe80::18#hoge.com", NULL, NULL, NULL) < 0);
|
|
||||||
assert_se(in_addr_port_from_string_auto("fe80::18%19", NULL, NULL, NULL) < 0);
|
|
||||||
assert_se(in_addr_port_from_string_auto("fe80::18%19#hoge.com", NULL, NULL, NULL) < 0);
|
|
||||||
assert_se(in_addr_port_from_string_auto("[fe80::18]:53#hoge.com", NULL, NULL, NULL) < 0);
|
|
||||||
assert_se(in_addr_port_from_string_auto("[fe80::18]:53%19", NULL, NULL, NULL) < 0);
|
|
||||||
assert_se(in_addr_port_from_string_auto("[fe80::18]:53%19#hoge.com", NULL, NULL, NULL) < 0);
|
|
||||||
|
|
||||||
test_in_addr_port_from_string_auto_one("192.168.0.1", AF_INET, "192.168.0.1", 0);
|
|
||||||
test_in_addr_port_from_string_auto_one("192.168.0.1:53", AF_INET, "192.168.0.1", 53);
|
|
||||||
test_in_addr_port_from_string_auto_one("fe80::18", AF_INET6, "fe80::18", 0);
|
|
||||||
test_in_addr_port_from_string_auto_one("[fe80::18]:53", AF_INET6, "fe80::18", 53);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, char *argv[]) {
|
int main(int argc, char *argv[]) {
|
||||||
|
@ -360,7 +400,6 @@ int main(int argc, char *argv[]) {
|
||||||
test_in_addr_ifindex_from_string_auto();
|
test_in_addr_ifindex_from_string_auto();
|
||||||
test_in_addr_ifindex_name_from_string_auto();
|
test_in_addr_ifindex_name_from_string_auto();
|
||||||
test_in_addr_port_ifindex_name_from_string_auto();
|
test_in_addr_port_ifindex_name_from_string_auto();
|
||||||
test_in_addr_port_from_string_auto();
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,13 +26,13 @@ assert_cc(SUN_PATH_LEN == 108);
|
||||||
static void test_ifname_valid(void) {
|
static void test_ifname_valid(void) {
|
||||||
log_info("/* %s */", __func__);
|
log_info("/* %s */", __func__);
|
||||||
|
|
||||||
assert(ifname_valid("foo"));
|
assert( ifname_valid("foo"));
|
||||||
assert(ifname_valid("eth0"));
|
assert( ifname_valid("eth0"));
|
||||||
|
|
||||||
assert(!ifname_valid("0"));
|
assert(!ifname_valid("0"));
|
||||||
assert(!ifname_valid("99"));
|
assert(!ifname_valid("99"));
|
||||||
assert(ifname_valid("a99"));
|
assert( ifname_valid("a99"));
|
||||||
assert(ifname_valid("99a"));
|
assert( ifname_valid("99a"));
|
||||||
|
|
||||||
assert(!ifname_valid(NULL));
|
assert(!ifname_valid(NULL));
|
||||||
assert(!ifname_valid(""));
|
assert(!ifname_valid(""));
|
||||||
|
@ -44,9 +44,13 @@ static void test_ifname_valid(void) {
|
||||||
assert(ifname_valid("foo.bar"));
|
assert(ifname_valid("foo.bar"));
|
||||||
assert(!ifname_valid("x:y"));
|
assert(!ifname_valid("x:y"));
|
||||||
|
|
||||||
assert(ifname_valid("xxxxxxxxxxxxxxx"));
|
assert( ifname_valid_full("xxxxxxxxxxxxxxx", 0));
|
||||||
assert(!ifname_valid("xxxxxxxxxxxxxxxx"));
|
assert(!ifname_valid_full("xxxxxxxxxxxxxxxx", 0));
|
||||||
assert(ifname_valid_full("xxxxxxxxxxxxxxxx", true));
|
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) {
|
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_setup_logging(LOG_DEBUG);
|
||||||
|
|
||||||
test_ifname_valid();
|
test_ifname_valid();
|
||||||
|
|
||||||
test_socket_print_unix();
|
test_socket_print_unix();
|
||||||
|
|
||||||
test_sockaddr_equal();
|
test_sockaddr_equal();
|
||||||
|
|
||||||
test_sockaddr_un_len();
|
test_sockaddr_un_len();
|
||||||
|
|
||||||
test_in_addr_is_multicast();
|
test_in_addr_is_multicast();
|
||||||
|
|
||||||
test_getpeercred_getpeergroups();
|
test_getpeercred_getpeergroups();
|
||||||
|
|
||||||
test_passfd_read();
|
test_passfd_read();
|
||||||
test_passfd_contents_read();
|
test_passfd_contents_read();
|
||||||
test_receive_nopassfd();
|
test_receive_nopassfd();
|
||||||
|
|
|
@ -7,6 +7,7 @@ _Pragma("GCC diagnostic ignored \"-Wimplicit-fallthrough\"")
|
||||||
#include "ethtool-util.h"
|
#include "ethtool-util.h"
|
||||||
#include "link-config.h"
|
#include "link-config.h"
|
||||||
#include "network-internal.h"
|
#include "network-internal.h"
|
||||||
|
#include "socket-util.h"
|
||||||
%}
|
%}
|
||||||
struct ConfigPerfItem;
|
struct ConfigPerfItem;
|
||||||
%null_strings
|
%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.MACAddress, config_parse_hwaddr, 0, offsetof(link_config, mac)
|
||||||
Link.NamePolicy, config_parse_name_policy, 0, offsetof(link_config, name_policy)
|
Link.NamePolicy, config_parse_name_policy, 0, offsetof(link_config, name_policy)
|
||||||
Link.Name, config_parse_ifname, 0, offsetof(link_config, name)
|
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.AlternativeNamesPolicy, config_parse_alternative_names_policy, 0, offsetof(link_config, alternative_names_policy)
|
||||||
Link.Alias, config_parse_ifalias, 0, offsetof(link_config, alias)
|
Link.Alias, config_parse_ifalias, 0, offsetof(link_config, alias)
|
||||||
Link.MTUBytes, config_parse_mtu, AF_UNSPEC, offsetof(link_config, mtu)
|
Link.MTUBytes, config_parse_mtu, AF_UNSPEC, offsetof(link_config, mtu)
|
||||||
|
|
Loading…
Reference in New Issue