]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
src/shared/: split AF_UNIX/AF_VSOCK address parsing into src/basic/
authorLuca Boccassi <bluca@debian.org>
Tue, 3 Jan 2023 17:01:28 +0000 (18:01 +0100)
committerLuca Boccassi <bluca@debian.org>
Thu, 5 Jan 2023 17:43:47 +0000 (18:43 +0100)
We'll use it from libsystemd0 later, but AF_INET/6 requires some
netlink calls and thus the additional library dependency

src/basic/socket-util.c
src/basic/socket-util.h
src/shared/socket-netlink.c

index 54f5f1cc5bca053d88e910e7609e00abf70ec5f7..d7946a3641a5b1f7e56fa6f4f69ba58e76aa0ee9 100644 (file)
@@ -1472,3 +1472,71 @@ int connect_unix_path(int fd, int dir_fd, const char *path) {
 
         return RET_NERRNO(connect(fd, &sa.sa, salen));
 }
+
+int socket_address_parse_unix(SocketAddress *ret_address, const char *s) {
+        struct sockaddr_un un;
+        int r;
+
+        assert(ret_address);
+        assert(s);
+
+        if (!IN_SET(*s, '/', '@'))
+                return -EPROTO;
+
+        r = sockaddr_un_set_path(&un, s);
+        if (r < 0)
+                return r;
+
+        *ret_address = (SocketAddress) {
+                .sockaddr.un = un,
+                .size = r,
+        };
+
+        return 0;
+}
+
+int socket_address_parse_vsock(SocketAddress *ret_address, const char *s) {
+        /* AF_VSOCK socket in vsock:cid:port notation */
+        _cleanup_free_ char *n = NULL;
+        char *e, *cid_start;
+        unsigned port, cid;
+        int r;
+
+        assert(ret_address);
+        assert(s);
+
+        cid_start = startswith(s, "vsock:");
+        if (!cid_start)
+                return -EPROTO;
+
+        e = strchr(cid_start, ':');
+        if (!e)
+                return -EINVAL;
+
+        r = safe_atou(e+1, &port);
+        if (r < 0)
+                return r;
+
+        n = strndup(cid_start, e - cid_start);
+        if (!n)
+                return -ENOMEM;
+
+        if (isempty(n))
+                cid = VMADDR_CID_ANY;
+        else {
+                r = safe_atou(n, &cid);
+                if (r < 0)
+                        return r;
+        }
+
+        *ret_address = (SocketAddress) {
+                .sockaddr.vm = {
+                        .svm_cid = cid,
+                        .svm_family = AF_VSOCK,
+                        .svm_port = port,
+                },
+                .size = sizeof(struct sockaddr_vm),
+        };
+
+        return 0;
+}
index 0b8d53e8954257d03a3b523c2fe41b8a7170220f..5cb35f65fb9fdb9985ad0edc304b508dda70f201 100644 (file)
@@ -336,3 +336,9 @@ int socket_get_mtu(int fd, int af, size_t *ret);
 #define UCRED_INVALID { .pid = 0, .uid = UID_INVALID, .gid = GID_INVALID }
 
 int connect_unix_path(int fd, int dir_fd, const char *path);
+
+/* Parses AF_UNIX and AF_VSOCK addresses. AF_INET[6] require some netlink calls, so it cannot be in
+ * src/basic/ and is done from 'socket_local_address from src/shared/. Return -EPROTO in case of
+ * protocol mismatch. */
+int socket_address_parse_unix(SocketAddress *ret_address, const char *s);
+int socket_address_parse_vsock(SocketAddress *ret_address, const char *s);
index 494047a5d159d21f8218fd1c7dc54d920bc4cb91..e115dff5064f2bd9912a23629bed719647682a25 100644 (file)
 #include "string-util.h"
 
 int socket_address_parse(SocketAddress *a, const char *s) {
-        _cleanup_free_ char *n = NULL;
-        char *e;
+        uint16_t port;
         int r;
 
         assert(a);
         assert(s);
 
-        if (IN_SET(*s, '/', '@')) {
-                /* AF_UNIX socket */
-                struct sockaddr_un un;
-
-                r = sockaddr_un_set_path(&un, s);
-                if (r < 0)
-                        return r;
-
-                *a = (SocketAddress) {
-                        .sockaddr.un = un,
-                        .size = r,
-                };
+        r = socket_address_parse_unix(a, s);
+        if (r == -EPROTO)
+                r = socket_address_parse_vsock(a, s);
+        if (r != -EPROTO)
+                return r;
 
-        } else if (startswith(s, "vsock:")) {
-                /* AF_VSOCK socket in vsock:cid:port notation */
-                const char *cid_start = s + STRLEN("vsock:");
-                unsigned port, cid;
+        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 */
+                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),
+                        };
 
-                e = strchr(cid_start, ':');
-                if (!e)
-                        return -EINVAL;
+        } else {
+                union in_addr_union address;
+                int family, ifindex;
 
-                r = safe_atou(e+1, &port);
+                r = in_addr_port_ifindex_name_from_string_auto(s, &family, &address, &port, &ifindex, NULL);
                 if (r < 0)
                         return r;
 
-                n = strndup(cid_start, e - cid_start);
-                if (!n)
-                        return -ENOMEM;
-
-                if (isempty(n))
-                        cid = VMADDR_CID_ANY;
-                else {
-                        r = safe_atou(n, &cid);
-                        if (r < 0)
-                                return r;
-                }
-
-                *a = (SocketAddress) {
-                        .sockaddr.vm = {
-                                .svm_cid = cid,
-                                .svm_family = AF_VSOCK,
-                                .svm_port = port,
-                        },
-                        .size = sizeof(struct sockaddr_vm),
-                };
-
-        } else {
-                uint16_t port;
-
-                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 */
-                        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 (port == 0) /* No port, no go. */
-                                return -EINVAL;
+                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();
-                }
+                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();
         }
 
         return 0;