Binding a UDP socket to wildcard hosts in Ruby - ruby

I have been trying to understand the basic idea behind UDP hole punching, and I'm having trouble understanding the difference between the following two socket bindings:
sock = UDPSocket.new
sock.bind('', port )
and
sock = UDPSocket.new
sock.bind('0.0.0.0', port)
Previously I had thought using '' or '0.0.0.0' did the same thing -- allow the socket to listen on any network interface -- but since the code didn't work with them interchanged I must be missing something.
For the initial 'punch' the datagram is sent from a socket bound to '', which is then closed and the actual communication with the remote host is done over a socket bound to 0.0.0.0. I know 0.0.0.0 generally refers to the default route, but I can't figure out the significance of that in this situation. Does binding a socket to 0.0.0.0 mean you're assigning it the address of the default gateway?

Looks like both provides the same behavior: your socket is listening on all interfaces on given port:
ruby 38156 grych 7u IPv4 0x40a92a845129cab1 0t0 UDP *:6666
My system is Darwin 14.0 (OS X Mavericks), ruby 2.0.0 - I am wondering if it depends on the OS.

Related

what does tcp:*:port mean in zeromq?

I see this sort of address used in a bunch of examples. What does it mean exactly? Does it mean it will connect to any/all machines on the subnet that have something listening to that port? Or something else entirely? I see such usage in the docs and in books without explanation. Sort of annoying.
It is explained in the manual.
ZeroMQ supports multiple transports. tcp means you are using the TCP transport.
The address (or endpoint) for the TCP transport has the following format:
tcp://interface:port
When you bind to a local address, interface is either the IP address of a specific interface (network) or *, which means to listen on all interfaces (networks). port is the TCP port or * for a random port.
When you connect to a remote endpoint, interface is the hostname or IP address of the remote machine. port is the TCP port of the remote endpoint.
To add to rveerd's answer, what's often missed is that you can multiply bind a socket. So, tcp://*:5555 specifies port 5555 on any interface and you can bind the socket accordindly. But by calling zmq_bind() again you can bind the same socket to, say, ipc:///tmp/feeds/0, which means it will also accept connections on the /tmp/feeds/0 IPC pipe.
This is a pretty spectacularly useful feature in my view, because you can trvially have other actors local and remote to the machine though a single zmq socket.

Same host UDP packet correlation in Go

In Go one can send UDP packets using net.Addr interface to specify the target endpoint. Some special addresses, e.g. :8080 and 0.0.0.0, sends packets using local loopback interface. When received, still on the same host, the message's net.Addr shows [::1]:8080 as source. What is the the easiest way to determine that the packet was sent and received by the same host?
Here's an example in the Go Playground. It shows 0.0.0.0:8080 (ipv4) instead of [::1]:8080.
I ended up using net.Dial("udp", addr) and eminently closing the connection. Dial also resolves hostnames, which I also needed.
Would be nice to avoid creating a socket, but Dial works for now.
:8080 is not an address, it is a port number, typically used when testing your own http websites on Windows because on Windows you cannot easily use port 80, the actual http port.
This will only use the loopback interface if you use localhost as the IP address.
The localhost address for IPv4 is 127.0.0.1 and for IPv6 it is ::1. The address 0.0.0.0 is usually used as a placeholder address to indicate, for example, listening on all IP addresses, see this question.
As mentioned in the comment, you can use net.IP.Equal to check if your peer is localhost. Just compare your address in question to 127.0.0.1 or to ::1, the net.IP.Equal function considers them equal.

ruby cannot assign requested address

