Description
Version
v17.3.1
Platform
Linux darkk-ya-laptop 4.4.0-210-generic #242-Ubuntu SMP Fri Apr 16 09:57:56 UTC 2021 x86_64 x86_64 x86_64 GNU/Linux
Subsystem
dgram
What steps will reproduce the bug?
Use the following four files to build the test-case:
dgram-udp6-address.js
:
'use strict';
const dgram = require('dgram');
const socket = dgram.createSocket({ type: 'udp6' });
const discard_port = 9;
const global_ipv6 = '2600::';
// It might be rejected if there is no route to the ip (e.g. IPv4-only network).
socket.connect(discard_port, global_ipv6, err => {
if (err === undefined) {
console.log('remoteAddress: ', socket.remoteAddress());
// The next line triggers assertion under certain conditions:
// node[631]: ../src/tcp_wrap.cc:354:v8::Local<v8::Object> node::AddressToJS(node::Environment*, const sockaddr*, v8::Local<v8::Object>): Assertion `(r) == (0)' failed.
console.log('address: ', socket.address());
} else {
console.log('UDP connection error', err);
}
socket.unref();
});
Dockerfile
:
FROM node:17-bullseye
RUN set -ex \
&& apt-get update \
&& apt-get install -y --no-install-recommends iproute2 \
&& :
COPY --chown=0:0 \
dgram-udp6-address.js \
test.sh \
/
test.sh
:
#!/bin/bash
set -ex
ip link add dummy0 type dummy
ip link set dummy0 up
ip -6 address add fe80::aaaa:bbbb:cccc:dddd dev dummy0
ip -6 route add default dev dummy0
ip addr
ip -6 route
node --version
node /dgram-udp6-address.js
run.sh
:
#!/bin/bash
set -ex
tar cz Dockerfile dgram-udp6-address.js test.sh | docker build -t dgram-udp6-address:latest -
exec docker run --rm --tty -i \
--privileged \
--net=none \
--sysctl net.ipv6.conf.all.disable_ipv6=0 \
dgram-udp6-address:latest \
/bin/bash /test.sh
The test-case is run with ./run.sh
.
How often does it reproduce? Is there a required condition?
It's 100% reproducible with this network set-up.
This network setup simulates the default setup of Rostelecom ISP in St. Petersburg regarding their handling of IPv6 as seen by my Ubuntu 16.04 laptop:
- the ISP-provided router announces a default gateway via link-local address
fe80::1
- local machines get link-local address
- no real IPv6 connectivity is provided
- the router responds with
ICMP6, destination unreachable, unreachable route
to IPv6 packets with global destination
What is the expected behavior?
node
should not crash whole app. It should rather be some kind of exception, socket error or something like that.
I've noticed the behavior while developing Electron app, whole app was terminated on socket.address()
call.
What do you see instead?
...
+ node /dgram-udp6-address.js
remoteAddress: { address: '2600::', family: 'IPv6', port: 9 }
node[15]: ../src/tcp_wrap.cc:372:v8::Local<v8::Object> node::AddressToJS(node::Environment*, const sockaddr*, v8::Local<v8::Object>): Assertion `(r) == (0)' failed.
1: 0xb2c330 node::Abort() [node]
2: 0xb2c3ae [node]
3: 0xc1da97 node::AddressToJS(node::Environment*, sockaddr const*, v8::Local<v8::Object>) [node]
4: 0xc2f2ad void node::GetSockOrPeerName<node::UDPWrap, &uv_udp_getsockname>(v8::FunctionCallbackInfo<v8::Value> const&) [node]
5: 0xd798de [node]
6: 0xd7acff v8::internal::Builtin_HandleApiCall(int, unsigned long*, v8::internal::Isolate*) [node]
7: 0x162fff9 [node]
/test.sh: line 12: 15 Aborted (core dumped) node /dgram-udp6-address.js
Additional information
Other affected versions are v12.22.8, v14.18.2, v16.13.1
Relevant strace
snippet is:
socket(AF_INET6, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, IPPROTO_IP) = 17
bind(17, {sa_family=AF_INET6, sin6_port=htons(0), sin6_flowinfo=htonl(0), inet_pton(AF_INET6, "::", &sin6_addr), sin6_scope_id=0}, 28) = 0
connect(17, {sa_family=AF_INET6, sin6_port=htons(9), sin6_flowinfo=htonl(0), inet_pton(AF_INET6, "2600::", &sin6_addr), sin6_scope_id=0}, 28) = 0
getpeername(17, {sa_family=AF_INET6, sin6_port=htons(9), sin6_flowinfo=htonl(0), inet_pton(AF_INET6, "2600::", &sin6_addr), sin6_scope_id=0}, [128->28]) = 0
remoteAddress: { address: '2600::', family: 'IPv6', port: 9 }
getsockname(17, {sa_family=AF_INET6, sin6_port=htons(44890), sin6_flowinfo=htonl(0), inet_pton(AF_INET6, "fe80::aaaa:bbbb:cccc:dddd", &sin6_addr), sin6_scope_id=0}, [128->28]) = 0
access("/proc/net", R_OK) = 0
access("/proc/net/unix", R_OK) = 0
socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0) = 20
ioctl(20, SIOCGIFNAME, {ifr_index=0}) = -1 ENODEV (No such device)
close(20) = 0
getpid() = 18
node[18]: ../src/tcp_wrap.cc:372:v8::Local<v8::Object> node::AddressToJS(node::Environment*, const sockaddr*, v8::Local<v8::Object>): Assertion `(r) == (0)' failed.
So, the kernel returns sin6_flowinfo=htonl(0)
for the bound socket, so the assertion is false.
#39143 seems to be a similar issue on AIX.