Get my NAT IPFW firewall for jail not to work from outside

Hello, in short:
A Jail is installed. Can start and stop and connect to it. Inside its running an Apache web server. Some simple Website exists.
Starting the jail and make a test like this works:
printf "HEAD / HTTP/1.1\r\nHost: <www.example.com>t\r\n\r\n"
also telnet <www.example.com> 80
Code:
Trying "jail-IP"...
Connected to "jail-IP".
Escape character is '^]'.
GET /index.htm HTTP/1.1
host: www.example.com
<line feed>
[Enter]
[Enter]
Output:
Code:
HTTP/1.1 200 OK
    Date: Mon, 06 Jun 2022 16:38:00 GMT
    Server: Apache..........................Webseite
Problem: doing this from outside the host do not work. I have oriented me, by this example:
https://www.ohreally.nl/2021/02/08/freebsd-jails-a-complete-example/ but using IPFW as firewall. He uses "pf". So I try to translate that to "pf", but I can not find out, what I have done wrong.
Code:
#-----------------------------------------------------------------------
#                NAT for Jails (IPFW)
cmd="ipfw -q add"
nwinterface="<my vnet interface>"

${cmd} 410 nat 1 ip from any to me in via $nwinterface
${cmd} 420 nat 1 ip from Jail.IP.0.0/27 to any out via $nwinterface

#for web server ports
ipfw nat 1 config if $nwinterface redirect_port tcp Jail.IP.IP.IP:80 80
ipfw nat 1 config if $nwinterface redirect_port tcp Jail.IP.IP.IP:443 443
#

# Allow out non-secure standard www function
${cmd} 600 allow tcp from any to any 80 out via $nwinterface setup keep-state

# Allow out secure www function https over TLS SSL
${cmd} 620 allow tcp from any to any 443 out via $nwinterface setup keep-state
There are also other firewall settings, but not for NAT, or for the web server. I have a web server running on the the host, and with this 'other firewall settings' there are no problems for it. Sure the Host Apache is stopped, when I test the jail, so the Apache ports are free for the jail.

What could be wrong in my configuration - many thanks.
 
Last edited by a moderator:
You need to clarify: is this vnet/VIMAGE jail, or traditional jail?

If it is vnet, then it is usually put onto some bridge, and will then behave like an individual, separate host with it's own IP address(es), and also should get it's own ipfw running inside. No special jail treatment necessary, it gets treated like an independent host on the network.

If it is traditional jail, then it uses an IP address from the host, that is usually on the lo interface. It is more difficult to run NAT in these circumstances and grab the correct flows. You will need to dry-run test this with logging, go through each flow incoming and outgoing, and see with ipfw show where it gets counted.
 
You need to clarify: is this vnet/VIMAGE jail, or traditional jail?
Thanks for the answer. It is traditional jail.
You will need to dry-run test this with logging, go through each flow incoming and outgoing, and see with ipfw show where it gets counted.
Can you give me an example how to do that?
 
Thanks for the answer. It is traditional jail.

Can you give me an example how to do that?
Sorry being late, I was away for a few days.

You can observe the counters on the rules and, after doing a test connect, see how many packets match each rule:
Code:
# ipfw show 8450-8470
08455 443289 33618813 divert 8677 // [FILTER][suricata] GW.uplink[37]
08465 443288 33618733 divert 8668 // [FILTER][natd] GW.uplink[37]
# ipfw zero 8455
Entry 8455 cleared.
# ipfw zero 8465
Entry 8465 cleared.
# ipfw show 8450-8470
08455      5      348 divert 8677 // [FILTER][suricata] GW.uplink[37]
08465      0        0 divert 8668 // [FILTER][natd] GW.uplink[37]
To get a clue from the counters, in production the regular traffic will need to be somehow stopped, otherwise some counters will continuousely increment.

You can temporarily insert extra rules that do nothing else than count (for some condition), to see if some test traffic does appear before and after a certain rule:
Code:
# ipfw add 8454 count proto tcp dst-ip me
08454 count proto tcp dst-ip me
# ipfw add 8456 count proto tcp dst-ip me
08456 count proto tcp dst-ip me
# ipfw show 8450-8470
08454      0        0 count proto tcp dst-ip me
08455    281    22060 divert 8677 // [FILTER][suricata] GW.uplink[37]
08456      0        0 count proto tcp dst-ip me
08465    276    21712 divert 8668 // [FILTER][natd] GW.uplink[37]

