On 2022/03/09 22:18, Volker Schlecht wrote:
> 
> 
> On 3/9/22 15:57, Stuart Henderson wrote:
> > On 2022/02/10 21:18, Volker Schlecht wrote:
> > > I integrated the patch for src/env.cc, dropped one for the bundled uv and
> > > upgraded to 12.22.10 ... what do you think?
> > 
> > Sorry it took a while to test this. I would like to get this in but it's
> > not working properly for me, sockets now only listen to IPv6 by default,
> > presumably from the change to the non-bundled libuv.
> 
> Possibly ... node-12.x is bundling libuv 1.40 with a cherrypicked fix from
> 1.41.1.  To me it's not apparent how the changes between libuv 1.40 and 1.42
> in libuv/src/unix/tcp.c could have changed that behavior, but that doesn't
> say much.

I think it's not the changes between 1.40 and 1.42 but the patch to
libuv in the old version of node port;

https://github.com/openbsd/ports/commit/accca92a9a3ad9fdb88817c0f255d0427506ba92#diff-4e78763888c6b266a50ff1c4055577b88e715f00937d3bfc033cce7288f041ea

This patch is bogus. It tries to setsockopt IPV6_V6ONLY, which fails on
OpenBSD, so node's v6 bind fails and it falls back to the v4 bind.
The code in libuv wraps that in ifndef OpenBSD, so the standalone libuv
doesn't try to call this.

i.e. it had the effect of disabling the v6 for "any address" binds, but
indirectly.

 71011 node     CALL  
socket(AF_INET6,0xc001<SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK>,0)
 71011 node     RET   socket 22/0x16
 71011 node     CALL  kbind(0x7f7fffff89a8,24,0xd92d1552916ba653)
 71011 node     RET   kbind 0
 71011 node     CALL  setsockopt(22,SOL_SOCKET,SO_REUSEADDR,0x7f7fffff8a7c,4)
 71011 node     RET   setsockopt 0
 71011 node     CALL  setsockopt(22,41<ipv6>,27,0x7f7fffff8a7c,4)
 71011 node     RET   setsockopt -1 errno 22 Invalid argument
 71011 node     CALL  close(22)
 71011 node     RET   close 0
 71011 node     CALL  
socket(AF_INET,0xc001<SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK>,0)
 71011 node     RET   socket 22/0x16
 71011 node     CALL  setsockopt(22,SOL_SOCKET,SO_REUSEADDR,0x7f7fffff8a8c,4)
 71011 node     RET   setsockopt 0
 71011 node     CALL  kbind(0x7f7fffff89b8,24,0xd92d1552916ba653)
 71011 node     RET   kbind 0
 71011 node     CALL  bind(22,0x7f7fffff8ef0,16)
 71011 node     STRU  struct sockaddr { AF_INET, 0.0.0.0:8000 }
 71011 node     RET   bind 0


> I don't know which node code you're running there, but
> 
> https://github.com/nodejs/node/blob/v12.x/doc/api/net.md
> 
> "If host is omitted, the server will accept connections on the unspecified
> IPv6 address (::) when IPv6 is available, or the unspecified IPv4 address
> (0.0.0.0) otherwise.
> 
> In most operating systems, listening to the unspecified IPv6 address (::)
> may cause the net.Server to also listen on the unspecified IPv4 address
> (0.0.0.0)."
> 
> Any chance that the code you're running is banking on the behavior of an
> operating system with dual stack sockets?

I think it's likely that nearly all code trying to create a network
listener will bank on this.

The specific code I'm using that I thought was only working on 12 is
node-mjpeg-proxy. But I didn't figure out the v6 issue at that point
(and missed it in fstat output).

Later I tried updating my box running postcodes.io to -current (moving
from node 12->16 again) and that wasn't working either, but now I did
spot that it was listening on v6.

Going back to the initial box I tried again and yes that was the same
problem with v6. In that case it's easy enough to change the bind address
as it needs a self-written express-app.js with a listen command which is
easy enough to modify (assuming that the problem is known). Doing that
and it works ok with updated node.

So (as of today) I don't need to keep 12 for this any more, and nobody
else mentioned a need for it, so let's drop my idea of a separate port for
12 unless we run into something else.

postcodes.io is trickier, it is presented as more of a complete package
and config is expected to be done via an .env file which doesn't allow
setting a bind address. Obviously patchable but it makes things much more
of a pain.

> When I explicitly pass an ipv4 host, I get a server listening on ipv4
> 
> net.createServer(c=>console.log).listen(5556,'0.0.0.0')
> 
> However
> 
> net.createServer(c=>console.log).listen(5556)
> or
> net.createServer(c=>console.log).listen(5555,'::')
> 
> both listen on ipv6 only. Which is in line with the node documentation, and
> which is what I would have expected on OpenBSD ...(?)

Really the expectation is that by default software either listens on
v4+v6 or only on IPv4. v6-only is a niche use csae.

Because OpenBSD has the no-v4-on-v6-sockets thing, for software that
listens only to a single v6 socket by default, we would usually patch
it to use v4. I think we should probably do this for node too, taking
it back to the runtime behaviour of the old port for 12.x, but make it
explicit rather than via a side-effect.

I tried patching the only likely-looking place I could find (diff
below) but it doesn't seem to be working for me though...not sure why..



Index: Makefile
===================================================================
RCS file: /cvs/ports/lang/node/Makefile,v
retrieving revision 1.97
diff -u -p -r1.97 Makefile
--- Makefile    16 Feb 2022 14:24:37 -0000      1.97
+++ Makefile    10 Mar 2022 12:33:32 -0000
@@ -8,6 +8,7 @@ USE_WXNEEDED =          Yes
 COMMENT = JavaScript runtime built on Chrome's V8 JavaScript engine
 
 NODE_VERSION =         v16.14.0
+REVISION =             0
 PLEDGE_VER =           1.1.2
 DISTFILES =            node-pledge-{}${PLEDGE_VER}.tar.gz:0 \
                        ${DISTNAME}-headers.tar.gz \
Index: patches/patch-lib_net_js
===================================================================
RCS file: patches/patch-lib_net_js
diff -N patches/patch-lib_net_js
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ patches/patch-lib_net_js    10 Mar 2022 12:33:32 -0000
@@ -0,0 +1,30 @@
+- If an address is not specified, for the "any address" bind,
+node was trying to bind to v6 out of preference and dropping back
+to v4 if that fails.
+
+OpenBSD doesn't permit v4 connections to sockets bound to a v6
+address, change to binding to v4 for "any address" so this is a
+better match for typical expectations.
+
+(Ideally it would create two separate binds to 0.0.0.0 and :: for
+an "any address").
+
+
+Index: lib/net.js
+--- lib/net.js.orig
++++ lib/net.js
+@@ -1258,13 +1258,7 @@ function createServerHandle(address, port, addressType
+   if (address || port || isTCP) {
+     debug('bind to', address || 'any');
+     if (!address) {
+-      // Try binding to ipv6 first
+-      err = handle.bind6(DEFAULT_IPV6_ADDR, port, flags);
+-      if (err) {
+-        handle.close();
+-        // Fallback to ipv4
+-        return createServerHandle(DEFAULT_IPV4_ADDR, port);
+-      }
++      return createServerHandle(DEFAULT_IPV4_ADDR, port);
+     } else if (addressType === 6) {
+       err = handle.bind6(address, port, flags);
+     } else {

Reply via email to