node-wot
node-wot copied to clipboard
Draft: CoAP server to include IPv6 when no address specified
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.
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 https://github.com/eclipse-thingweb/node-wot/issues/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 :/
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 https://github.com/eclipse-thingweb/node-wot/issues/362
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.