UDP packets lost (LAN-Netcat) , switching server-client sides packets are OK - sockets

I was trying to run a game that uses UDP socket on LAN , but could not see the other computer in my network, so i tried somethings to see what can give rise to this issue. The running OS's are:
PC1: Linux Ubuntu
PC2: Windows 10
The issue is that when PC2 is listening , the PC1 can send and receive packets:
$PC2> ncat -ul 8888
$PC1> ncat -u PC2 8888
OK
Send and receive works OK, However when client/server is switched, the packets are lost.
$PC1> ncat -ul 8888
$PC2> ncat -u PC1 8888
On a side note, on PC2 when trying to send the packet with Pythons socket.sendto function the return value is not -1 and is the size of the packet.
Also turning of firewall on PC2 doesn't help.
This is weird problem since one-way works fine but switching the client/server the packets are loss.

One of the hosts (PC1) might be behind a NAT, while the other (PC2) is in a public network. It should be clear if it is the case, if you provide ip addresses of the hosts. Presence of NAT would explain why switching client and server breaks.
When a packet is sent from PC1 to PC2, NAT would add an ip translation record of the form
(PC1 internal ip address, port1) -- (PC1 public ip address, port2),
and translate internal address to public and vice versa whenever needed.
When PC1 becomes a server, there is no way to reach it from PC2 through the NAT. Unless you configure port forwarding of the NAT or use some third-party NAT discovery services.
NAT port forwarding works in the following manner. If a port forward rule
(PC1 public ip address, port2) -- (PC1 internal ip address, port1) is specified, all packets send to (PC1 public ip address, port2) are forwarded to (PC1 internal ip address, port1).

Related

Sending a UDP datagram to a shared IP address and port

Suppose that two computers use the same Wi-Fi to access the Internet. Each of these computers has the same program installed, which is bound to the same UDP port. I want to know, since both computers have the same external IP address and listen to the same port but on different machines, what will be the result if a UDP datagram is sent to this common external address and to a common port, then which machine will receive it and how to send it each machine its own personal datagram?
The router will not forward the packet to either computer, since it doesn't know which one it should forward to.
In fact, even if the program was only running on one computer, the router still wouldn't forward the packet. It has to see outbound traffic going from the computer to the outside world first, before it decides which external port to use for forwarding inbound traffic back to the computer. And the router might not decide to use the same port on the public IP that the computer used on the private IP.
This is why everyone hates NAT and likes IPv6.

Can be two identical socket established?

