7

I'm trying to determine if it is possible to selectively route IP packets from a process or process group through a specific interface while all other packets are routed through another interface. That is, I want all traffic from /usr/bin/testapp to be routed through eth1 while all other packets go through eth0. Packets in this case can be TCP, UDP, ICMP, etc. and can be configured by the end users to use various port(s).

Because I'm not able to easily force the process in question to bind to a specific interface, I am trying to achieve the same outcome via routing. Is this possible?

--- edit ---

Through a helpful suggestion here, and in many other places, is to mark packets based on UID; that is not really the goal. The goal is to mark/filter/route based on process regardless of user. That is to say, if alice, bob and charlie all run their own instance of /usr/bin/testapp; all packets from all three instances should go through eth1 while all other packets from the system should go through eth0.

Note that marking by source/destination port, user name/UID, etc. is not sufficient since various users may run testapp and they may setup different ports in their own ~/.config/testapp.conf or whatever. The question is about filtering by process.

One option that is available, though I do not know how helpful it is, is to use a /bin/(ba|z)?sh-based wrapper around the native binary.

--- edit ---

I'm referring to routing on a system running a modern Linux kernel, say 4.0 or better. If there are software dependencies beyond iproute2, nftables, conntrack and similar tools, I'm willing to explore open source solutions, though basic tools are preferable.

justinzane
  • 181
  • 2
  • 13
  • This might be able to help: http://stackoverflow.com/questions/4314163/create-iptables-rule-per-process-service. – Massimo Jun 16 '15 at 19:43
  • Can you control the source/destination ports and/or IP? If so, you can easily do this with iproute2 and fwmark. Also, consider running testapp inside a vm/container and doing it that way. – dmourati Jul 08 '15 at 07:27
  • Users will launch other processes (that binds to network) as well or only testapp ? – Nehal Dattani Jul 13 '15 at 09:16

5 Answers5

3

Your routing the packets through either eth1 or eth0. tables mangle should address this. To do so, I had to mark packets and set up rules for handling it. First, add a rule that make the kernel route packets marked with 2 through table

ip rule add fwmark 2 table 3

Add a route for redirecting traffic over a different interface, assuming the gateway being 10.0.0.1:

ip route add default via 10.0.0.1 table 3

Flush your routing Cache.

ip route flush cache

Now, set a firewall rule for marking designated packets:

iptables -t mangle -A OUTPUT -p tcp --dport 465 -j MARK --set-mark 2

Finally, relax the reverse path source validation. Some suggest you to set it to 0, but 2 seems a better choice according to https://www.kernel.org/doc/Documentation/networking/ip-sysctl.txt. If you skip this, you will receive packets (this can be confirmed using tcpdump -i tap0 -n), but packets do not get accepted. The command to change the setting so packets get accepted:

sysctl -w net.ipv4.conf.tap0.rp_filter=2

Reference : http://serverfault.com/questions/345111/iptables-target-to-route-packet-to-specific-interface

c4f4t0r
  • 5,149
  • 3
  • 28
  • 41
Peter Nduati
  • 334
  • 1
  • 6
  • 1
    Thanks, however, unless I'm not understanding, you example seems to only manage packets with a dest. port of 465. While that might work for something like an MTA, it would not be very helpful for anything that used an a priori undefined set of destination ports. – justinzane Jul 08 '15 at 13:32
  • @justinzane Couldn't you just change from port 465 to whatever port your processes are using? Otherwise, there's no way to differentiate down to the process level, because network routing generally happens at the network layer, not the application layer. – CIA Jul 09 '15 at 17:27
0

This is possible using network namespaces to isolate the process, a virtual ethernet connection to connect that network namespace to your main namespace. You can then use iptables to route based on that source.

So here's an example. I'm using network manager for some commands but you could do it raw

# Create a namespace
ip netns add ns1

# create a bridge between them
nmcli connection add type veth ifname virt0 peer virt1
ip link set virt1 netns ns1
ip addr add 192.168.69.1/24 dev virt0
ip netns exec ns1 ip addr add 192.168.69.2/24 dev virt1
ip netns exec ns1 ip link up virt1
echo 1 > sudo tee /proc/sys/net/ipv4/ip_forward

# At this point traffic from ns1 will appear in your main network namespace as coming from ip 192.168.69.2 dev virt0, so you can handle it from there.  You will need NAT to make it go somewhere useful.
# In this case I want the traffic to go out through interface vpn1, which is not a default route on my system.

# Add your process-specific routing rules in a non-default table (12345 in this case)
ip route add default dev vpn1 table 12345 proto static scope link metric 50
# Set up a rule to use that table for the traffic coming from that IP, with lower priority than the default table's rule.
ip rule add priority 30000 from 192.168.69.0/24 lookup 12345
# Add the nat, so that the traffic can actually exist on your outbound interface
iptables -t nat -A POSTROUTING -o vpn1 -j MASQUERADE

# At this point traffic from ns1 will go out through interface vpn1. Now you can run command sin that netns to utilize this.

nsenter  --net=/var/run/netns/ns1 your_program
David
  • 338
  • 1
  • 6
0

You might run the process with a specific user and match the packets with the iptable's owner extension. Once matched, you can mark it and use it with another routing table, use POSTROUTING or whatever solution you might like.

This post better explains packet matching with owner.

Mauricio López
  • 944
  • 4
  • 9
  • Thank you, but not quite what I'm looking for. I've edited the question to be more clear than it initially was. – justinzane Jul 07 '15 at 15:53
0

Sadly the iptables extensions manpage (http://ipset.netfilter.org/iptables-extensions.man.html) states no module to fullfill your requirements.

I would suggest the same as Mauricio López.

You could setuid or setgid the target application to a specific user or group, so that no matter who originally started the application, it will always run as a specific user or group):

adduser specialrouteuser
chown specialrouteuser: /usr/bin/testapp
chmod +s /usr/bin/testapp

and then use the iptables owner extension to match that specific UID or GID.

This of course might add other problems or security issues.

mofoe
  • 129
  • 5
0

Well, given that you told us:

Because I'm not able to easily force the process in question to bind to a specific interface, I am trying to achieve the same outcome via routing. Is this possible?

we can start helping you from this very point. Once upon a time in FreeBSD jail system call appeared with the purpose to restrict a process, or group of processes to some sub-section on system resources. Particularly, one could specify an IP-address those "isolated" processes would use for theirs network activity. That was so handy that I really missed this feature in Linux a lot. But Linux has some ways to achieve similar results too:

or, most lightweight would be just tinkering with namespaces manually: https://unix.stackexchange.com/questions/155446/linux-is-there-handy-way-to-exec-a-program-binding-it-to-ip-address-of-choice

poige
  • 9,171
  • 2
  • 24
  • 50