Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

UDP/Datagram: Can't send messages while bind is done to 127.0.0.1 must bind to 0.0.0.0 #29047

Closed
assaf-xm opened this issue Aug 8, 2019 · 8 comments
Labels
dgram Issues and PRs related to the dgram subsystem / UDP. invalid Issues and PRs that are invalid.

Comments

@assaf-xm
Copy link

assaf-xm commented Aug 8, 2019

When using dgram for only sending UDP messages, upon the first send there is an automatic bind to 0.0.0.0

Trying to explicitly bind to 127.0.0.1 will cause send to fail with the error message:
Error: send EINVAL 111.111.111.111:11111
at SendWrap.afterSend [as oncomplete] (dgram.js:467:11)

Reproduction:

let PORT = 11111;
let HOST = '111.111.111.111';

let dgram = require('dgram');
let message = Buffer.from('Testing!');

let client = dgram.createSocket('udp4');
client.bind(0, '127.0.0.1'); /////////////////// remove this line for auto bind or change to 0.0.0.0 to be able to send

client.send(message, 0, message.length, PORT, HOST, function(err, bytes) {
if (err) throw err;
console.log('UDP message sent to ' + HOST +':'+ PORT);
client.close();
});

@sam-github
Copy link
Contributor

I assume you think there is a bug, but I'm not sure what it is. Could you elaborate?

That bind is implicitly done on first send is documented:

If the socket has not been previously bound with a call to bind, the socket is assigned a random port number and is bound to the "all interfaces" address ('0.0.0.0' for udp4 sockets, '::0' for udp6 sockets.)

@assaf-xm
Copy link
Author

assaf-xm commented Aug 8, 2019

While the bind on first send (if not already bounded) is documented, in case the dgram module is used only as a UDP client (outgoing messages only), opening a local port to 0.0.0.0 seems like a security issue.
Trying to reduce it and bind to 127.0.0.1 is limiting the outgoing UDP messages only to localhost, and this seems like a bug.

@bnoordhuis
Copy link
Member

opening a local port to 0.0.0.0 seems like a security issue

That's how UDP sockets work in general, it's not specific to Node.js. From http://man7.org/linux/man-pages/man7/udp.7.html:

   In order to receive packets, the socket can be bound to
   a local address first by using bind(2).  Otherwise, the socket layer
   will automatically assign a free local port out of the range defined
   by /proc/sys/net/ipv4/ip_local_port_range and bind the socket to
   INADDR_ANY.

Trying to reduce it and bind to 127.0.0.1 is limiting the outgoing UDP messages only to localhost, and this seems like a bug.

I don't follow that line of reasoning. You ask the operating system to restrict it to localhost and that's what it does.

Thanks for taking the time to open an issue but I'm closing this out as notabug.

@bnoordhuis bnoordhuis added dgram Issues and PRs related to the dgram subsystem / UDP. invalid Issues and PRs that are invalid. labels Aug 9, 2019
@assaf-xm
Copy link
Author

assaf-xm commented Aug 9, 2019

So in order to (only) send UDP packets to a remote machine, you have to open a random local port to listen to 0.0.0.0?
(for example with netcat this is not needed)

@bnoordhuis
Copy link
Member

netcat does the exact same thing. And actually it's not netcat doing that but the kernel.

Think about it: the UDP packet header requires a source address and port.

@assaf-xm
Copy link
Author

The source port on the UDP packet header is optional (see https://tools.ietf.org/html/rfc768):
"Source Port is an optional field, when meaningful, it indicates the port
of the sending process, and may be assumed to be the port to which a
reply should be addressed in the absence of any other information. If
not used, a value of zero is inserted."

I also don't think that the kernel does this bind, looking in uv/src/unix/udp.c:
'uv__udp_send' function specifically calls 'uv__udp_maybe_deferred_bind'. I wonder if this is mandatory?

@bnoordhuis
Copy link
Member

I linked you to the relevant man page. That rather closes the discussion, don't you think?

Yes, libuv does an explicit bind. If it didn't, the kernel would do it implicitly on libuv's behalf.

@assaf-xm
Copy link
Author

I agree, it looks like the bind will happen anyway.
Not sure if there is a difference if it's done implicitly or explicitly.

In any case, thank you for addressing this issue and the quick responses!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
dgram Issues and PRs related to the dgram subsystem / UDP. invalid Issues and PRs that are invalid.
Projects
None yet
Development

No branches or pull requests

3 participants