A socket is combination of an IP address, a transport protocol and a port number.
For example: two hosts, on different LANs behind NAT, can have the same IP (let's say 192.168.0.2).
When these hosts connect to a web server, could two identical sockets be established?
I know that ports are randomly generated, but on different hosts it could be generated the same one.
Or it is server which tells that this port number is already in use?
Or is it NAT device, which changing SRC IP in IP packet?
How does NAT device knows then, where to send packet back to host on LAN?
Thanks
As you correctly guessed it is NAT who assigns ephemeral port number, so they can't coincide. Therefore, from server perspective, destination duplet of host #1 would be something like 192.168.0.2:46812, and for host #2 - 192.168.0.2:51378. When NAT receives these packets, it knows which host behind the NAT the packet belongs to based on the port number. If you have access to machine's console you can check the numbers with netstat -anp

Confusion about the stun server

What i require is that, I will open an UDP server listening in X port(local machine) and a machine(public IP) can send UDP packet to me. My machine doesn't have a public IP. Basically I need stun.
I am testing stuntman server/client project. I run stuntman-server in a server(public ip). Run client in my system (local ip). I asked for mapped ip/port for 9999 port.
./stunclient --mode full --protocol udp --localport 9999 stun.server.ip
Stun server returns an IP and port. What i did then, open an UDP server (using java) in my local system and start listening in 9999 port and send an UDP message from other machine (which has public IP) to mapped IP/port returned by stun server. But i can't receive any data. You can assume that my server/client code (written in java) is working fine in local network.
Flow:
My machine ->>>>>stun request for 9999 port and my ip ------> stun server
My machine <<<<<<<<<<<<<<<<<<mapped ip/port <<<<<<<<<<<<<<< stun server
My machine : Run JAVA udp server socket in 9999 port
My machine <<<<<<<<<<<<<<<<<<<UDP message to mapped ip/port<<<<<< other public machine
xxxxxxxxxxxxxxxxxxxNot workingxxxxxxxxxxxxxxxxxxxxxxxx
You didn't publish the results of your stunclient run, but I imagine it looked something like the following:
$ stunclient --mode full --localport 9999 stunserver.stunprotocol.org
Binding test: success
Local address: 192.168.1.8:9999
Mapped address: 1.2.3.4:9999
Behavior test: success
Nat behavior: Endpoint Independent Mapping
Filtering test: success
Nat filtering: Address and Port Dependent Filtering
I'm going to guess that your Behavior Test is "Endpoint Independent" and the Filtering test was "Address and Port Dependent" as those are the most common in the home and mostly matches with what you described above. (aka as "port restricted NAT").
In any case, this means you have created a port mapping between yourself and the STUN server. In the example above, my public IP address is 1.2.3.4. And is common, but not always the case, my local port (9999) is the same as the public port.
Internally, your NAT keeps a logical table such as the following:
------------------------------------------------------------------------------------
|| LOCAL IP | LOCAL PORT || EXT PORT || REMOTE IP | REMOTE PORT ||
||================================================================================||
|| 192.168.1.8 | 9999 || 9999 || 107.23.150.92 | 3478 ||
------------------------------------------------------------------------------------
Because you sent out a packet from port 9999 to the stun server (107.23.150.92), the NAT creates a port mapping entry in it's table for several minutes. When a packet arrives on the NAT/router from the Internet, it consults the table. When the response came back from the STUN server's IP:port, the NAT was able to forward it to your computer behind the NAT based on the "remote" fields in the table above.
But there is no port mapping between you and the "other public machine" that you are hoping to receive data from. Let's assume that the IP address of that other machine is 2.4.6.8 and it is attempting to send from it's local port 8888. The NAT still doesn't have anything in the table to map traffic from 2.4.6.8:8888 to a host behind the NAT. So when traffic arrive at a NAT from an a host not in the table, the NAT only knows to drop the packet on the floor. There is a NAT classification known as "Cone NAT" where this would work, but those aren't as common.
In your case, there is an easy workaround. After obtaining a port mapping from the STUN server, send another datagram from your same local port (9999) to the remote host (and remote port) that you want to receive data from. The remote host can simply ignore this datagram, but it effectively creates another port mapping entry on your NAT
------------------------------------------------------------------------------------
|| LOCAL IP | LOCAL PORT || EXT PORT || REMOTE IP | REMOTE PORT ||
||================================================================================||
|| 192.168.1.8 | 9999 || 9999 || 107.23.150.92 | 3478 ||
|| 192.168.1.8 | 9999 || 9999 || 2.4.6.8 | 8888 ||
------------------------------------------------------------------------------------
That simple 1-byte data packet to 2.4.6.8:8888 allows the NAT to forward traffic back from that address to your host behind the NAT.
In other words, using your own network flow nomenclature:
My machine:9999 ---->[STUN BINDING REQUEST]--->stun server:3478
My machine:9999 <----[STUN BINDING RESPONSE mapped IP:port]<--- stun server:3478
My machine:9999 [Open socket on port 9999]
My machine:9999 ---->[1 byte datagram] -------> 'other:8888'
My machine:9999 <---- [UDP to public IP:port obtained in step 2]<----'other:8888'
Typically, in a normal P2P flow, both endpoints work with a STUN server to discover their port mapping. And then use another service on to exchange IP:port information between each other. From what you describe, you are manually exchanging these values between your programs, which is fine for testing.
If the other machine is on the public internet, you technically do not need STUN. The first machine (behind a NAT) can just send directly to the remote IP and port to say, "send me some data". The remote side just inspects the peer address and port of this message to decide where to send back to. The port mapping has already been created. Some RTSP clients assume the server is public
My answer on the basics of socket NAT traversal is here.
I happen to know the developer of STUNTMAN. He's a reasonably nice guy, good looking, and very smart. They also say him and I look alike and have near identical spelling with our names. You can always mail him directly if you have questions about STUN and NAT traversal.

Does UDP hole punching occur in between hosts inside the same network?

Say I have a router with IP 42.98.1.70, with 2 NiCs connected to it with IPs 192.168.1.200 and 192.168.1.300. The router has port forwarding on port 10433 to redirect packets to 192.168.1.200. The routers internal network IP is 192.168.1.100.
When NIC 192.168.1.300 sends a packet to socket 42.98.1.70:10433. the host 192.168.1.200 gets a packet from socket 192.168.1.100:48900, which as far as I know, looks like a hole punched socket setup by the router.
So theoretically, if host 192.168.1.200 replies with a packet to socket 192.168.1.100:48900, that packet should eventually get back to host 192.168.1.300, since the router should bridge the two via its internal table mapping, aka 'UDP hole punching'.
However, the packet sent back to 192.168.1.100:48900 from 192.168.1.200 never reaches 192.168.1.300.
i'm suspecting that what could be going on is that UDP hole punching doesn't work in between NICs on the same network. It only works between a source that is external to the network and one that is within it. Is that the case?
After reading this RFC - https://www.rfc-editor.org/rfc/rfc5128, it looks like what i was trying to do is called "hair pinning". Although some routers support it, not all do. Apparently mine is one of those.

Does port forwarding work from inside the network?

Say you have a router with external ip 42.1.98.9, with the port 10443 set to forward all incoming TCP/UDP packets to host 192.168.1.200. The routers internal network address is 192.168.1.100.
say there are two NICs connected to the router, with internal IP 192.168.1.200 and 192.168.1.300.
I've noticed that packets sent to socket 42.1.98.9:10443 gets redirected to 192.168.1.200, which is the expected behaviour.
However, say the computer 192.168.1.300 sends a packet to socket 192.168.100:10443. In other words a computer from inside the network is sending a packet to the router, in a port that should theoretically redirect incoming packets.
On that scenario, I'm not noticing the packets being redirected to the proper host -- 192.168.1.200.
Why is that? Does port forward on the router occur only for packets being sent to its external IP address?
Thanks
Yes, generally port forwarding is only from the external address to internal addresses. I'm guessing a commercial-grade router could be programmed to do what you want, but not any home router I've ever seen.
You should be able to use the router's external address from inside the network though (i.e., send packets from 192.168.1.300 to 42.1.98.9:10443 and it should redirect to 192.168.1.200:10443).