I had already created a qt program that listens on a specific port on my server. And it works fine. Now I want to create a simple ruby program to do the same. Right now I just have a simple test server using netcat which establishes a network socket and accepts UDP data (this is Ubuntu server by the way):
$ sudo nc -l 1720
Now I am just trying to listen on the port in Ruby:
# network.rb
require 'socket'
socket = UDPSocket.new
socket.bind('64.xxx.xx.xxx', 1720)
This right away raises this exception:
network.rb:4:in `bind': Cannot assign requested address - bind(2) (Errno::EADDRNOTAVAIL)
WHy is it saying the address is not available? All that is there is a netcat socket. The goal is that I will have UDP data coming in from GPRS devices to that port, and then I will have ruby sitting on my ubuntu server listening for that data, then decoding it, and storing it into a postgresql database.
You are making a server or client?
you used nc, so i guess you are making client.
server is bind
client is connect:
c = UDPSocket.new
c.connect("127.0.0.1", 1111)
"address is not available" usually as the port is used.
or you can ping the address fisrt to check if the address can be reached
I was getting the same error by running:
rails s -b 10.0.0.61
It turns out that my local IP wasn't 10.0.0.61 and this was causing the error.

Sending TCP packets over internet (using Ruby)

I am trying to learn how to send TCP packets across the internet to another computer. So say, computer 1 sends data across the internet to computer 2 (using TCP). Assuming that both computer have port forwarding correctly set, how would I go about establishing a TCP connection between the two computers (in Ruby preferably)? I have it working on my LAN, but when I try over the internet, it doesn't seem to work.
My attempt (basically):
Computer 1:
server = TCPServer.new 32500
client = server.accept
Computer 2:
TCPSocket.new PUBLIC_IP_OF_COMPUTER_1, 32500
Problem is that TCPSocket never connects to TCPServer.
I read in the Ruby doc that TCPServer.new's syntax is
new(remote_host, remote_port, local_host=nil, local_port=nil)
What happens if I just leave local_host=nil and local_port=nil (rather than assign them the private IP and port 32500 number on Computer 1)?
If somebody could point me in the right direction, that's be great! I hope I my approach is at least somewhat correct.
You created a server which is listening only on the loopback Interface.
Try this out:
curl ifconfig.me
You will get your external IP address, how it is visible from outside, for example 123.123.123.123
server = TCPServer.new 2000
Now You have a server listening on port 2000
lsof -i :2000
for example:
ruby 37186 wopi 6u IPv4 0xcf0818acc2bdc38d 0t0 TCP *:callbook (LISTEN)
now connect from THE SAME machine to localhost
telnet localhost 2000
this works
telnet 123.123.123.123 2000 # substitute your real external IP address
this will not work
That is why You can't connect from outside.
Checkout how ngrep, netcat and tcpdump are working, invaluable tools for network debugging.

PF_PACKET socket and 'Port unreachable' ICMP messages

My application needs to receive UDP packets from multiple destination ports (this is a bonafide application and not a sniffer). Therefore, I have chosen to use a PF_PACKET socket and to do port filtering at the application level.
Here's how I create the socket:
int g_rawSocket = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
I am correctly receiving UDP packets. However, the kernel on which the application runs is sending ICMP packets of type 'Destination unreachable' and code 'Port unreachable' to the remote device that is sending packets to my app. I guess that this is because I have not bound a port number to the socket. However, I wonder if it is appropriate to use bind with a PF_PACKET socket, especially as I need to bind multiple ports to it, which I guess is not possible.
Any comments please?
No, it can't be bound to a specific port, since it's working on a lower level than the Transport (UDP/TCP) layer. However, you could open and listen to all sockets, using regular UDP (AF_INET/SOCK_DGRAM) sockets and select for example and as far as I know you can bind and listen to as many sockets as you want, as long as you don't exceed the limits of open file descriptors for your process.
I have also done the same thing in my application.
in my case i have created sockets as many i need & bind them with the particular port. but i m not listening to any socket. so i created one raw socket
int sock_raw = socket(AF_INET , SOCK_RAW , IPPROTO_UDP);
& then received all the traffic without any ICMP.
So i think u have to bind all the ports to avoid ICMP either you have to some kernel hacking as stoping or removing the code for ICMP in the linux-kernel code & build it again

Resources