]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
shared: make socket_address_parse use the generic parser for IPv[46] addresses
authorZbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>
Thu, 3 Sep 2020 11:01:13 +0000 (13:01 +0200)
committerZbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>
Wed, 9 Sep 2020 22:46:44 +0000 (00:46 +0200)
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.

src/shared/socket-netlink.c

index 444aae271ac1a39942f408e001683e35b58af6ce..25bc0167a63999c08741c642666b533741e3f156 100644 (file)
@@ -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");
                 }
         }