4
  • I have two network interfaces, A 1.2.3.4 and B 1.2.3.99. (in ifconfig)
  • I run nc -l 1.2.3.99 20101 -v to listen on the interface B.
  • I run nc -v 1.2.3.99 20101 -s 1.2.3.4 -4 because I want to use the interface A.

It connects but when I check with wireshark, no packet from A or B, only in lo...

Why it doesn't use the interface with the associated IP ? What should I do to force them to use the associated interface ?

Edit:

After following the piece of advice of Patrick:

ip route add local 1.2.3.99 dev B table main
ip route del local 1.2.3.99 dev B table local
ip route add 1.2.3.99 dev B table local

I run nc -l 1.2.3.99 20101 but I get an error when I create the tcp server Ncat: bind to 1.2.3.99:20101: Cannot assign requested address. QUITTING.

17:10:38 alexis:~  $ ip route list table local
1.2.3.99 dev B  scope link 
...

17:10:40 alexis:~  $ ip route list table main
default via 10.133.0.1 dev eth0 
local 1.2.3.99 dev B  scope host
...
  • Side note, if the netmask on both these interfaces/addresses is /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. – Patrick Jun 2 '17 at 4:23
  • Also, please specify the operating system. The answer/explanation can vary by OS. – Patrick Jun 2 '17 at 4:26
  • The netmask should be /32 since I want only one address for each interface. We are in Unix&Linux stackexchange. I'm using CentOS tho. – Alexis_FR_JP Jun 2 '17 at 6:12
  • Yes, but Unix & Linux is very broad. You've got Linux, HP-UX, Solaris, FreeBSD, OpenBSD, Plan9, ... – Patrick Jun 2 '17 at 12:08
9

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 1.2.3.99 from 1.2.3.4, which will output something like:

# ip route get 1.2.3.99 from 1.2.3.4
local 1.2.3.99 from 1.2.3.4 dev lo 
    cache <local>

This shows that the kernel is going to send the traffic over the lo interface.

To walk through why, lets start with the command ip rule:

# 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 1.2.3.0 dev eth0  proto kernel  scope link  src 1.2.3.4 
local 1.2.3.4 dev eth0  proto kernel  scope host  src 1.2.3.4 
broadcast 1.2.3.255 dev eth0  proto kernel  scope link  src 1.2.3.4 
local 1.2.3.99 dev eth1  proto kernel  scope host  src 1.2.3.99

(yours will likely look different)

From this we then look to see if any of the routes match the destination address (1.2.3.99) 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 lo interface.


As for how to make it use the A/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 local one:

ip route add local 1.2.3.99 dev B table main
ip route del local 1.2.3.99 dev B table local
ip route add 1.2.3.99 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 lo interface.

  • I understood. Asking to the application to use one interface is not a solution. I am using nc just because it's easy and can reproduce what the app will do. I need to use ip route. Unfortunately, I have an error Ncat: bind to 1.2.3.99:20101: Cannot assign requested address. QUITTING. when trying to listen on this interface B. – Alexis_FR_JP Jun 2 '17 at 6:15
1

Access to local addresses always uses the loopback interface since network interfaces are designed to send packets to other nodes on the wire, not yourself.

0

With netcat-openbsd on debian and opensd, you can choose the routing table you want to use.

The option is -V.

With regular netcat I believe this is not possible.

With socat you can use a specific interface declaring it at call time.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.