chiark / gitweb /
Add sd_is_socket_sockaddr (#4885)
[elogind.git] / src / libelogind / sd-daemon / sd-daemon.c
index a25353bb51adc1c87f678abc6bc3728809d08ed4..3e66092b110b907f003191b903c3de55050cddef 100644 (file)
@@ -1,5 +1,3 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
 /***
   This file is part of systemd.
 
@@ -105,7 +103,7 @@ _public_ int sd_listen_fds(int unset_environment) {
 finish:
         unsetenv_all(unset_environment);
         return r;
-        }
+}
 
 _public_ int sd_listen_fds_with_names(int unset_environment, char ***names) {
         _cleanup_strv_free_ char **l = NULL;
@@ -139,8 +137,8 @@ _public_ int sd_listen_fds_with_names(int unset_environment, char ***names) {
         } else {
                 r = strv_extend_n(&l, "unknown", n_fds);
                 if (r < 0)
-        return r;
-}
+                        return r;
+        }
 
         *names = l;
         l = NULL;
@@ -315,18 +313,76 @@ _public_ int sd_is_socket_inet(int fd, int family, int type, int listening, uint
                         if (l < sizeof(struct sockaddr_in))
                                 return -EINVAL;
 
-                        return htons(port) == sockaddr.in.sin_port;
+                        return htobe16(port) == sockaddr.in.sin_port;
                 } else {
                         if (l < sizeof(struct sockaddr_in6))
                                 return -EINVAL;
 
-                        return htons(port) == sockaddr.in6.sin6_port;
+                        return htobe16(port) == sockaddr.in6.sin6_port;
                 }
         }
 
         return 1;
 }
 
+_public_ int sd_is_socket_sockaddr(int fd, int type, const struct sockaddr* addr, unsigned addr_len, int listening) {
+        union sockaddr_union sockaddr = {};
+        socklen_t l = sizeof(sockaddr);
+        int r;
+
+        assert_return(fd >= 0, -EBADF);
+        assert_return(addr, -EINVAL);
+        assert_return(addr_len >= sizeof(sa_family_t), -ENOBUFS);
+        assert_return(IN_SET(addr->sa_family, AF_INET, AF_INET6), -EPFNOSUPPORT);
+
+        r = sd_is_socket_internal(fd, type, listening);
+        if (r <= 0)
+                return r;
+
+        if (getsockname(fd, &sockaddr.sa, &l) < 0)
+                return -errno;
+
+        if (l < sizeof(sa_family_t))
+                return -EINVAL;
+
+        if (sockaddr.sa.sa_family != addr->sa_family)
+                return 0;
+
+        if (sockaddr.sa.sa_family == AF_INET) {
+                const struct sockaddr_in *in = (const struct sockaddr_in *) addr;
+
+                if (l < sizeof(struct sockaddr_in) || addr_len < sizeof(struct sockaddr_in))
+                        return -EINVAL;
+
+                if (in->sin_port != 0 &&
+                    sockaddr.in.sin_port != in->sin_port)
+                        return false;
+
+                return sockaddr.in.sin_addr.s_addr == in->sin_addr.s_addr;
+
+        } else {
+                const struct sockaddr_in6 *in = (const struct sockaddr_in6 *) addr;
+
+                if (l < sizeof(struct sockaddr_in6) || addr_len < sizeof(struct sockaddr_in6))
+                        return -EINVAL;
+
+                if (in->sin6_port != 0 &&
+                    sockaddr.in6.sin6_port != in->sin6_port)
+                        return false;
+
+                if (in->sin6_flowinfo != 0 &&
+                    sockaddr.in6.sin6_flowinfo != in->sin6_flowinfo)
+                        return false;
+
+                if (in->sin6_scope_id != 0 &&
+                    sockaddr.in6.sin6_scope_id != in->sin6_scope_id)
+                        return false;
+
+                return memcmp(sockaddr.in6.sin6_addr.s6_addr, in->sin6_addr.s6_addr,
+                              sizeof(in->sin6_addr.s6_addr)) == 0;
+        }
+}
+
 _public_ int sd_is_socket_unix(int fd, int type, int listening, const char *path, size_t length) {
         union sockaddr_union sockaddr = {};
         socklen_t l = sizeof(sockaddr);
@@ -464,14 +520,12 @@ _public_ int sd_pid_notify_with_fds(pid_t pid, int unset_environment, const char
         if (sockaddr.un.sun_path[0] == '@')
                 sockaddr.un.sun_path[0] = 0;
 
-        msghdr.msg_namelen = offsetof(struct sockaddr_un, sun_path) + strlen(e);
-        if (msghdr.msg_namelen > sizeof(struct sockaddr_un))
-                msghdr.msg_namelen = sizeof(struct sockaddr_un);
+        msghdr.msg_namelen = SOCKADDR_UN_LEN(sockaddr.un);
 
         have_pid = pid != 0 && pid != getpid();
 
         if (n_fds > 0 || have_pid) {
-                /* CMSG_SPACE(0) may return value different then zero, which results in miscalculated controllen. */
+                /* CMSG_SPACE(0) may return value different than zero, which results in miscalculated controllen. */
                 msghdr.msg_controllen =
                         (n_fds > 0 ? CMSG_SPACE(sizeof(int) * n_fds) : 0) +
                         (have_pid ? CMSG_SPACE(sizeof(struct ucred)) : 0);