IPFW ipfw fwd does not work - internal port forward

Hi,
I'm trying to get a node.js application running as non-root on port 3080. But I want it to get reached by port 80 from extern. The easiest method I guessed is using ipfw fwd. In the thread https://forums.freebsd.org/threads/ipfw-fwd-with-generic-kernel.41243/#post-266748 post #5 assumed the fwd function works in generic kernel. But I'm not able to get it work.
Can anybody confirm it should work with generic kernel? Here is my ipfw configuration:
Code:
#!/bin/sh

# Flush out the list before we begin
ipfw -q -f flush

# Set rules command prefix
cmd="ipfw -q add"
pif="vtnet0"     # interface name of NIC attached to Internet

# No restrictions on Loopback Interface
$cmd 00002 allow all from any to any via lo0

# Allow dynamic traffic
$cmd 00003 check-state

# Redirect HTTP ports to internal ports
$cmd 00110 fwd 127.0.0.1,3080 all from any to me 80 in via $pif

# Allow every outgoing traffic
$cmd 00200 allow all from me to any out via $pif keep-state

# Allow incomming SSH
$cmd 00300 allow tcp from any to me 22 in via $pif limit src-addr 2

# Block every other incomming traffic
$cmd 00900 deny all from any to me in via $pif
And I've tried to open 3080 and 80 regulary and to replace 127.0.0.1 with the servers public IP, but all this also doesn't work.
The /boot/loader.conf contains:
Code:
ipfw_load="YES"
ipfw_nat_load="YES"
net.inet.ip.fw.default_to_accept="1"
And /etc/sysctl.conf:
Code:
net.inet.ip.forwarding=1
net.inet.ip.fastforwarding=1
net.inet6.ip6.forwarding=1

Am I doing something wrong? If my attempt is not possible, what's the easiest way (but also secure) to get my non-root application reached with privileged ports, without compiling a custom kernel?

Kind regards

Zabrah
 
Code:
net.inet.ip.forwarding=1
net.inet6.ip6.forwarding=1
Not related to your issue but you should use this in rc.conf instead:
Code:
gateway_enable="YES"
ipv6_gateway_enable="YES"
And I would recommend NOT enabling IPv6 forwarding if there's no need for it (your configuration seems to be IPv4-only).


what's the easiest way (but also secure) to get my non-root application reached with privileged ports, without compiling a custom kernel?
A common solution is to put an nginx or Apache in front of it and proxy the requests to the node application. That same trick is used for applications like Jenkins (java application) or Gitlab (Ruby on Rails) for example.

Note that you need to verify the forwarding (which looks fine) from outside your network. Hairpinning requires additional configuration. Also keep your internet modem/router in mind. These usually are already configured for NAT and thus a port needs to be forwarded there too. Double NAT (once on the modem/router and once the FreeBSD host) should be avoided as it's a pain to maintain.
 
Thank you. But after adding this, it still doesn't work.

Nginx was my first thought, but I wanted to experiment with a connection direct as possible.
It's still for testing and learning. So I thing, a direct connection would be faster, since I want to use a low end server.

The server is not part of a local network. It's just a VPS reachable by a public IP. The forwarding should only happen inside the server. I thought, ipfw fwd changes the port of the packet and gives it to my application, the application sees the packet as if it received it directly and its answer is pushed directly through the interface without any further forwarding. Isn't it?
I made my application logging incoming connections, but it seems not to get any request in the first place.
 
The server is not part of a local network. It's just a VPS reachable by a public IP.
Ok, that's good, then we don't need to worry about any additional NAT or forwarding.

I thought, ipfw fwd changes the port of the packet and gives it to my application, the application sees the packet as if it received it directly and its answer is pushed directly through the interface without any further forwarding. Isn't it?
NAT or port forwarding works by changing the source address (with NAT) or the destination port (forwarding) of the actual packet. Then it's pushed through according the system's routing table. The firewall keeps track of the translated packets and will 'undo' the translation on the return packets. A firewall doesn't route, that's the system's job. And it's perfectly fine to translate a destination port to any other port (80 on outside to 3080 inside).

I made my application logging incoming connections, but it seems not to get any request in the first place.
The best tool for that job is tcpdump(1), which allows you to look at the actual network packets. Look at the packets on the incoming interface, if there's nothing coming in there's obviously nothing to translate. If you can see the packets come in then check your rule set for hits.
 
I figured it out! Thank you for your tip with tcpdump. It's info brought me the idea to add "keep-state" to the "fwd". Now with $cmd 00110 fwd 127.0.0.1,3080 all from any to me 80 in via $pif keep-state it works.
 
Back
Top