Skip to content

LISTEN * for listening with upsd on "any address" does not work with both IPv4 and IPv6 #2012

@jimklimov

Description

@jimklimov

On a Linux system set up with both IPv4 and IPv6, I've used LISTEN * assuming it would mean any address. This has in fact only added a listener on IPv4 0.0.0.0 but did not add any IPv6 capability.

After some reading in https://stackoverflow.com/questions/27480094/ipv6-is-equivalent-to-0-0-0-0-when-listening-for-connections I've also checked that it works to use LISTEN 0.0.0.0 and LISTEN my.host.name (including an IPv6 setup when the hostname points to such address).

Finally, checked that for "any" address I can LISTEN :: or LISTEN ::0 which however disables the IPv4 listener at least on this system where IPv4-over-IPv6 is supported (what that SO discussion refers to as "a dual-stack listener bound to INADDR6_ANY", probably).

WARNING: Note that depending on line order, this can remove IPv6 support even though it is in config file; and even more confusingly the LAST active config line wins the race:

:; cat upsd.conf
DEBUG_MIN 6
LISTEN *
LISTEN ::

:; journalctl -flu nut-server
Aug 05 12:57:27 pve nut-server[2856573]:    0.000170        [D1] debug level is '6'
Aug 05 12:57:27 pve nut-server[2856573]:    0.000179        [D3] setuptcp: try to bind to :: port 3493
Aug 05 12:57:27 pve nut-server[2856573]:    0.000193        listening on :: port 3493
Aug 05 12:57:27 pve nut-server[2856573]:    0.000197        [D3] setuptcp: try to bind to * port 3493
Aug 05 12:57:27 pve nut-server[2856573]:    0.000263        [D3] setuptcp: bind: Address already in use
Aug 05 12:57:27 pve nut-server[2856573]:    0.000273        [D3] setuptcp: bind: Address already in use
Aug 05 12:57:27 pve nut-server[2856573]:    0.000278        not listening on * port 3493
...
Aug 05 12:57:27 pve systemd[1]: Started Network UPS Tools - power devices information server.
Aug 05 12:57:32 pve nut-server[2856573]: User upsmon@::ffff:127.0.0.1 logged into UPS [myups]

:; netstat -anp | grep 3493
tcp        0      0 127.0.0.1:38304         127.0.0.1:3493          ESTABLISHED 2790659/upsmon
tcp6       0      0 :::3493                 :::*                    LISTEN      2856573/upsd
tcp6       0      0 127.0.0.1:3493          127.0.0.1:38304         ESTABLISHED 2856573/upsd

vs.

:; cat upsd.conf
DEBUG_MIN 6
LISTEN ::
LISTEN *

:; journalctl -flu nut-server
Aug 05 13:07:54 pve nut-server[2875736]:    0.000293        [D1] debug level is '6'
Aug 05 13:07:54 pve nut-server[2875736]:    0.000313        [D3] setuptcp: try to bind to * port 3493
Aug 05 13:07:54 pve nut-server[2875736]:    0.000430        listening on * port 3493
Aug 05 13:07:54 pve nut-server[2875736]:    0.000444        [D3] setuptcp: try to bind to :: port 3493
Aug 05 13:07:54 pve nut-server[2875736]:    0.000463        [D3] setuptcp: bind: Address already in use
Aug 05 13:07:54 pve nut-server[2875736]:    0.000478        not listening on :: port 3493
...
Aug 05 13:07:54 pve systemd[1]: Started Network UPS Tools - power devices information server.
Aug 05 13:08:02 pve nut-server[2875736]: User upsmon@127.0.0.1 logged into UPS [myups]

### Note there is no IPv6 listener
:; netstat -anp | grep 3493
tcp        0      0 0.0.0.0:3493            0.0.0.0:*               LISTEN      2875736/upsd
tcp        0      0 127.0.0.1:55644         127.0.0.1:3493          ESTABLISHED 2790659/upsmon
tcp        0      0 127.0.0.1:3493          127.0.0.1:55644         ESTABLISHED 2875736/upsd