You can activate logging (in /etc/rc.conf add firewall_logging="YES", or temporarily with sysctl net.inet.ip.fw.verbose=1).
Now you can add the log option to any rule:
Code:
# ipfw add 8454 count log proto tcp dst-ip me
08454 count log proto tcp dst-ip me
# ipfw add 8456 count log proto tcp dst-ip me
08456 count log proto tcp dst-ip me
# ipfw show 8450-8470
08454      0        0 count log proto tcp dst-ip me
08455    602    46152 divert 8677 // [FILTER][suricata] GW.uplink[37]
08456      0        0 count log proto tcp dst-ip me
08465    597    45804 divert 8668 // [FILTER][natd] W.uplink[37]
Each matched packet should now be reported into /var/log/security.
You can add the log option to your nat rules as well.

With such in place, You can then run your telnet test, and follow the individual packets through the ruleset, see if they enter the ruleset, if they reach the nat rule, if they leave at the nat rule or how they look after it. (With sysctl net.inet.ip.fw.one_pass=1 packets should leave at the nat rule, otherwise they continue through the further rules.)
There will be an initiating SYN packet, and a responding SYN ACK packet in the opposite direction. These are treated individually, so you need to check each to see where it gets stuck.
 
Sorry for the late response.

I figured out that I get a general problem with telnet on port 80 from my Windows client. But I see that the IPFW line
"${cmd} 410 nat 1 ip from any to me in via $nwinterface"
get used, when I do the telnet command.

I try curl <mydomain.com> from both: the FreeBSD server and from Windows client
1) with the web server running on the host. Both are working and give an output.
2) with the web server running in the jail. Both are NOT working and give no output.

When I am using the jail IP curl Jail.IP.IP.IP on the host, it works also with the jail. But when I am using the domain name curl <mydomain.com> it give the output:
* Trying <Host.IP.IP.IP>:80
and hangs.

The request for my domain is right translated to the host IP. But it seems the redirect_port setting is not working.
With ipfw list I see no "config" settings for the "nat 1" I had done in the rules.

So again I think some of my IPFW NAT configuration (see at beginning) is wrong, but I can not figured out what it is.
Any help?
 
After long trying a found a solution from some IPFW examples to reach the web server in the jail. But it runs only without any other firewall commands:
ipfw -q -f flush
ipfw nat show config
ipfw nat 1 delete
/etc/rc.d/ipfw restart
# /etc/ipfw.rules
#
#-----------------------------------------------------------------------
# NAT for Jails (IPFW)
cmd="ipfw -q add"
nwinterface="<my host network interface>"

#sh /etc/rc.firewall workstation

ipfw nat 1 config if $nwinterface redirect_port tcp Jail.IP.IP.IP:443 443 redirect_port tcp Jail.IP.IP.IP:80 80
${cmd} 410 nat 1 ip from Jail.IP.0.0/27 to any out via $nwinterface
${cmd} 420 nat 1 ip from any to HOST.IP.IP.IP
That is all what it needs. But there is no more a firewall, and that make no sense: to have a jail for more security and can not use the firewall settings

I use /etc/rc.firewall with sh /etc/rc.firewall workstation. But then the connection to the web server in the jail get broken. I tested it with:
curl -v -m 5 www.myvirtdomain.tld and
curl -v -m 8 -k https://www.433domain.tld

I found out that there are some rules in the "workstation" set, that block it:
0100 allow ip from any to any via lo0
1200 allow tcp from me to any established
1300 allow tcp from me to any setup keep-state :default

#also these usefull rules

# ${cmd} 03000 deny ip from any to any not verrevpath in
# This rule drops all incoming packets that appear to be coming to the
# system on the wrong interface. For example, a packet with a source address
# belonging to a host on a protected internal network would be dropped if
# it tried to enter the system from an external interface.
#
# The antispoof option could be used to do similar like above "verrevpath"
# but more restricted:
#
${cmd} 03000 deny ip from any to any not antispoof in

I like not change the file /etc/rc.firewall nor copy all rules form it to my script.

How can I fixed that problem?
What is wrong with these /etc/rc.firewall settings above in combination with my script settings?
Hoe can I use the antispoof rule again, with the new nat rules for the jail ?
 
Back
Top