David
2007-12-06 04:02:31 UTC
Hello, please excuse the length of my question, and I hope that this is
an appropriate place to ask.
I have a workstation that has two interfaces connected to two private
networks, 192.168.0.0/24 and 192.168.1.0/24, each of which has a
separate masquerading gateway to the internet, something like as follows:
+-----------> to internet
|
router0
192.168.0.1
|
|
192.168.0.100
+-----<eth0>----+
| |
| Workstation |
| |
+-----<eth1>----+
192.168.1.100
|
|
192.168.1.1
router1
|
+-----------> to internet
I want to control which traffic to/from processes running on the
workstation uses which interface (i.e. outbound path to internet) on a
process-by-process basis, without the cooperation of the program (i.e.
rather than having the program bind to a particular local interface,
when I start a program I want to be able to choose one or the other
interface, and have all of that process's traffic get routed through
that interface).
My idea of how to accomplish this (I'm open to alternate suggestions) is
to set up a default route via one gateway, e.g. router0, then a
designated group-ID via the iptables 'owner' match module to mark
packets from processes owned by a user in that group, and use the
iproute2 tables to route those packets via the other gateway (router1).
(it seems that ipt_ROUTE is frowned upon and I've never been able to get
it to work anyhow.) So, after each interface is up on its sub-net and
the default route is set, my commands are like this:
iptables --table mangle --append OUTPUT --match owner --gid-owner
alt-route-group -j MARK --set-mark 1
ip rule add fwmark 1 pref 10001 table 100
ip route add default via router1 table 100
It's not a very elegant solution, but it seems like it should work; yet
I have a problem: when I run a program sudo'd to the designated
user/group, its traffic does indeed get matched, marked, and exits via
the "alternate" interface (eth1), bound for the alternate gateway
(router1), but when I examine by sniffing the interface, I find that the
packets' source IP address is that of the default interface (eth0,
192.168.0.100). Of course this prevents proper routing of any return
packets.
I tried forcing the source-address in the routing table entry with 'src':
ip route add default via router1 dev eth1 src 192.168.1.100 table 100
But it still showed the source as 192.168.0.100 (eth0's address), even
though the packet exited via eth1, and I verified that their destination
ethernet address is bound for router1.
So I wonder if anyone knows what's wrong? I would also be interested in
other suggestions for how to do per-process routing (but I'd like to get
this approach working even if I abandon it). Any help is greatly
appreciated.
My tables:
~ # iptables --table mangle --list OUTPUT
Chain OUTPUT (policy ACCEPT)
target prot opt source destination
MARK all -- anywhere anywhere OWNER
GID match alt-route-group MARK set 0x1
~ # ip rule show
0: from all lookup local
10001: from all fwmark 0x1 lookup 100
32766: from all lookup main
32767: from all lookup default
~ # ip route show table main
192.168.1.0/24 dev eth1 proto kernel scope link src 192.168.1.100
192.168.0.0/24 dev eth0 proto kernel scope link src 192.168.0.100
169.254.0.0/16 dev eth0 scope link
default via 192.168.0.1 dev eth0
~ # ip route show table 100
default via 192.168.1.1 dev eth1 src 192.168.1.100
The command:
~ # sudo -u alt-route-user ping google.com
PING google.com (64.233.187.99) 56(84) bytes of data.
--- google.com ping statistics ---
4 packets transmitted, 0 received, 100% packet loss, time 3010ms
/tmp #
Produces the trace:
~ # tshark -n -i eth1 icmp
Capturing on eth1
0.000000 192.168.0.100 -> 64.233.187.99 ICMP Echo (ping) request
1.009611 192.168.0.100 -> 64.233.187.99 ICMP Echo (ping) request
2.009777 192.168.0.100 -> 64.233.187.99 ICMP Echo (ping) request
3.013895 192.168.0.100 -> 64.233.187.99 ICMP Echo (ping) request
4 packets captured
~ #
Thanks in advance,
David
an appropriate place to ask.
I have a workstation that has two interfaces connected to two private
networks, 192.168.0.0/24 and 192.168.1.0/24, each of which has a
separate masquerading gateway to the internet, something like as follows:
+-----------> to internet
|
router0
192.168.0.1
|
|
192.168.0.100
+-----<eth0>----+
| |
| Workstation |
| |
+-----<eth1>----+
192.168.1.100
|
|
192.168.1.1
router1
|
+-----------> to internet
I want to control which traffic to/from processes running on the
workstation uses which interface (i.e. outbound path to internet) on a
process-by-process basis, without the cooperation of the program (i.e.
rather than having the program bind to a particular local interface,
when I start a program I want to be able to choose one or the other
interface, and have all of that process's traffic get routed through
that interface).
My idea of how to accomplish this (I'm open to alternate suggestions) is
to set up a default route via one gateway, e.g. router0, then a
designated group-ID via the iptables 'owner' match module to mark
packets from processes owned by a user in that group, and use the
iproute2 tables to route those packets via the other gateway (router1).
(it seems that ipt_ROUTE is frowned upon and I've never been able to get
it to work anyhow.) So, after each interface is up on its sub-net and
the default route is set, my commands are like this:
iptables --table mangle --append OUTPUT --match owner --gid-owner
alt-route-group -j MARK --set-mark 1
ip rule add fwmark 1 pref 10001 table 100
ip route add default via router1 table 100
It's not a very elegant solution, but it seems like it should work; yet
I have a problem: when I run a program sudo'd to the designated
user/group, its traffic does indeed get matched, marked, and exits via
the "alternate" interface (eth1), bound for the alternate gateway
(router1), but when I examine by sniffing the interface, I find that the
packets' source IP address is that of the default interface (eth0,
192.168.0.100). Of course this prevents proper routing of any return
packets.
I tried forcing the source-address in the routing table entry with 'src':
ip route add default via router1 dev eth1 src 192.168.1.100 table 100
But it still showed the source as 192.168.0.100 (eth0's address), even
though the packet exited via eth1, and I verified that their destination
ethernet address is bound for router1.
So I wonder if anyone knows what's wrong? I would also be interested in
other suggestions for how to do per-process routing (but I'd like to get
this approach working even if I abandon it). Any help is greatly
appreciated.
My tables:
~ # iptables --table mangle --list OUTPUT
Chain OUTPUT (policy ACCEPT)
target prot opt source destination
MARK all -- anywhere anywhere OWNER
GID match alt-route-group MARK set 0x1
~ # ip rule show
0: from all lookup local
10001: from all fwmark 0x1 lookup 100
32766: from all lookup main
32767: from all lookup default
~ # ip route show table main
192.168.1.0/24 dev eth1 proto kernel scope link src 192.168.1.100
192.168.0.0/24 dev eth0 proto kernel scope link src 192.168.0.100
169.254.0.0/16 dev eth0 scope link
default via 192.168.0.1 dev eth0
~ # ip route show table 100
default via 192.168.1.1 dev eth1 src 192.168.1.100
The command:
~ # sudo -u alt-route-user ping google.com
PING google.com (64.233.187.99) 56(84) bytes of data.
--- google.com ping statistics ---
4 packets transmitted, 0 received, 100% packet loss, time 3010ms
/tmp #
Produces the trace:
~ # tshark -n -i eth1 icmp
Capturing on eth1
0.000000 192.168.0.100 -> 64.233.187.99 ICMP Echo (ping) request
1.009611 192.168.0.100 -> 64.233.187.99 ICMP Echo (ping) request
2.009777 192.168.0.100 -> 64.233.187.99 ICMP Echo (ping) request
3.013895 192.168.0.100 -> 64.233.187.99 ICMP Echo (ping) request
4 packets captured
~ #
Thanks in advance,
David