When you tell an application to use a specific IP address, the application is using the IP address, not the interface. Some applications do let you use a specific interface, but this is a separate behavior (SO_BINDTODEVICE).
Since the application is binding to an IP address, and not an interface, the kernel is free to use whatever interface it wants. To determine which interface to use, it uses the routing tables (yes, there are multiple).
If you just want a quick way to determine what interface/route the traffic will take, you can use
ip route get 18.104.22.168 from 22.214.171.124, which will output something like:
# ip route get 126.96.36.199 from 188.8.131.52
local 184.108.40.206 from 220.127.116.11 dev lo
This shows that the kernel is going to send the traffic over the
To walk through why, lets start with the command
# ip rule
0: from all lookup local
32766: from all lookup main
32767: from all lookup default
This shows all the routing tables the kernel is going to use to find the route for traffic. It starts with the top, and stops on the first match. The
from all means that the rule matches any source address. So it's going to consult table
local first. We can then look inside this table:
# ip route show table local
broadcast 127.0.0.0 dev lo proto kernel scope link src 127.0.0.1
local 127.0.0.0/8 dev lo proto kernel scope host src 127.0.0.1
local 127.0.0.1 dev lo proto kernel scope host src 127.0.0.1
broadcast 127.255.255.255 dev lo proto kernel scope link src 127.0.0.1
broadcast 18.104.22.168 dev eth0 proto kernel scope link src 22.214.171.124
local 126.96.36.199 dev eth0 proto kernel scope host src 188.8.131.52
broadcast 184.108.40.206 dev eth0 proto kernel scope link src 220.127.116.11
local 18.104.22.168 dev eth1 proto kernel scope host src 22.214.171.124
(yours will likely look different)
From this we then look to see if any of the routes match the destination address (126.96.36.199) by looking to see if the destination matches the second field. In the output above, the very last one matches. In this line, the first field is
local, which according to
man ip-route means:
local - the destinations are assigned to this host. The packets are looped back and delivered locally.
This means that the traffic is going to flow over the
As for how to make it use the
B interface, you have 2 options:
1) The application would need to provide you with an argument where you can specify the interface. There are a dozen flavors of netcat, but the version on my systems does not have such an option.
socat does though (I personally recommend
socat over netcat because of the inconsistency & portability nightmare that is netcat. It's also way more powerful).
2) Create a non-
local route that matches before the
ip route add local 188.8.131.52 dev B table main
ip route del local 184.108.40.206 dev B table local
ip route add 220.127.116.11 dev B table local
In these rules, the first 2 rules move the
local route into the
main table. Adding the route to the
main table has to come first as the host has to have a
local route somewhere for the kernel to accept traffic for that address. Having the route in 2 tables is OK. After that we then add a new route to the
local table which does not have the
local designation, which will result in traffic not going over the
/24, you're likely going to be frequently running into problems. Having 2 interfaces on the same subnet can be done, but it presents numerous difficulties to get working properly.