From 35a3eb9bdc95d1e6ba25bc65c78959ea104e45a1 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 27 May 2020 19:27:51 +0200 Subject: [PATCH 1/4] socket-util: add generic socket_pass_pktinfo() helper The helper turns on the protocol specific "packet info" structure cmsg for three relevant protocols we know. --- src/basic/socket-util.c | 24 +++++++++++++++++++++++- src/basic/socket-util.h | 2 ++ 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/src/basic/socket-util.c b/src/basic/socket-util.c index 0be098df2ea..05dd7e70014 100644 --- a/src/basic/socket-util.c +++ b/src/basic/socket-util.c @@ -1174,5 +1174,27 @@ ssize_t recvmsg_safe(int sockfd, struct msghdr *msg, int flags) { } return n; - +} + +int socket_pass_pktinfo(int fd, bool b) { + int af; + socklen_t sl = sizeof(af); + + if (getsockopt(fd, SOL_SOCKET, SO_DOMAIN, &af, &sl) < 0) + return -errno; + + switch (af) { + + case AF_INET: + return setsockopt_int(fd, IPPROTO_IP, IP_PKTINFO, b); + + case AF_INET6: + return setsockopt_int(fd, IPPROTO_IPV6, IPV6_RECVPKTINFO, b); + + case AF_NETLINK: + return setsockopt_int(fd, SOL_NETLINK, NETLINK_PKTINFO, b); + + default: + return -EAFNOSUPPORT; + } } diff --git a/src/basic/socket-util.h b/src/basic/socket-util.h index 6f366c04299..9e02e398875 100644 --- a/src/basic/socket-util.h +++ b/src/basic/socket-util.h @@ -220,3 +220,5 @@ int socket_bind_to_ifname(int fd, const char *ifname); int socket_bind_to_ifindex(int fd, int ifindex); ssize_t recvmsg_safe(int sockfd, struct msghdr *msg, int flags); + +int socket_pass_pktinfo(int fd, bool b); From a3d19f5d99c44940831a33df8b5bece4aaf749f7 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 27 May 2020 19:36:56 +0200 Subject: [PATCH 2/4] core: add new PassPacketInfo= socket unit property --- docs/TRANSIENT-SETTINGS.md | 1 + man/systemd.socket.xml | 9 +++++++++ src/core/dbus-socket.c | 4 ++++ src/core/load-fragment-gperf.gperf.m4 | 1 + src/core/socket.c | 8 ++++++++ src/core/socket.h | 1 + src/shared/bus-unit-util.c | 1 + test/fuzz/fuzz-unit-file/directives.service | 1 + 8 files changed, 26 insertions(+) diff --git a/docs/TRANSIENT-SETTINGS.md b/docs/TRANSIENT-SETTINGS.md index d9b1c20c77f..f8282752973 100644 --- a/docs/TRANSIENT-SETTINGS.md +++ b/docs/TRANSIENT-SETTINGS.md @@ -429,6 +429,7 @@ Most socket unit settings are available to transient units. ✓ Broadcast= ✓ PassCredentials= ✓ PassSecurity= +✓ PassPacketInfo= ✓ TCPCongestion= ✓ ReusePort= ✓ MessageQueueMaxMessages= diff --git a/man/systemd.socket.xml b/man/systemd.socket.xml index 60ea63f742a..46a2dbc7edf 100644 --- a/man/systemd.socket.xml +++ b/man/systemd.socket.xml @@ -709,6 +709,15 @@ Defaults to . + + PassPacketInfo= + Takes a boolean value. This controls the IP_PKTINFO, + IPV6_RECVPKTINFO and NETLINK_PKTINFO socket options, which + enable reception of additional per-packet metadata as ancillary message, on + AF_INET, AF_INET6 and AF_UNIX sockets. + Defaults to . + + TCPCongestion= Takes a string value. Controls the TCP diff --git a/src/core/dbus-socket.c b/src/core/dbus-socket.c index ad7b41a95b2..73e6a749147 100644 --- a/src/core/dbus-socket.c +++ b/src/core/dbus-socket.c @@ -104,6 +104,7 @@ const sd_bus_vtable bus_socket_vtable[] = { SD_BUS_PROPERTY("Broadcast", "b", bus_property_get_bool, offsetof(Socket, broadcast), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("PassCredentials", "b", bus_property_get_bool, offsetof(Socket, pass_cred), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("PassSecurity", "b", bus_property_get_bool, offsetof(Socket, pass_sec), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("PassPacketInfo", "b", bus_property_get_bool, offsetof(Socket, pass_pktinfo), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("RemoveOnStop", "b", bus_property_get_bool, offsetof(Socket, remove_on_stop), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("Listen", "a(ss)", property_get_listen, 0, SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("Symlinks", "as", NULL, offsetof(Socket, symlinks), SD_BUS_VTABLE_PROPERTY_CONST), @@ -202,6 +203,9 @@ static int bus_socket_set_transient_property( if (streq(name, "PassSecurity")) return bus_set_transient_bool(u, name, &s->pass_sec, message, flags, error); + if (streq(name, "PassPacketInfo")) + return bus_set_transient_bool(u, name, &s->pass_pktinfo, message, flags, error); + if (streq(name, "ReusePort")) return bus_set_transient_bool(u, name, &s->reuse_port, message, flags, error); diff --git a/src/core/load-fragment-gperf.gperf.m4 b/src/core/load-fragment-gperf.gperf.m4 index 5fd58b379ba..c76d08b3a6d 100644 --- a/src/core/load-fragment-gperf.gperf.m4 +++ b/src/core/load-fragment-gperf.gperf.m4 @@ -396,6 +396,7 @@ Socket.Transparent, config_parse_bool, 0, Socket.Broadcast, config_parse_bool, 0, offsetof(Socket, broadcast) Socket.PassCredentials, config_parse_bool, 0, offsetof(Socket, pass_cred) Socket.PassSecurity, config_parse_bool, 0, offsetof(Socket, pass_sec) +Socket.PassPacketInfo, config_parse_bool, 0, offsetof(Socket, pass_pktinfo) Socket.TCPCongestion, config_parse_string, 0, offsetof(Socket, tcp_congestion) Socket.ReusePort, config_parse_bool, 0, offsetof(Socket, reuse_port) Socket.MessageQueueMaxMessages, config_parse_long, 0, offsetof(Socket, mq_maxmsg) diff --git a/src/core/socket.c b/src/core/socket.c index 218b4b245df..359683a4261 100644 --- a/src/core/socket.c +++ b/src/core/socket.c @@ -635,6 +635,7 @@ static void socket_dump(Unit *u, FILE *f, const char *prefix) { "%sBroadcast: %s\n" "%sPassCredentials: %s\n" "%sPassSecurity: %s\n" + "%sPassPacketInfo: %s\n" "%sTCPCongestion: %s\n" "%sRemoveOnStop: %s\n" "%sWritable: %s\n" @@ -654,6 +655,7 @@ static void socket_dump(Unit *u, FILE *f, const char *prefix) { prefix, yes_no(s->broadcast), prefix, yes_no(s->pass_cred), prefix, yes_no(s->pass_sec), + prefix, yes_no(s->pass_pktinfo), prefix, strna(s->tcp_congestion), prefix, yes_no(s->remove_on_stop), prefix, yes_no(s->writable), @@ -1070,6 +1072,12 @@ static void socket_apply_socket_options(Socket *s, int fd) { log_unit_warning_errno(UNIT(s), r, "SO_PASSSEC failed: %m"); } + if (s->pass_pktinfo) { + r = socket_pass_pktinfo(fd, true); + if (r < 0) + log_unit_warning_errno(UNIT(s), r, "Failed to enable packet info socket option: %m"); + } + if (s->priority >= 0) { r = setsockopt_int(fd, SOL_SOCKET, SO_PRIORITY, s->priority); if (r < 0) diff --git a/src/core/socket.h b/src/core/socket.h index 9e0be15ba8d..482e45fce74 100644 --- a/src/core/socket.h +++ b/src/core/socket.h @@ -121,6 +121,7 @@ struct Socket { bool broadcast; bool pass_cred; bool pass_sec; + bool pass_pktinfo; /* Only for INET6 sockets: issue IPV6_V6ONLY sockopt */ SocketAddressBindIPv6Only bind_ipv6_only; diff --git a/src/shared/bus-unit-util.c b/src/shared/bus-unit-util.c index 3be75e6b4d2..9a5730f3eae 100644 --- a/src/shared/bus-unit-util.c +++ b/src/shared/bus-unit-util.c @@ -1632,6 +1632,7 @@ static int bus_append_socket_property(sd_bus_message *m, const char *field, cons "Broadcast", "PassCredentials", "PassSecurity", + "PassPacketInfo", "ReusePort", "RemoveOnStop", "SELinuxContextFromNet")) diff --git a/test/fuzz/fuzz-unit-file/directives.service b/test/fuzz/fuzz-unit-file/directives.service index 048bd34e9e2..7435d7abec0 100644 --- a/test/fuzz/fuzz-unit-file/directives.service +++ b/test/fuzz/fuzz-unit-file/directives.service @@ -164,6 +164,7 @@ PIDFile= PartOf= PassCredentials= PassSecurity= +PassPacketInfo= PathChanged= PathExists= PathExistsGlob= From 43007b302efae90897b62095a6995f43c60c1ff1 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 27 May 2020 19:37:19 +0200 Subject: [PATCH 3/4] networkd: clean up NETLINK_PKTINFO vs. SO_PASSCRED confusion We actually care for NETLINK_PKTINFO, not for SO_PASSCRED, hence when allocating the netlink socket, configure things accordingly. Tracked down by Benjamin Robin, see: https://github.com/systemd/systemd/pull/15571#issuecomment-633213747 --- src/libsystemd/sd-netlink/netlink-socket.c | 6 +----- units/systemd-networkd.socket | 2 +- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/src/libsystemd/sd-netlink/netlink-socket.c b/src/libsystemd/sd-netlink/netlink-socket.c index 71b3d1e2f1f..bcd82fe1646 100644 --- a/src/libsystemd/sd-netlink/netlink-socket.c +++ b/src/libsystemd/sd-netlink/netlink-socket.c @@ -16,10 +16,6 @@ #include "socket-util.h" #include "util.h" -/* For some reason we need some extra cmsg space on some kernels. It's not clear why, and one of those days - * we need to track this down. See: https://github.com/systemd/systemd/pull/15457 */ -#define EXTRA_CMSG_SPACE 1024 - int socket_open(int family) { int fd; @@ -244,7 +240,7 @@ int socket_write_message(sd_netlink *nl, sd_netlink_message *m) { static int socket_recv_message(int fd, struct iovec *iov, uint32_t *ret_mcast_group, bool peek) { union sockaddr_union sender; - CMSG_BUFFER_TYPE(CMSG_SPACE(sizeof(struct nl_pktinfo)) + EXTRA_CMSG_SPACE) control; + CMSG_BUFFER_TYPE(CMSG_SPACE(sizeof(struct nl_pktinfo))) control; struct msghdr msg = { .msg_iov = iov, .msg_iovlen = 1, diff --git a/units/systemd-networkd.socket b/units/systemd-networkd.socket index 445193e8d34..bc049e5ade9 100644 --- a/units/systemd-networkd.socket +++ b/units/systemd-networkd.socket @@ -17,7 +17,7 @@ Before=sockets.target [Socket] ReceiveBuffer=128M ListenNetlink=route 1361 -PassCredentials=yes +PassPacketInfo=yes [Install] WantedBy=sockets.target From 08ab18618ec59022582f1513c0718ba369f5ba85 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 27 May 2020 19:38:38 +0200 Subject: [PATCH 4/4] resolved: tweak cmsg calculation We ask for the TTL, then have enough space for it. We probably can drop the extra cmsg space now, but let's figure that out another time, since the extra cmsg space is used elsewhere in resolved as well. --- src/resolve/resolved-dns-stream.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/resolve/resolved-dns-stream.c b/src/resolve/resolved-dns-stream.c index bbaffc165ac..1e2ff05c3e5 100644 --- a/src/resolve/resolved-dns-stream.c +++ b/src/resolve/resolved-dns-stream.c @@ -88,6 +88,7 @@ static int dns_stream_complete(DnsStream *s, int error) { static int dns_stream_identify(DnsStream *s) { CMSG_BUFFER_TYPE(CMSG_SPACE(MAXSIZE(struct in_pktinfo, struct in6_pktinfo)) + + CMSG_SPACE(int) + /* for the TTL */ + EXTRA_CMSG_SPACE /* kernel appears to require extra space */) control; struct msghdr mh = {}; struct cmsghdr *cmsg;