Summary: | RFE: core: we should have a way to make failed listening on specific ports in .socket non-fatal, via a syntax of ListenStream=-[::]:4711 | ||
---|---|---|---|
Product: | systemd | Reporter: | Didier 'OdyX' Raboud <odyx> |
Component: | general | Assignee: | systemd-bugs |
Status: | NEW --- | QA Contact: | systemd-bugs |
Severity: | normal | ||
Priority: | medium | CC: | felix+freedesktop |
Version: | unspecified | ||
Hardware: | Other | ||
OS: | Linux (All) | ||
Whiteboard: | |||
i915 platform: | i915 features: |
Description
Didier 'OdyX' Raboud
2014-10-02 16:23:31 UTC
Sorry, but I cannot parse what yuou are actually trying to do? Can you precisely describe what you want to do, and what exactly doesn't work? (For clarity, I'm the current CUPS maintainer for Debian). Let me try to rephrase then: CUPS got patched in Debian using a variation of your patch [0] to support socket activation. I'm trying to find a socket configuration that enables CUPS to be activated on both ipv6-enabled and ipv4-only hosts on all local IPs (that's the subject of https://bugs.debian.org/747073), as well as on all public-facing IPs Now, with the following unit file: ListenStream=631 BindIPv6Only=both … on ipv6-enabled hosts, this will let CUPS be activated when accessing http://[::1]:631/, http://localhost:631/ or http://127.0.0.1:631/. In the two latter cases though, CUPS will not allow the connection (with 'Bad Request' and 'Forbidden' respectively) with messages like these in the error_log (debug2 level): Accepted from [v1.::127.0.0.1]:631 (IPv6) Request from "[v1.::127.0.0.1]" using invalid Host: field "localhost:631" cupsdIsAuthorized: auth=CUPSD_AUTH_DENY... With BindIPv6Only=ipv6-only, CUPS will not get activated on localhost or 127.0.0.1, of course. On ipv4-only hosts, BindIPv6Only will get discarded and CUPS will get activated _and_ accept the connections on localhost or 127.0.0.1 with "Accepted from 127.0.0.1:631 (IPv4). Now, as I understand it, on ipv6-enabled hosts, systemd will only create IPv6 (AF_INET6 ?) sockets, even on IPv4 addresses, which then causes confusion on the CUPS side (hence the funny [v1.::127.0.0.1] pseudo-IPv6 address coming from httpAddrString [1]), which doesn't expect IPv4 addresses over AF_INET6 (see the https://www.cups.org/str.php?L4491 ), thereby refusing the connection. Now, a way around is to specify specifically ListenStream=127.0.0.1:631, but then adding ListenStream=[::1]:631, which will (of course) fail the unit activation on ipv4-only hosts. There doesn't seem to have a way to ask systemd to bind the socket if the address exists. So, if I understand it correctly, I think either systemd is wrong to bind sockets on IPv4 addresses with AF_INET6 and handing IPv4 addresses to CUPS or CUPS is wrong when checking the address over AF_INET6 sockets. The CUPS upstream author seems to think the problem is in systemd (see the CUPS bug linked above). (By the way, this is nowhere near my expertise field, so feel free to correct any of my misconceptions…) Opinions ? [0] http://sources.debian.net/src/cups/1.7.5-4/debian/patches/systemd-optional-socket-activation.patch [1] http://sources.debian.net/src/cups/1.7.5-4/cups/http-addr.c/#L403 Friendly ping? Did my explanation make any sense? I'm not aware of it being possible to do what you're requesting with a single bind (that is, resulting in a single socket file descriptor). I believe you need two different binds, and systemd socket units support that if you're prepared to get both fd=3 and fd=4. systemd is simply doing the best it can through one bind. So, systemd currently doesn't support this scheme nicely. We should however. The ipv6only compat stuff is you really should set to "on" for cups. CUPS appears to require that, and that's probably a really good idea for it. Now, to achieve what you want, you should use: ListenStream=0.0.0.0:631 ListenStream=[::]:631 both lines listed in the same .socket file. The first line will listen on the IPv4 port 631 on all interfaces, the second line on the IPv6 port 631. Now, there's one problem with this: the latter line will cause the .socket unit to fail on kernels where ipv6 is not compiled in. The question now is what to do about this. We have two options: 1) introduce a syntax "ListenStream=-[::]:631" (i.e. note the "-"), which would tell systemd that failure to listen on that port shall not be considered fatal. This would then be similar to our "ExectStart=-/bin/false" syntax, where the dash encodes that the exit cause for the process shall be ignored. 2) change the logic of .socket units to succeed if we managed to listen on at least *one* of all of its specified ports. Currently we fail if at least one listening fails, and we'd turn this around so that we'd succeed if at least one listening succeeds. I think option #1 is preferable here though, simply because we normally should guarantee stability of the order of fds we pass to the processes we invoke. By specifying the dash, the user tells us that it is OK if an fd might be missing when passed to the process. But just doing that by default sounds really ill advised. Does that make sense? Renaming the bug accordingly. It does very much, thanks! I had come to the same conclusion earlier this year: https://bugs.debian.org/747073#44 . I see this feature as blocking the proper socket-activation of CUPS, which I will then disable for the next Debian release, unless this gets into systemd fast enough. :) |
Use of freedesktop.org services, including Bugzilla, is subject to our Code of Conduct. How we collect and use information is described in our Privacy Policy.