Routing
The primary way to decide where the kernel packets is the routing table (ip route
and friends), not the firewall rules (iptables
, nftables
). Once you've enabled IP forwarding with net.ipv4.ip_forward = 1
, then the kernel will process incoming packets through the routing table and send them back out. So if you want traffic to 10.0.0.2 to go through eth0, regardless of where it came from:
ip route add 10.0.0.2/32 dev eth0
Now, by default, when the kernel sees traffic coming in on eth0 and going right back out the same, it'll send an ICMP redirect to tell the source machine "hey, this is inefficient! send it directly!" You need to turn this off (net.ipv4.conf.eth0.send_redirects = 0
) It also checks the source address to make sure it came from where it expected; you may need to turn this off as well (net.ipv4.conf.eth0.rp_filter = 0
).
Since this goes through the kernel routing machinery, required stuff like decreasing the IP TTL will be done. But stuff like the source and destination IP address is not changed.
Routing + NAT
If you additionally need the source or destination IP addresses to be changed, you add NAT on top. For example, if you need the source IP address to be this machine, you could add your:
iptables -t nat -A POSTROUTING --out-interface eth0 -j MASQUERADE
Note that unless you've changed the default, FORWARD should already accept. If not, you can add your rule (or alternatively, change the default).
NAT + Routing
You can also change the destination IP address when the packet comes in, which will change how its routed (because this change is done before routing sees it). This looks like:
iptables -t nat -A PREROUTING -s 10.0.0.1 -j DNAT --to-dest 10.0.0.2
Note that you can't use --out-interface
here because the out interface isn't known until after routing. You can use --in-interface
though.
Existing tools
You should also take a look at iperf3 and the packet generator.
MIRROR
target that did what it sounds like you're asking for, but it was removed (for, in general, being a bad idea). Could you clarify why you want to do this? It really sounds like something that you should never actually want to do, and I'm wondering if there isn't a much better way to achieve your goal. – derobert Nov 10 '16 at 17:13dev_queue_xmit()
to send the traffic back on the interface, so we've verified that it does come back, but it'd be better if we didn't have to make changes. – user2233706 Nov 10 '16 at 17:17