diff --git a/Makefile-man.am b/Makefile-man.am
index 228e29fc4f..5e6eee5e32 100644
--- a/Makefile-man.am
+++ b/Makefile-man.am
@@ -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)
diff --git a/man/sd_is_fifo.xml b/man/sd_is_fifo.xml
index 991c7f8bd8..1192ca1681 100644
--- a/man/sd_is_fifo.xml
+++ b/man/sd_is_fifo.xml
@@ -48,6 +48,7 @@
sd_is_socket
sd_is_socket_inet
sd_is_socket_unix
+ sd_is_socket_sockaddr
sd_is_mq
sd_is_special
Check the type of a file descriptor
@@ -80,6 +81,15 @@
uint16_t port
+
+ int sd_is_socket_sockaddr
+ int fd
+ int type
+ const struct sockaddr *addr
+ unsigned addr_len
+ int listening
+
+
int sd_is_socket_unix
int fd
@@ -139,6 +149,18 @@
AF_UNSPEC, AF_INET, or
AF_INET6.
+ sd_is_socket_sockaddr() is similar to
+ sd_is_socket_inet(), but checks if the socket is bound to the
+ address specified by addr. The
+ family specified by addr must be
+ either AF_INET or AF_INET6 and
+ addr_len must be large enough for that family. If
+ addr specifies a non-zero port, it is also checked if the
+ socket is bound to this port. In addition, for IPv6, if addr
+ specifies non-zero sin6_flowinfo or
+ sin6_scope_id, it is checked if the socket has the same
+ values.
+
sd_is_socket_unix() is similar to
sd_is_socket() but optionally checks the
AF_UNIX path the socket is bound to, unless
@@ -193,7 +215,13 @@
sd-daemon3,
sd_listen_fds3,
systemd.service5,
- systemd.socket5
+ systemd.socket5,
+ ip7,
+ ipv67,
+ unix7,
+ fifo7,
+ mq_overview7,
+ socket7.
diff --git a/src/libsystemd/libsystemd.sym b/src/libsystemd/libsystemd.sym
index 46c4dac7d7..c1135ffa22 100644
--- a/src/libsystemd/libsystemd.sym
+++ b/src/libsystemd/libsystemd.sym
@@ -515,4 +515,5 @@ global:
LIBSYSTEMD_233 {
global:
sd_id128_get_machine_app_specific;
+ sd_is_socket_sockaddr;
} LIBSYSTEMD_232;
diff --git a/src/libsystemd/sd-daemon/sd-daemon.c b/src/libsystemd/sd-daemon/sd-daemon.c
index b20a7ebb4c..a9a32dd5a2 100644
--- a/src/libsystemd/sd-daemon/sd-daemon.c
+++ b/src/libsystemd/sd-daemon/sd-daemon.c
@@ -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);
diff --git a/src/systemd/sd-daemon.h b/src/systemd/sd-daemon.h
index 740b176903..8c096f610f 100644
--- a/src/systemd/sd-daemon.h
+++ b/src/systemd/sd-daemon.h
@@ -22,6 +22,7 @@
#include
#include
+#include
#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