Skip to content

Conversation

@mkovatsc
Copy link
Contributor

@mkovatsc mkovatsc commented Oct 31, 2025

When starting a servient with a new CoapServer(), it only binds to IPv4 addresses. At least my expectation is that the CoAP server should bind to all addresses of a host when no specific address is given. Hence, I consider this a bug.

This is just a strawman hotfix to start the work on fixing IPv6 support for the CoAP server.

When no address is given to NodeJS dgram, it only binds to the IPv4 wildcard address (0.0.0.0), but not IPv6 even when the host has it enabled. There might be an implicit default for the type being set to udp4.

When passing the IPv6 wildcard address :: to sockets, the expectation is that it binds to both IPv6 and IPv4 addresses (i.e., dual-stack). This can be reconfigured at least under Linux with the net.ipv6.bindv6only sysctl parameter, but then the hosts expectation is that the default wildcard means only :: without 0.0.0.0. It might still confuse node-wot users who are not aware of net.ipv6.bindv6only.

Please investigate and test this further, as I did not test this on IPv4-only machines. It might directly fail there and might need more code to detect IPv6 support on the host before defaulting to ::.

Overall, the issue is with dgram, whose dual-stack capabilities are quite broken by requiring a decision on udp4 vs upd6 upfront.

This is just a strawman hotfix to start the work on fixing IPv6 support for the CoAP server. Untested on IPv4-only machines and not considering the `net.ipv6.bindv6only` sysctl parameter (depends on the expectation of the user).
@mkovatsc mkovatsc requested a review from JKRhb as a code owner October 31, 2025 11:32
@mkovatsc mkovatsc added bug Something isn't working binding-coap Issues related to coap protocol binding need-investigation labels Oct 31, 2025
@JKRhb
Copy link
Member

JKRhb commented Oct 31, 2025

Thank you, @mkovatsc, for providing this hotfix! I guess the test needs to be adjusted as well to respect the changes?

Thank you also for opening #1454 – it is a bit sad that this is such a fundamental issue, also considering that UDP does not get a lot of attention in the JS world in general :/

@mkovatsc
Copy link
Contributor Author

While working on the README revision, I noticed that the issue only appeared on my Raspberry Pi with Linux 5.15.32-v7l+, which has neither ULA nor GUA IPv6 addresses, only the link-local ones. It seems that link-local addresses get filtered when no address is specified, while they are included when passing :: explicitly.

The original issue I encountered was that mDNS responds with only a AAAA including the link-local address, which is then used by the CoAP client to contact the Thing exposed on the RPi. So while the general expectation is that the Thing should be bound to link-local addresses, some component -- most likely dgram -- prevents that.

With servient.addServer(new CoapServer()):

$ netstat -tulpn | grep 5683
(Not all processes could be identified, non-owned process info
 will not be shown, you would have to be root to see it all.)
udp        0      0 0.0.0.0:5683            0.0.0.0:*                           11539/node

With servient.addServer(new CoapServer({ address: "::" })):

$ netstat -tulpn | grep 5683
(Not all processes could be identified, non-owned process info
 will not be shown, you would have to be root to see it all.)
udp6       0      0 :::5683                 :::*                                11474/node

Also coap-client(.exe) completes this time:

> coap-client -v 7 coap://unicorn-pi.local/.well-known/core
Oct 31 14:32:30.162 DEBG ***[fe80::5d1d:33c:b722:d279]:49904 <-> [fe80::dea6:32ff:fe3e:849e]:5683 UDP : session 0000020C83888910: created outgoing session
Oct 31 14:32:30.165 DEBG ***[fe80::5d1d:33c:b722:d279]:49904 <-> [fe80::dea6:32ff:fe3e:849e]:5683 UDP : session connected
Oct 31 14:32:30.165 DEBG timeout is set to 90 seconds
Oct 31 14:32:30.165 DEBG sending CoAP request:
Oct 31 14:32:30.165 DEBG *  [fe80::5d1d:33c:b722:d279]:49904 <-> [fe80::dea6:32ff:fe3e:849e]:5683 UDP : netif: sent   46 bytes
v:1 t:CON c:GET i:dbb3 {} [ Uri-Host:unicorn-pi.local, Uri-Path:.well-known, Uri-Path:core, Request-Tag:0xcc5edddf ]
Oct 31 14:32:30.167 DEBG ** [fe80::5d1d:33c:b722:d279]:49904 <-> [fe80::dea6:32ff:fe3e:849e]:5683 UDP : mid=0xdbb3: added to retransmit queue (2844ms)
Oct 31 14:32:30.177 DEBG *  [fe80::5d1d:33c:b722:d279]:49904 <-> [fe80::dea6:32ff:fe3e:849e]:5683 UDP : netif: recv   44 bytes
v:1 t:ACK c:2.05 i:dbb3 {} [ Content-Format:application/link-format ] :: '</unicorn>;rt="wot.thing";ct="50 432"'
Oct 31 14:32:30.177 DEBG ** [fe80::5d1d:33c:b722:d279]:49904 <-> [fe80::dea6:32ff:fe3e:849e]:5683 UDP : mid=0xdbb3: removed (1)
Oct 31 14:32:30.177 DEBG ** process incoming 2.05 response:
</unicorn>;rt="wot.thing";ct="50 432"Oct 31 14:32:30.177 DEBG ***[fe80::5d1d:33c:b722:d279]:49904 <-> [fe80::dea6:32ff:fe3e:849e]:5683 UDP : session 0000020C83888910: closed

This seems highly related to #362

@mkovatsc
Copy link
Contributor Author

mkovatsc commented Oct 31, 2025

When I added a manual IPv6 address to that RPi, that one gets listed in the TD, but it was still bound to 0.0.0.0 only:

    {
      href: 'coap://[fdc2:f1c8:d321:dfa0::2]:5683/unicorn/properties',
      contentType: 'application/cbor',
      op: [Array]
    }

Link-local addresses never get listed -- this should come from a filter in node-wot. It might make sense to suppress those, but if the device is reachable under a link-local address via DNS name, then the DNS name should be listed. To get the correct one highly depends on a proper host configuration, though, especially when mDNS is involved. os.hostname() + .local works if the system is set up correctly -- maybe add a check if there is an mDNS responder.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

binding-coap Issues related to coap protocol binding bug Something isn't working need-investigation

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants