2

I am hoping to use iptables to silently redirect incoming traffic arriving at a privileged port on the public eth interface (public IPv4 address) to a hidden unprivileged port on the same ubuntu box. The ufw firewall is active. There are other options, of course, such as capabilities, or a privileged process copying traffic to the unprivileged port, or a privileged process dropping its privs after bind, etc, but to me at least iptables seems to be the most appealing.

The dummy interface solution in DNAT to 127.0.0.1 with iptables / Destination access control for transparent SOCKS proxy would be perfect for me (once I insert an extra 'dev' keyword into the ip add addr... command). Except for one thing:

  • I must open the firewall up for incoming traffic to the IP of the dummy interface on the hidden port

As far as I can see, this allows others to send incoming traffic directly to that IP:port, should they be able to guess the roughly 40 bits of hidden info (a private IPv4 address + a port).

Is there a solution where no outside traffic can reach that hidden port, unless the original dest IP is the public IP of the box, and the dest port is the privileged port?


[In everyday terms, the dummy interface solution is like having my buddy come to my club, and telling him that here is a VIP pass, take it to the back entrance, and the bouncer will let you in. He will get in, sure, but anyone else may try to fool the bouncer with a fake pass. Can I instead escort my buddy to the back entrance, tell the bouncer he is good, and walk in with him? In other words, can I mark this NATted packet somehow that the firewall rules are bypassed on it?]

  • UFW always allows connections to localhost, so you shouldn't need to do that. Did you actually try it first? – Michael Hampton Feb 11 '21 at 22:13
  • 1
    I do not quite understand what you mean. THe packet I need to get to the hidden port originates from outside. Most online "solutions" redirect these to another port, but that is not a real solution because then you have to open that other port on the firewall (IP stays same, so the new port is public). The only real solution I have seen so far is what I linked to. Which is DNAT to a dummy interface on the same box. Except, that still leaves a hole on the firewall, albeit one that is harder to find. The question is whether one can eliminate that hole. – user12304836 Feb 11 '21 at 22:24
  • Huh? DNAT to a dummy interface? No, you would DNAT to localhost. – Michael Hampton Feb 11 '21 at 22:29
  • E.g., if you redirect port 80 on host 1.2.3.4 to port 8080 on dummy interface 10.11.12.13, then you would do ```*nat -A PREROUTING -p tcp --dport 80 -j DNAT --to-destination 10.11.12.13:8080``` (cannot format lines here for some reason) – user12304836 Feb 11 '21 at 22:30
  • DNAT to localhost (127.0.0.1) to/from outside is dropped by the kernel. It is possible to enable it but that creates a bigger security hole than the one I am trying to close. Or a potentially bigger one. – user12304836 Feb 11 '21 at 22:32
  • It could be, though, that my assumption that packets from outside to a private address would actually make it there is wrong... and then the whole issue is moot. It is just too hard to test that on my current network :/ – user12304836 Feb 11 '21 at 22:50
  • Oh, you're right. You have to use the REDIRECT target, not DNAT. – Michael Hampton Feb 11 '21 at 22:51
  • Have the same problem, I want to redirect 80 to 8080, but I don't want 8080 to be open public. Currently I just do the *nat PREROUTING -j REDIRECT to 8080. I have to also have an ufw rule to then open 8080 or the redirected packets won't arrive, but as soon as I open it, packets destined directly to 8080 also are allowed (of course..). Is the MARK stuff the only way you found to solve this? – BjornW Jul 07 '23 at 08:00

2 Answers2

2

In the meantime I learned that one CAN mark packets (see, e.g., How to set mark on packet when forwarding it in nat prerouting table?), and also learned more about which iptables operations are applied when (https://www.digitalocean.com/community/tutorials/a-deep-dive-into-iptables-and-netfilter-architecture). With these the solution is straightforward:

  1. in /etc/ufw/before.rules, add a MANGLE rule:
*mangle
-F
-A PREROUTING -p tcp -i eth0 -d 1.2.3.4 --dport 80 -j MARK --set-mark 0x401
COMMIT
  1. in the same file insert a redirect into the NAT table rules (*nat section) with the line
-A PREROUTING -p tcp --dport 80 -j REDIRECT --to-port 8080
  1. and finally, insert into the ufw-before-input chain of the FILTER table (*filter section) with the line
-A ufw-before-input -m mark --mark 0x401 -j ACCEPT
  1. restart ufw
services ufw restart

There is no need to open any ports, incoming packets to 1.2.3.4:80 get redirected to 1.2.3.4:8080 and are explicitly greenlighted through the firewall. The time order of iptables operations on the packet is: mark, redirect, let through.

0

You can skip the dummy interface and REDIRECT such traffic to the localhost IP address.

In the nat table:

-A PREROUTING -p tcp --dport 80 -j REDIRECT --to-ports 8080

Then you tell ufw to allow traffic to that port, but only destined to the localhost IP address.

sudo ufw allow to 127.0.0.1 port 8080 proto tcp
Michael Hampton
  • 244,070
  • 43
  • 506
  • 972
  • 1
    That redirect does not work. The redirected packet preserves dest ip, so you need to listen on the original interface at the new port - AND - have that port wide open on the firewall (then it works, confirmed). This is definitely not what I am after. – user12304836 Feb 12 '21 at 08:49
  • This way need to open both 80 and 8080 ports on ufw ! that is not a good solution, any workaround that on that way port 8080 does not needed to open on ufw ? – alireza Feb 08 '23 at 04:35