View previous topic :: View next topic |
Author |
Message |
pablo_supertux Advocate
Joined: 25 Jan 2004 Posts: 2946 Location: Somewhere between reality and Middle-Earth and in Freiburg (Germany)
|
Posted: Wed Jul 31, 2024 10:01 am Post subject: Port forwarding when localhost is involved |
|
|
Hi
I have a project where I have a python script that spawns a modbus tcp "server". Modbus tcp binds normally to port 502. Non-root users cannot bind to ports <=1024 so if I want to run my python script as a non-root user, then I have a couple of options:
1. nc/socat as root. While this is not difficult, it has problems reconnecting when the python scripts restarts. I'd rather not use this
2. use setcap with setcap 'cap_net_bind_service=+ep' /path/to/python but I don't like it, it gives this python interpreter way to much "power", any script would be able to bind to port <= 1024.
3. use iptables to do port forwarding from port 1502 to port 502
I think that the third option is the better option, but I'm having trouble with it. I've looked up in google about it and there are tons of threads in stackoverflow & serverfault but after reading them I'm more confused, because the answers vary wildly.
My network setting:
- I have have an USB-eth (eth1) configured with 192.168.100.1/24
- A tap in0 configured with 192.168.15.1/24 (for virtualbox bridging mode with my VMs)
- I have a DHCP server and a bind server listing on in0 and eth1
Code: |
# /etc/conf.d/net
modules="dhcpcd"
config_eth0="dhcp"
dhcpcd_eth0="-t 40 -4" # Timeout after 10 seconds
tuntap_in0="tap"
config_in0="192.168.15.1/24"
config_eth1="192.168.100.1/24"
# /etc/local.d/baselayout1.start
echo 1 > /proc/sys/net/ipv4/ip_forward
iptables --table nat --append POSTROUTING --out-interface eth0 -j MASQUERADE
iptables --append FORWARD --in-interface in0 -j ACCEPT
|
So these are my problems:
I found this https://www.netfilter.org/documentation/HOWTO/NAT-HOWTO.txt and tried the following command
Code: |
iptables -t nat -A PREROUTING -p tcp --dport 502 -j DNAT --to 127.0.0.1:1502
|
If I do telnet ip 502 (from a VM I used 192.168.15.1 and from a notebook bound to eth1 I used 192.168.100.1), then telnet show "Trying ip ...." and then it hangs.
iptables -t nat -L -v shows this:
Code: |
Chain PREROUTING (policy ACCEPT 89 packets, 10859 bytes)
pkts bytes target prot opt in out source destination
6 360 DNAT tcp -- any any anywhere anywhere tcp dpt:502 to:127.0.0.1:1502
|
Looks good, but something does not work correctly. I found this https://serverfault.com/a/1104711/237453 and after executing
Code: |
echo 1 > /proc/sys/net/ipv4/conf/all/route_localnet
|
then my VM and my notebook can connect to port 502. However my localhost cannot connect to itself on port 502:
Code: |
telnet 127.0.0.1 502
Trying 127.0.0.1...
telnet: connect to address 127.0.0.1: Connection refused
|
I also found this https://stackoverflow.com/a/28170005/1480131. I removed the PREROUTING rule and tried
Code: |
iptables -t nat -A PREROUTING -p tcp --dport 502 -j REDIRECT --to 1502
iptables -t nat -A OUTPUT -p tcp --dport 502 -j REDIRECT --to 1502
|
Now telnet 127.0.0.1 502 works but the VM and the notebook cannot connect to port 502, now they show me "Unable to connect to remote host: Connection refused"
I ended up combining these 3 rules
Code: |
iptables -t nat -A PREROUTING -p tcp --dport 502 -j DNAT --to 127.0.0.1:1502
iptables -t nat -A PREROUTING -p tcp --dport 502 -j REDIRECT --to 1502
iptables -t nat -A OUTPUT -p tcp --dport 502 -j REDIRECT --to 1502
|
and the DNAT rule in the PREROUTING chain must come before the REDIRECT rule, otherwise the VM and my notebook cannot connect.
My question is: is this correct? This seems way more complicated than it should be. Am I just more complicated than it should be?
// edit:
after playing around a bit with the order, I realized that I don't need the REDIRECT rule in the PREROUTING chain, this seems to be more than enough:
Code: |
iptables -t nat -A PREROUTING -p tcp --dport 502 -j DNAT --to 127.0.0.1:1502
iptables -t nat -A OUTPUT -p tcp --dport 502 -j REDIRECT --to 1502
|
Why do I need the REDIRECT rule in the OUTPUT chain if I want to connect on the localhost on port 502? _________________ A! Elbereth Gilthoniel!
silivren penna míriel
o menel aglar elenath,
Gilthoniel, A! Elbereth! |
|
Back to top |
|
|
pietinger Moderator
Joined: 17 Oct 2006 Posts: 5094 Location: Bavaria
|
Posted: Wed Jul 31, 2024 10:17 pm Post subject: |
|
|
pablo_supertux wrote: |
after playing around a bit with the order, I realized that I don't need the REDIRECT rule in the PREROUTING chain, this seems to be more than enough:
Code: | iptables -t nat -A PREROUTING -p tcp --dport 502 -j DNAT --to 127.0.0.1:1502
iptables -t nat -A OUTPUT -p tcp --dport 502 -j REDIRECT --to 1502 |
Why do I need the REDIRECT rule in the OUTPUT chain if I want to connect on the localhost on port 502? |
Because your modbus tcp "server" is listening on 1502 ... and your first packet coming from telnet saying it wants to connect to port 502; this packet must be "rewritten", so in this packet is the new destination port 1502.
You need two rules because you have two types of incoming packets traversing different parts of the kernel/netfilter:
- From Network
- From localhost
Please see this great picture: https://stuffphilwrites.com/fw-ids-iptables-flowchart-v2024-05-22/
(here you find more explanations: https://lewestech.com/mirrors/www.iptables.info/en/structure-of-iptables.html )
What happens if you do (without having the redirect rule in OUTPUT) a "telnet 127.0.0.1 1502" ? _________________ https://wiki.gentoo.org/wiki/User:Pietinger |
|
Back to top |
|
|
pablo_supertux Advocate
Joined: 25 Jan 2004 Posts: 2946 Location: Somewhere between reality and Middle-Earth and in Freiburg (Germany)
|
Posted: Fri Aug 02, 2024 9:43 pm Post subject: |
|
|
thanks, I'll take a closer look later
pietinger wrote: |
What happens if you do (without having the redirect rule in OUTPUT) a "telnet 127.0.0.1 1502" ? |
Without the OUTPUT rule, telnet can connect:
Code: |
telnet localhost 1502
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
^]
telnet> Connection closed.
|
With the 3 rules, telnet connects to either localhost:502 or localhost:1502
// edit: in the graph there are two input sources: "Incoming packet" and "locally generated package". What is the difference? _________________ A! Elbereth Gilthoniel!
silivren penna míriel
o menel aglar elenath,
Gilthoniel, A! Elbereth! |
|
Back to top |
|
|
pietinger Moderator
Joined: 17 Oct 2006 Posts: 5094 Location: Bavaria
|
Posted: Fri Aug 02, 2024 10:22 pm Post subject: |
|
|
pablo_supertux wrote: | // edit: in the graph there are two input sources: "Incoming packet" and "locally generated package". What is the difference? |
If you create a packet from a local application it starts at: "locally generated package" (that is obvious) ... then ... THIS is important ... if it arrives at "Outgoing packet" ... this does not mean the kernel is finished here and gives it to the network device ... it means: Now we check WHO is the destination ... AND if the destination is 127.0.0.1 ... THEN ... THIS packet goes INTO "Incoming packet" ... and the show goes on
So, you have two types of "Incoming packet":
1. Really from network (network adapter/device), OR
2. From the own station
Therefore you have also the two questions: "localhost source?" and "localhost dest?"
The picture would be perfect if there would be a ---------- line from "Outgoing packet" to "Incoming packet" IF FROM localhost TO localhost
And now you see why you must do DNAT in both sections (OUTPUT and PREROUTING; because a local packet will never arrive at DNAT PREROUTING).
(Sorry for my poor english - ask next time in german section ) _________________ https://wiki.gentoo.org/wiki/User:Pietinger |
|
Back to top |
|
|
Hu Administrator
Joined: 06 Mar 2007 Posts: 22625
|
Posted: Sat Aug 03, 2024 12:30 am Post subject: |
|
|
Rather than go through these elaborate games, why not reconfigure the client to expect a port other than 502, so that the Python script can bind to an unprivileged port and the client can connect directly to that unprivileged port? |
|
Back to top |
|
|
pablo_supertux Advocate
Joined: 25 Jan 2004 Posts: 2946 Location: Somewhere between reality and Middle-Earth and in Freiburg (Germany)
|
Posted: Sun Aug 04, 2024 8:11 pm Post subject: |
|
|
@pietinger thaks for the explanation
@hu I have no access to them modbus master and I cannot change/configure it, it expects the slave to listen on port 502 and I didn't want to run my python stack as root (like I've done in the past with other customers). _________________ A! Elbereth Gilthoniel!
silivren penna míriel
o menel aglar elenath,
Gilthoniel, A! Elbereth! |
|
Back to top |
|
|
|