Q:

How to hijack traffic to a port using iptables

I have an application listening on port 2000. I want to proxy all traffic to this port (originating locally) to a different port, say 4000.
Right now i am doing something like this.
iptables -t nat -A OUTPUT -p tcp --dport 2000 -d 127.0.0.1 -j DNAT --to-destination 127.0.0.1:4000

This works as long as there is nothing listening on 2000. if I telnet to 2000, traffic is routed to 4000 as expected. But if there is something listening on 2000, the traffic is not hijacked/proxied. Is there a way to achieve this?

A:

It looks like the nc version you are using uses IPv6 by default. When you have nc listening on port 2000 the client connects to that bypassing your IPv4-only DNAT rule.
When nothing is listening on port 2000 it still tries to connect to that using IPv6 but fails, and then falls back to IPv4 where the DNAT rule will send it to the instance listening on port 4000.
The best solution I can think of at the moment is to simply create equivalent rules for both IPv4 and IPv6:
iptables -t nat -A OUTPUT -p tcp --dport 2000 -d 127.0.0.1 -j DNAT --to-destination 127.0.0.1:4000
ip6tables -t nat -I OUTPUT -p tcp --dport 2000 -d ::1 -j DNAT --to-destination '[::1]:4000'

