How to use different network interfaces for different processes?

61

48

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.

Andrea Spadaccini

Posted 2011-02-03T11:08:37.813

Reputation: 776

clients use bind/connect as well, look at the bind.c.txt documentation of how to force ircII (an irc-client programm) to a given ip: 'Example in bash to use your virtual IP as your outgoing sourceaddress for ircII: BIND_ADDR="your-virt-ip" LD_PRELOAD=./bind.so ircII' – akira – 2011-02-03T13:34:08.903

I found a different approach here, I hope it's helpful (I sure hope the described kernel policy routing is enabled by default nowadays): http://kindlund.wordpress.com/2007/11/19/configuring-multiple-default-routes-in-linux/

– Savvas Radevic – 2012-01-28T23:52:48.407

Answers

48

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

Posted 2011-02-03T11:08:37.813

Reputation: 52 754

The force_bind project by Catalin M. Boie supports ipv6 – BurnsBA – 2016-01-12T05:52:45.140

1Works great but had to add #include <arpa/inet.h> for compilation to succeed. – anno – 2019-02-11T23:12:04.803

8Wow, what the heck. +1 – sinni800 – 2011-02-03T12:04:33.720

1Hi, this seems a really nice trick, but it does not work for me. I have two 3G modems that, when connected, open two interfaces (ppp0 and ppp1). If I try to force one of the two IPs, I always end up going out with the same interface (I see it because I have two instances of wireshark, one for each interface). I also removed the debug prints from bind.c and indeed I see that the "overloaded" library is loaded, so I don't know why it doesn't work. – Andrea Spadaccini – 2011-02-09T17:18:48.577

3LD_PRELOAD is ignored if your effective UID is not the same as your real UID. – matthias krull – 2011-03-24T17:59:56.347

32

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

Posted 2011-02-03T11:08:37.813

Reputation: 419

4don't do this on the remote server if eth0 is the public network interface.. – ygrek – 2014-07-21T07:46:11.770

Wow, Linux still surprises me with simple solutions to strange problems... – Mark K Cowan – 2015-06-08T15:14:38.700

1the last line should be ip netns exec myNamespace firefox – meuh – 2015-06-20T15:01:44.790

This is the easiest solution that I found., better than use the rt_tables files, wich can be a solution for incomming connections but not for the outgoing. – Rfraile – 2017-02-15T10:58:40.900

Uh, as soon as you change the namespace for eth0, you lose connectivity to your host! So I'm not sure how this works. – Otheus – 2017-07-27T18:21:21.520

@Otheus - this was mentioned in an earlier commenr. I never tried this using a remote connection though I believe it should be the same as trying to change the IP of the interface you're connected to. Run the whole command in one line (with ; or &&) and pray for the best. I have no idea if services will continue to listen to that interface... – olivervbk – 2017-07-27T18:53:13.460

1Use "sudo ip netns del <namespace-name>" to remove the namespace when needed! – Eduardo Lucio – 2017-08-08T14:13:08.720

If we could run the application without using root would be great. – Eduardo Lucio – 2017-08-08T14:14:12.073

1@EduardoLucio it should be possible to execute it like: sudo ip netns exec myNamespace su -u someUser -c firefox – olivervbk – 2017-08-09T15:32:35.497

2Please try to add more details to your answer. – Renju Chandran chingath – 2014-05-06T16:47:51.937

Details added... – olivervbk – 2014-06-16T16:40:28.280

2

Based on @olivervbk answer below is my!

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.

Eduardo Lucio

Posted 2011-02-03T11:08:37.813

Reputation: 712

2

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

Posted 2011-02-03T11:08:37.813

Reputation: 137

2The two higher-voted posts prove otherwise. – Paul Gear – 2016-07-06T07:36:26.887

1

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
chown 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 wont 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

intika

Posted 2011-02-03T11:08:37.813

Reputation: 839

Note that mark is not possible for normal users, you must run as root. – jornane – 2019-08-09T12:54:45.067

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

Posted 2011-02-03T11:08:37.813

Reputation: 63 487

-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.

David Schwartz

Posted 2011-02-03T11:08:37.813

Reputation: 58 310

One case is if you have different public IPs and you want to launch a new process in each one for outgoing connections. – Rfraile – 2017-02-15T10:56:07.843

3Firstly, there may be multiple valid routes between the client & server, but with different characteristics suitable for different traffic types; e.g. UMTS (Cellular Data) may cost money but has greater range than WiFi, but both are slower than a fiber connection. If the upstream providers do source filtering (or NAT), you have no choice but to send out the 'right' interface. Secondly, influencing routing is not the only reason to select a source address. Even when both addresses are on the same interface it can be useful to control which is bound to when initiating connections, as the server – None – 2012-06-11T05:58:50.487