Note that it DOES work to specify two non-conflicting addresses, e.g. any for IPv4 and exact addr/hostname for IPv4:

:; journalctl -flu nut-server
Aug 05 13:02:10 pve nut-server[2868613]: listening on my.host.name port 3493
Aug 05 13:02:10 pve nut-server[2868613]: listening on * port 3493
...
Aug 05 13:02:17 pve nut-server[2868613]: User upsmon@127.0.0.1 logged into UPS [myups]

:; netstat -anp | grep 3493
tcp        0      0 0.0.0.0:3493            0.0.0.0:*               LISTEN      2868613/upsd
tcp        0      0 127.0.0.1:3493          127.0.0.1:34290         ESTABLISHED 2868613/upsd
tcp        0      0 127.0.0.1:34290         127.0.0.1:3493          ESTABLISHED 2790659/upsmon
tcp6       0      0 1234:1234:1234:a00:3493 :::*                    LISTEN      2868613/upsd

Currently I do not see any hints about :: or ::0 in such role in the NUT docs, and I think that at least a few docs lines should be added, and maybe the LISTEN * activity (re-)defined to support actually all addresses according to currently handled address families.

:; git grep LISTEN | grep ::
conf/upsd.conf.sample:# LISTEN ::1 3493
docs/config-notes.txt:  LISTEN ::1 3493
docs/man/upsd.conf.txt:"LISTEN 'interface' 'port'"::
docs/man/upsd.conf.txt:127.0.0.1 if no LISTEN addresses are specified (and ::1 if IPv6 support is
docs/man/upsd.conf.txt: LISTEN ::1
docs/security.txt:`127.0.0.1` if no LISTEN addresses are specified (and `::1` if IPv6 support is
docs/security.txt:         LISTEN ::1
scripts/augeas/nutupsdconf.aug.in: *    LISTEN 127.0.0.1 LISTEN 192.168.50.1 LISTEN ::1 LISTEN 2001:0db8:1234:08d3:1319:8a2e:0370:7344

For that matter, use of asterisk is also not specifically documented:

:; git grep LISTEN | grep '*'
scripts/augeas/nutupsdconf.aug.in: * LISTEN interface port
scripts/augeas/nutupsdconf.aug.in: *    Multiple LISTEN addresses may be specified. The default is to bind to 0.0.0.0 if no LISTEN addresses are specified.
scripts/augeas/nutupsdconf.aug.in: *    LISTEN 127.0.0.1 LISTEN 192.168.50.1 LISTEN ::1 LISTEN 2001:0db8:1234:08d3:1319:8a2e:0370:7344
server/conf.c:  /* LISTEN <address> [<port>] */
server/upsd.c:   * no other valid LISTEN interface */
server/upsd.c:  /* default behaviour if no LISTEN addres has been specified */
server/upsd.c:  /* check if we have at least 1 valid LISTEN interface */

The "any" names involved are not locally resolvable (I wondered if this could be why NUT only bound to IPv4 0.0.0.0):

:; getent hosts '0.0.0.0'
:; getent hosts '*'
:; getent hosts '::'
:; getent hosts '::0'

# IPv6 loopback for example IS resolvable:
:; getent hosts '::1'
::1             ip6-localhost ip6-loopback

CC @clepple @aquette : am I missing anything here? Does anything (older documented behaviors, least-surprise principle) preclude from just declaring and implementing a definitive behavior for LISTEN * lines?

Are there known systems where listening on both IPv4 0.0.0.0 and the "specifically unspecified" IPv6 address 0:0:0:0:0:0:0:0 a.k.a. :: is possible?

Is there some programmatic way (portable, or several for different OSes) to check for dual-stack support (e.g. to "know" we can march ahead grabbing :: or ::0 and it will handle IPv4 too... or just handle * by trying to take these two in this order)?

Metadata

Metadata

Labels

documentationenhancementservice/daemon start/stopGeneral subject for starting and stopping NUT daemons (drivers, server, monitor); also BG/FG/Debug

Type

No type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions