]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
Add sd_is_socket_sockaddr (#4885)
authorZbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>
Wed, 14 Dec 2016 10:51:26 +0000 (05:51 -0500)
committerLennart Poettering <lennart@poettering.net>
Wed, 14 Dec 2016 10:51:26 +0000 (11:51 +0100)
Fixes #1188.

Makefile-man.am
man/sd_is_fifo.xml
src/libsystemd/libsystemd.sym
src/libsystemd/sd-daemon/sd-daemon.c
src/systemd/sd-daemon.h

index 228e29fc4f4ef035e5353a4d563c34a178cff75f..5e6eee5e325661bd9fdb07b37df5c4257554bc42 100644 (file)
@@ -403,6 +403,7 @@ MANPAGES_ALIAS += \
        man/sd_is_mq.3 \
        man/sd_is_socket.3 \
        man/sd_is_socket_inet.3 \
+       man/sd_is_socket_sockaddr.3 \
        man/sd_is_socket_unix.3 \
        man/sd_is_special.3 \
        man/sd_journal.3 \
@@ -757,6 +758,7 @@ man/sd_id128_t.3: man/sd-id128.3
 man/sd_is_mq.3: man/sd_is_fifo.3
 man/sd_is_socket.3: man/sd_is_fifo.3
 man/sd_is_socket_inet.3: man/sd_is_fifo.3
+man/sd_is_socket_sockaddr.3: man/sd_is_fifo.3
 man/sd_is_socket_unix.3: man/sd_is_fifo.3
 man/sd_is_special.3: man/sd_is_fifo.3
 man/sd_journal.3: man/sd_journal_open.3
@@ -1551,6 +1553,9 @@ man/sd_is_socket.html: man/sd_is_fifo.html
 man/sd_is_socket_inet.html: man/sd_is_fifo.html
        $(html-alias)
 
+man/sd_is_socket_sockaddr.html: man/sd_is_fifo.html
+       $(html-alias)
+
 man/sd_is_socket_unix.html: man/sd_is_fifo.html
        $(html-alias)
 
index 991c7f8bd80ac0bfc2c9091bf2f97150a1e39261..1192ca168152083c94bbbb2ffb613d73422460f2 100644 (file)
@@ -48,6 +48,7 @@
     <refname>sd_is_socket</refname>
     <refname>sd_is_socket_inet</refname>
     <refname>sd_is_socket_unix</refname>
+    <refname>sd_is_socket_sockaddr</refname>
     <refname>sd_is_mq</refname>
     <refname>sd_is_special</refname>
     <refpurpose>Check the type of a file descriptor</refpurpose>
         <paramdef>uint16_t <parameter>port</parameter></paramdef>
       </funcprototype>
 
+      <funcprototype>
+        <funcdef>int <function>sd_is_socket_sockaddr</function></funcdef>
+        <paramdef>int <parameter>fd</parameter></paramdef>
+        <paramdef>int <parameter>type</parameter></paramdef>
+        <paramdef>const struct sockaddr *<parameter>addr</parameter></paramdef>
+        <paramdef>unsigned <parameter>addr_len</parameter></paramdef>
+        <paramdef>int <parameter>listening</parameter></paramdef>
+      </funcprototype>
+
       <funcprototype>
         <funcdef>int <function>sd_is_socket_unix</function></funcdef>
         <paramdef>int <parameter>fd</parameter></paramdef>
     <constant>AF_UNSPEC</constant>, <constant>AF_INET</constant>, or
     <constant>AF_INET6</constant>.</para>
 
+    <para><function>sd_is_socket_sockaddr()</function> is similar to
+    <function>sd_is_socket_inet()</function>, but checks if the socket is bound to the
+    address specified by <parameter>addr</parameter>. The
+    <structfield>family</structfield> specified by <parameter>addr</parameter> must be
+    either <constant>AF_INET</constant> or <constant>AF_INET6</constant> and
+    <parameter>addr_len</parameter> must be large enough for that family. If
+    <parameter>addr</parameter> specifies a non-zero port, it is also checked if the
+    socket is bound to this port. In addition, for IPv6, if <parameter>addr</parameter>
+    specifies non-zero <structfield>sin6_flowinfo</structfield> or
+    <structfield>sin6_scope_id</structfield>, it is checked if the socket has the same
+    values.</para>
+
     <para><function>sd_is_socket_unix()</function> is similar to
     <function>sd_is_socket()</function> but optionally checks the
     <constant>AF_UNIX</constant> path the socket is bound to, unless
       <citerefentry><refentrytitle>sd-daemon</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
       <citerefentry><refentrytitle>sd_listen_fds</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
       <citerefentry><refentrytitle>systemd.service</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
-      <citerefentry><refentrytitle>systemd.socket</refentrytitle><manvolnum>5</manvolnum></citerefentry>
+      <citerefentry><refentrytitle>systemd.socket</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
+      <citerefentry project='man-pages'><refentrytitle>ip</refentrytitle><manvolnum>7</manvolnum></citerefentry>,
+      <citerefentry project='man-pages'><refentrytitle>ipv6</refentrytitle><manvolnum>7</manvolnum></citerefentry>,
+      <citerefentry project='man-pages'><refentrytitle>unix</refentrytitle><manvolnum>7</manvolnum></citerefentry>,
+      <citerefentry project='man-pages'><refentrytitle>fifo</refentrytitle><manvolnum>7</manvolnum></citerefentry>,
+      <citerefentry project='man-pages'><refentrytitle>mq_overview</refentrytitle><manvolnum>7</manvolnum></citerefentry>,
+      <citerefentry project='man-pages'><refentrytitle>socket</refentrytitle><manvolnum>7</manvolnum></citerefentry>.
     </para>
   </refsect1>
 
index 46c4dac7d71128b5f685eac11150d640f2253b9f..c1135ffa226ec1ff52deda9055819529ebd5463a 100644 (file)
@@ -515,4 +515,5 @@ global:
 LIBSYSTEMD_233 {
 global:
         sd_id128_get_machine_app_specific;
+        sd_is_socket_sockaddr;
 } LIBSYSTEMD_232;
index b20a7ebb4c3c8b6be14aaec2cfe85ccb1886e8e7..a9a32dd5a2b59d53e8a3d34667aeab1a2ff4138b 100644 (file)
@@ -322,6 +322,64 @@ _public_ int sd_is_socket_inet(int fd, int family, int type, int listening, uint
         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);
index 740b176903cb1dad509c88ff3039819d53da0999..8c096f610fbbb77e5b423d8dda1e6531da20a78b 100644 (file)
@@ -22,6 +22,7 @@
 
 #include <inttypes.h>
 #include <sys/types.h>
+#include <sys/socket.h>
 
 #include "_sd-common.h"
 
@@ -130,6 +131,18 @@ int sd_is_socket(int fd, int family, int type, int listening);
 */
 int sd_is_socket_inet(int fd, int family, int type, int listening, uint16_t port);
 
+/*
+  Helper call for identifying a passed file descriptor. Returns 1 if the
+  file descriptor is an Internet socket of the specified type
+  (SOCK_DGRAM, SOCK_STREAM, ...), and if the address of the socket is
+  the same as the address specified by addr. The listening flag is used
+  the same way as in sd_is_socket(). Returns a negative errno style
+  error code on failure.
+
+  See sd_is_socket_sockaddr(3) for more information.
+*/
+int sd_is_socket_sockaddr(int fd, int type, const struct sockaddr* addr, unsigned addr_len, int listening);
+
 /*
   Helper call for identifying a passed file descriptor. Returns 1 if
   the file descriptor is an AF_UNIX socket of the specified type