Gentoo Forums
Gentoo Forums
Gentoo Forums
Quick Search: in
Port forwarding when localhost is involved
View unanswered posts
View posts from last 24 hours

 
Reply to topic    Gentoo Forums Forum Index Networking & Security
View previous topic :: View next topic  
Author Message
pablo_supertux
Advocate
Advocate


Joined: 25 Jan 2004
Posts: 2942
Location: Somewhere between reality and Middle-Earth and in Freiburg (Germany)

PostPosted: Wed Jul 31, 2024 10:01 am    Post subject: Port forwarding when localhost is involved Reply with quote

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
View user's profile Send private message
pietinger
Moderator
Moderator


Joined: 17 Oct 2006
Posts: 4843
Location: Bavaria

PostPosted: Wed Jul 31, 2024 10:17 pm    Post subject: Reply with quote

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
View user's profile Send private message
pablo_supertux
Advocate
Advocate


Joined: 25 Jan 2004
Posts: 2942
Location: Somewhere between reality and Middle-Earth and in Freiburg (Germany)

PostPosted: Fri Aug 02, 2024 9:43 pm    Post subject: Reply with quote

pietinger wrote:


Please see this great picture: https://stuffphilwrites.com/fw-ids-iptables-flowchart-v2024-05-22/



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
View user's profile Send private message
pietinger
Moderator
Moderator


Joined: 17 Oct 2006
Posts: 4843
Location: Bavaria

PostPosted: Fri Aug 02, 2024 10:22 pm    Post subject: Reply with quote

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 :lol:

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 :lol: :P )
_________________
https://wiki.gentoo.org/wiki/User:Pietinger
Back to top
View user's profile Send private message
Hu
Administrator
Administrator


Joined: 06 Mar 2007
Posts: 22382

PostPosted: Sat Aug 03, 2024 12:30 am    Post subject: Reply with quote

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
View user's profile Send private message
pablo_supertux
Advocate
Advocate


Joined: 25 Jan 2004
Posts: 2942
Location: Somewhere between reality and Middle-Earth and in Freiburg (Germany)

PostPosted: Sun Aug 04, 2024 8:11 pm    Post subject: Reply with quote

@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
View user's profile Send private message
Display posts from previous:   
Reply to topic    Gentoo Forums Forum Index Networking & Security All times are GMT
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum