summaryrefslogtreecommitdiff
path: root/src/shared/socket-netlink.c
diff options
context:
space:
mode:
authorZbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>2020-09-03 13:01:13 +0200
committerZbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>2020-09-10 00:46:44 +0200
commit75af1666d7476ee77f47bcc2e6c415c040326eb9 (patch)
treeb88547e2049bee12c5866baee4f8648b5d53658a /src/shared/socket-netlink.c
parent222eaaf937d3d39beaea1878e04f20b1689834ec (diff)
downloadsystemd-75af1666d7476ee77f47bcc2e6c415c040326eb9.tar.gz
shared: make socket_address_parse use the generic parser for IPv[46] addresses
One special syntax is not supported anymore: "iface:port" would be parsed as an interface name plus numerical port, equivalent to "[::]%iface:port". This was added in 542563babda, but was undocumented, and we had no tests for it. It seems that this actually wasn't doing anything useful, because the kernel only uses the scope identifier for link-local addresses.
Diffstat (limited to 'src/shared/socket-netlink.c')
-rw-r--r--src/shared/socket-netlink.c105
1 files changed, 33 insertions, 72 deletions
diff --git a/src/shared/socket-netlink.c b/src/shared/socket-netlink.c
index 444aae271a..25bc0167a6 100644
--- a/src/shared/socket-netlink.c
+++ b/src/shared/socket-netlink.c
@@ -66,39 +66,8 @@ int socket_address_parse(SocketAddress *a, const char *s) {
.type = SOCK_STREAM,
};
- 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);
- 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 == '/') {
+ if (*s == '/') {
/* AF_UNIX socket */
-
size_t l;
l = strlen(s);
@@ -158,47 +127,11 @@ int socket_address_parse(SocketAddress *a, const char *s) {
} 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 (r < 0)
- return r;
-
if (socket_ipv6_is_supported()) {
a->sockaddr.in6.sin6_family = AF_INET6;
a->sockaddr.in6.sin6_port = htobe16(port);
@@ -210,6 +143,34 @@ int socket_address_parse(SocketAddress *a, const char *s) {
a->sockaddr.in.sin_addr.s_addr = INADDR_ANY;
a->size = sizeof(struct sockaddr_in);
}
+
+ } else {
+ union in_addr_union address;
+ int family;
+
+ r = in_addr_port_ifindex_name_from_string_auto(s, &family, &address, &port, NULL, NULL);
+ if (r < 0)
+ return r;
+
+ if (port == 0) /* No port, no go. */
+ return -EINVAL;
+
+ if (family == AF_INET) {
+ a->sockaddr.in = (struct sockaddr_in) {
+ .sin_family = AF_INET,
+ .sin_addr = address.in,
+ .sin_port = htobe16(port),
+ };
+ a->size = sizeof(struct sockaddr_in);
+ } else if (family == AF_INET6) {
+ a->sockaddr.in6 = (struct sockaddr_in6) {
+ .sin6_family = AF_INET6,
+ .sin6_addr = address.in6,
+ .sin6_port = htobe16(port),
+ };
+ a->size = sizeof(struct sockaddr_in6);
+ } else
+ assert_not_reached("Family quarrel");
}
}