I'm trying to open multiple sockets in a ruby application on different network interfaces in linux. For example lets say I have the interface eth0 with an IP of 192.168.1.2 and the interface wlan0 with the IP address 10.0.0.2. I would like to simultaneously connect to a server with a socket on each interface. I thought that binding to the IP address of these interfaces would work however that doesn't seem to be the case. In wireshark when I bind to the IP of wlan0 I successfully see the SYN packets send with the correct source IP, but wireshark sees them on eth0 and the socket is never opened.
Ruby version: ruby 1.9.3p194 (2012-04-20 revision 35410) [x86_64-linux]
Here is my current code. I have also tried the Addrinfo method documented on the ruby-doc page for Socket with the same results.
require 'socket'
ip = "192.168.1.2" # IP of internal interface
port = 8000
server = "" # IP of the server I'm trying to connect to goes here
lhost = Socket.pack_sockaddr_in(0, ip)
rhost = Socket.pack_sockaddr_in(port, server)
socket = Socket.new(Socket::AF_INET, Socket::SOCK_STREAM, 0)
socket.bind(lhost)
socket.connect(rhost)
Thank you for any help!
I was able to figure it out, and thought I should leave my answer in case anyone else gets stuck with this problem down the road.
What I needed to do was source based routing. The general idea is to create two routing tables, one that forces traffic on one interface and one that forces traffic on the other, and have an ip rule that uses the appropriate routing table based on the source IP address. I set it up like this:
First I had to edit /etc/iproute2/rt_tables
to add the following lines:
128 multiplex0
129 multiplex1
This created two routing tables with IDs 128
and 129
called multiplex0
and multiplex1
.
Next I created rules for these tables as follows:
ip route add default via 10.0.2.2 table multiplex0
ip route add default via 192.168.1.1 table multiplex1
These commands specify the default gateways to use in the routing tables. My 10.0/16 network had a default gateway of 10.0.2.2 and my 192.168.1/24 network had a default gateway of 192.168.1.1.
I believe you can add dev eth0
(or whatever your interface is) to the above commands to specify an interface if your networks have the same default gateway, though I have not yet tested this. I will make an edit when I learn more.
EDIT: I have tested this and it does indeed work. Both routes can have the same default gateway if you specify the interface in the route.
Next I needed to create rules to use these tables:
ip rule add from 10.0.0.0/16 table multiplex0
ip rule add from 192.168.1.1/24 table multiplex1
These rules say that any packet with a source IP in the 10.0/16 range should route based on the rules in multiplex0, while any packet with a source IP in the 192.168.1/24 range should use multiplex1. When the packets use these tables they are directed to the appropriate gateway and corresponding interface. Viola!
EDIT: It would be more accurate to specify just the IP of the network interface in this step! If both interfaces are on a 192.168.1/24 network for example, it would be necessary.
Lastly I issued ip route flush cache
to make everything take effect and using the ruby code above I was able to open my two sockets on the correct interfaces to the same publicly route-able host.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With