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

Get udp recipent IP for incoming packet #54483

Open
HuJK opened this issue Aug 21, 2024 · 0 comments
Open

Get udp recipent IP for incoming packet #54483

HuJK opened this issue Aug 21, 2024 · 0 comments
Labels
dgram Issues and PRs related to the dgram subsystem / UDP. feature request Issues that request new features to be added to Node.js.

Comments

@HuJK
Copy link

HuJK commented Aug 21, 2024

What is the problem this feature will solve?

It's impossible to serve a UDP based server with nodejs on multiple IP server.
A lot of cloud service provider or ISPs allowing us to purchase additional IP on it.

Assume I have a server with multiple IP on it.
In this case, I'm demo with 172.22.10.100 and 172.22.10.101
The 172.22.10.100 is marked as primary, and 172.22.10.101 is marked as secondary by kernel.

2: eth0@if141: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000
    link/ether 2e:98:22:63:a9:1c brd ff:ff:ff:ff:ff:ff link-netnsid 0
    inet 172.22.10.100/20 scope global eth0
       valid_lft forever preferred_lft forever
    inet 172.22.10.101/20 scope global secondary eth0
       valid_lft forever preferred_lft forever

This is a simple udp server, it replys "pong" message to every client.

var dgram = require('dgram');

var PORT = 55567;
var HOST = '0.0.0.0';

        // UDP Server
server = dgram.createSocket('udp4');

server.on('listening', function () {
    var address = this.address();
        console.log('UDP Server listening on ' + address.address + ":" + address.port);
    }.bind(server));

server.on('close', function() {
    console.log('udp socket closed..');
});

server.on('message', function (message, remote) {
    console.log('Data received from client : ' + message.toString());
    this.send(new Buffer("pong"), remote.port, remote.address, function(err, bytes) {
    if (err) throw err;
        console.log(`UDP message sent to ${remote.address}:${remote.port}`);
    });

}.bind(server));

server.bind(PORT, HOST);

If the client connect to 172.22.10.100.55567, it replies with src ip 172.22.10.100.55567

tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on any, link-type LINUX_SLL2 (Linux cooked v2), snapshot length 262144 bytes
13:01:39.892849 eth0  In  IP 172.22.3.2.36202 > 172.22.10.100.55567: UDP, length 4
13:01:39.893467 eth0  Out IP 172.22.10.100.55567 > 172.22.3.2.36202: UDP, length 4
13:01:43.951945 eth0  In  IP 172.22.3.2.57033 > 172.22.10.100.55567: UDP, length 4
13:01:43.952904 eth0  Out IP 172.22.10.100.55567 > 172.22.3.2.57033: UDP, length 4

But if the client connect to 172.22.10.101.55567, the server still reply with src ip 172.22.10.100.55567 which make it unuseable on IP 172.22.10.101

13:02:48.927441 eth0  In  IP 172.22.3.2.51876 > 172.22.10.101.55567: UDP, length 4
13:02:48.928299 eth0  Out IP 172.22.10.100.55567 > 172.22.3.2.51876: UDP, length 4
13:02:50.387984 eth0  In  IP 172.22.3.2.46488 > 172.22.10.101.55567: UDP, length 4
13:02:50.388810 eth0  Out IP 172.22.10.100.55567 > 172.22.3.2.46488: UDP, length 4

This bug happens is because linux selects source address with following rules:

  1. User specified (with bind or write)
  2. Tracked by kernel (not happen for udp listen)
  3. Hit routes by destination IP
    3-1. If pref-src is set on the route, use it
    3-2. if the route points a NIC, select an IP from it
    3-3. If multiple IP on the NIC, use the ip marked as primary.

TCP socket get covered by system at rule 2 but udp is not.
If the selection hits rule 3, it's basically guess. Because it lost the information of which IP is the client connect to.

Different from TCP session, system won't track udp session for user, we have to handle it by our self.
We have to bind specfic source IP on udp each session otherwise system just select the primary IP from NIC based on default table. So that it brokes at system have multiple route table or secondary IP on the NIC.

What is the feature you are proposing to solve the problem?

In order to reply message with correct source address, we have to get the information of destnation IP at incoming packet.
Unfortunately we can't do it in nodejs right now so that there is no way to implement workable udp server with nodejs on multiple IP server.

There are similar issue, but all get closed and locked. And all these are talking something about broadcast address.
nodejs/node-v0.x-archive#8788
nodejs/node-v0.x-archive#6589

But in my use case, it irrelevant to broadcast address or overlapping subnets etc.
It's just a try to create a regular udp server application on a multiple IP server.
So I want nodejs developers reconsider this feature.

The another issue is get destnation IP for incoming packet is platform specific.
We have to write a lot of code to hendle it.

In linux (include Android) based platform, we have to use IP_PKTINFO
In BSD based platform (include MacOS and iOS), we need IP_RECVDSTADDR
In Windows platform, we need WSAIoctl and WSARecvMsg
For these 3 platform, it covers 99% of our scenarios.

But this is a generial purpose requirement.
It would be nice if we can make a abstraction for this feature at nodejs, instead of implement it with platform specific code with C binding.

What alternatives have you considered?

Uses native C api to retrive the destnation IP at incoming packet, then we can reply reply with correct source address.
Which make the code more complex, unreadable and unportable.

@HuJK HuJK added the feature request Issues that request new features to be added to Node.js. label Aug 21, 2024
@HuJK HuJK changed the title Get udp recipent IP for incoming IP Get udp recipent IP for incoming packet Aug 21, 2024
@RedYetiDev RedYetiDev added the dgram Issues and PRs related to the dgram subsystem / UDP. label Aug 21, 2024
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. feature request Issues that request new features to be added to Node.js.
Projects
Status: Awaiting Triage
Development

No branches or pull requests

2 participants