78

I have two network interfaces on a Linux PC, and I need to manually set the interface that a given process will use.

The program (Twinkle softphone) does not have a similar option, so I believe that it must be set externally.

How can I do it?

Edit: I'm not trying to make a server process bind to a specific interface, but rather to make a client program contact a server using a specific interface.

7 Answers7

54

you can replace code at runtime by the use of LD_PRELOAD (@windows you can use a similar technique called detours, quite fancy). what this does is to inform the dynamic linker to first load all libs into the process you want to run and then add some more ontop of it. you normally use it like this:

% LD_PRELOAD=./mylib.so ls

and by that you change what ls does.

for your problem i would try http://www.ryde.net/code/bind.c.txt, which you can use like:

% BIND_ADDR="ip_of_ethX" LD_PRELOAD=./bind.so twinkle

here is how you build it:

% wget http://www.ryde.net/code/bind.c.txt -O bind.c
% gcc -nostartfiles -fpic -shared bind.c -o bind.so -ldl -D_GNU_SOURCE

a longer howto is http://daniel-lange.com/archives/53-Binding-applications-to-a-specific-IP.html

similar hacks and tools:

akira
  • 63,447
43

ip netns can do this.

TL;DR: Create network namespaces, associate interfaces to them and then run "ip netns exec NAME cmd..."

Just check if your distro supports ip netns... (Backtrack 5r3 does not, whereas Kali does ;) )

IN MORE DETAILS:

#create netns
ip netns add myNamespace
#link iface to netns
ip link set eth0 netns myNamespace
#set ip address in namespace
ip netns exec myNamespace ifconfig eth0 192.168.0.10/24 up
#set loopback (may be needed by process run in this namespace)
ip netns exec myNamespace ifconfig lo 127.0.0.1/8 up
#set route in namespace
ip netns exec myNamespace route add default gw 192.168.0.1
#force firefox to run inside namespace (using eth0 as outgoing interface and the route)
ip netns exec myNamespace firefox

Why is this better than binding the ip via LD_PRELOAD? Because LD_PRELOAD does not control the route that the processes uses. It will use the first route.

And since it always uses the same route, it will default to the interface registered to the route.(which is not what we want)

olivervbk
  • 527
4

Based on @olivervbk 's answer below is mine!

Run all commands as "root".

Use the command...

ip a

... to find out the name of the network interface you will want to use.

Run the commands below as the template...

ip netns add [INTERFACE_NAME]_ns
ip link set dev [INTERFACE_NAME] netns [INTERFACE_NAME]_ns
ip netns exec [INTERFACE_NAME]_ns ifconfig [INTERFACE_NAME] 10.1.1.10/24 up
ip netns exec [INTERFACE_NAME]_ns ifconfig lo 127.0.0.1/8 up
ip netns exec [INTERFACE_NAME]_ns route add default gw 10.1.1.1
ip netns exec [INTERFACE_NAME]_ns dhcpcd [INTERFACE_NAME]
ip netns exec [INTERFACE_NAME]_ns sudo -b -u [YOUR_USER] [APP_NAME] 2> /dev/null 1> /dev/null &
  • [INTERFACE_NAME] - Replace with the name of the chosen network interface.
  • [YOUR_USER] - Replace with your user name.
  • [APP_NAME] - Name of the application that will be executed in the namespace "[INTERFACE_NAME]_ns". Eg.: "firefox".

NOTE I: The "-b -u" flags in the "sudo" command allow the application to run using your user (not "root") and in the background releasing the terminal. The 2> /dev/null 1> /dev/null & snippet is to prevent outputs from "[APP_NAME]" being printed at the terminal.
NOTE II: The values of ip "10.1.1.10" and "10.1.1.1" are arbitrary.
NOTE III: To work for me I had to run the dhcpcd [INTERFACE_NAME] command.

To remove the namespace use...

ip netns del [INTERFACE_NAME]_ns

... or...

ip -all netns delete

... to remove any that exists.

4

Alternative I:

Using ld_preload to force the interface gateway https://github.com/Intika-Linux-Network/App-Route-Jail

Force an application to use a specific network interface

We need to find what gateway the network interface is using then force that gateway to our jailed application and thus force the application to bind to a specific network interface

  • How to find the interface gateway (there are many solution to find the gateway here are some commands that permit to find the used gateway)?
$ route
$ route -n
$ ip rule list
$ ip route show
$ netstat -rn
$ cat /etc/network/interfaces
$ cat /etc/sysconfig/network-scripts/ifcfg-eth0
$ traceroute www.google.com
$ ip route show 0.0.0.0/0 dev eth0

Per application gateway

  • Build App-Route-Jail
git clone https://github.com/Intika-Linux-Network/App-Route-Jail.git
cd Approute-Utils
chmod 755 make.sh
./make.sh
  • Add a route for the future marked packets (for the jailed application) in this example 192.168.1.1 is used as the forced gateway, this route rule will not affect other applications, this manipulation have to be done only once at the system boot for instance if you want to use this solution daily
ip rule add fwmark 10 table 100
ip route add default via 192.168.1.1 table 100
  • Start the application that you want to jail
MARK=10 LD_PRELOAD=./mark.so firefox
  • Testing the WAN IP address
MARK=10 LD_PRELOAD=./mark.so wget -qO- ifconfig.me

Alternative II:

Firejail https://firejail.wordpress.com/ can force an application to use a specific network, but the compatibility is limited.

firejail --dns=8.8.8.8 --net=eth0 --ip=192.168.1.1

Sources: Linuxhacks.org
Disclosure: I am the owner of Linuxhacks.org

intika
  • 1,383
3

I don't think it is possible to force a process to use a certain interface.

However, I think you might be able to play with ipchain/iptables and force that a certain port your process is listening at will only get packets coming through a particular interface.

Useful HOWTO: http://tldp.org/HOWTO/IPCHAINS-HOWTO.html

thetarro
  • 139
1

Usually if a program has no option for setting listening interface, it's listening on ALL interfaces. (You can verify this with lsof -i).

Creating iptables firewall rules that drop incoming traffic pointed towards its ports on interfaces you don't want it to be visible on is the easiest thing to do.

LawrenceC
  • 75,182
-2

Why would you want a program to use an interface other than the one connected to the server to talk to that server? And if the system isn't using the interface connected to a server to talk to that server, it's a system-level (routing table) issue and has nothing to do with which process happens to want to talk to that server.

Different servers on IP networks have different IP addresses. The kernel should know which interface to use to reach a particular IP address based on the routing table. If you're trying to talk to two different servers that have the same IP address, the system will get confused (because, among other things, it only indexes the connections internally by destination address). You can make that work, but it's a system-level fix involving putting one server in a separate logical network that's only connected to the machine through software NAT.

So if they have different IP addresses, use routes to select the correct interface. If they have the same IP address, you need to use NAT so that they appear to have different IP addresses to the system.