2

I'm running a java-based web server as a non-privileged user. Therefore it listens on ports 8080 and 8443 instead of 80 and 443.

Right now I'm using the following pf rules to forward the ports internally:

rdr pass on $ext_if proto tcp from any to $ext_ip port 80 -> $ext_ip port 8080
rdr pass on $ext_if proto tcp from any to $ext_ip port 443 -> $ext_ip port 8443

(with macros defined for $ext_if and $ext_ip, obviously)

Now I want to add more IPs to the interface (for SSL vHosts) -- what's the best way, to do this? Do I have to repeat those rules for every IP added? Or can I somehow make a rule for "every IP on that interface"?

EDIT: Unfortunately, the IPs are not from the same subnet. I tried listing them in the $ext_ip macro, but I still would prefer a solution where I don't have to add every IP explicitly.

Thanks!

Henning
  • 213
  • 1
  • 3
  • 7
  • `($ext_if)` will dynamically update to reflect the IP address/addresses of that interface making the `$ext_ip` macro necessary. This is very useful if you're doing NAT and your external IP address is assigned via DHCP. –  Dec 06 '11 at 05:29

3 Answers3

1

My research shows that there's no pf.conf clause that will get you this level of one-to-one expansion of rules.

I was hoping that you could do this with macros, which in your case would be something like:

vhost_ips = "{ 198.51.100.4, 198.51.100.5 }"
rdr pass on $ext_if proto tcp from any to $vhost_ips port 80  -> $ext_ip port 8080
rdr pass on $ext_if proto tcp from any to $vhost_ips port 443 -> $ext_ip port 8443

... but if the macro is used more than once on the same line, it actually expands the latter ones to the entire macro, and invokes round-robin:

rdr pass on int0 proto tcp from any to 198.51.100.4 port 80  -> { 198.51.100.4, 198.51.100.5 } port 8080 round-robin
rdr pass on int0 proto tcp from any to 198.51.100.5 port 443 -> { 198.51.100.4, 198.51.100.5 } port 8443 round-robin

... which I'm pretty sure was not what you intended. :-) Tables also appear to be out. The man page explicitly says:

"Tables can also be used for the redirect address of nat and rdr rules and in the routing options of filter rules, but only for round-robin pools."

So unfortunately, it looks as though your only option is to either manually maintain the list, or generate it as a separate file and include it.

Also unfortunately, the include clause is not mentioned in the pf.conf man pages on my 7.4, 8.2 or 9.0-RC2 systems, so if you are running the stock PF that comes with FreeBSD, I believe that they are running the PF imported from OpenBSD 4.5, which doesn't appear to support include ... but just in case, here's a way to generate the include:

$ cat vhost.list
198.51.100.4
198.51.100.5

$ cat gen-vhosts-pf.sh
#!/bin/sh
for ip in `egrep -v ^# /etc/vhost.list`; do
        echo "rdr pass on \$ext_if proto tcp from any to $ip port 80  -> $ip port 8080"
        echo "rdr pass on \$ext_if proto tcp from any to $ip port 443 -> $ip port 8443"
done

$ ./gen-vhosts-pf.sh | sudo tee /etc/pf.conf.vhosts
rdr pass on $ext_if proto tcp from any to 198.51.100.4 port 80  -> 198.51.100.4 port 8080
rdr pass on $ext_if proto tcp from any to 198.51.100.4 port 443 -> 198.51.100.4 port 8443
rdr pass on $ext_if proto tcp from any to 198.51.100.5 port 80  -> 198.51.100.5 port 8080
rdr pass on $ext_if proto tcp from any to 198.51.100.5 port 443 -> 198.51.100.5 port 8443

... which would be imported into pf.conf with:

include "/etc/pf.conf.vhosts"

If you're not running a PF that supports includes, it'll be a little trickier, but you get the idea.

Sorry for the slightly scattered research; I also couldn't find a canonical way to ask PF for its version information, so had to flail around a bit.

EDIT: You may be able to do the including with the load anchor clause, though it appears you will have to repeat your $ext_if macro within the anchor.

Royce Williams
  • 1,362
  • 8
  • 16
0

Assuming all IPs are on the same subnet, you can use Aggregation

$ext_net = "192.168.1.0/24"
arved
  • 453
  • 2
  • 14
0

I don't think you need to do anything special as aliases aren't configured as separate networking devices. This is unlike Linux where you have eth0, eth0:1, eth0:2 that are treated as discrete interfaces. Consequently, the pf rules should expand to apply to all the IP address present on that interface:

# ifconfig sis2 192.168.4.1 netmask 255.255.255.0 alias
# ifconfig sis2
sis2: flags=8843<UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST> mtu 1500
        lladdr 00:00:24:c6:4d:ee
        priority: 0
        media: Ethernet autoselect (100baseTX full-duplex)
        status: active
        inet 192.168.1.1 netmask 0xffffff00 broadcast 192.168.1.255
        inet6 fe80::200:24ff:fec6:4dee%sis2 prefixlen 64 scopeid 0x3
        inet 192.168.4.1 netmask 0xffffff00 broadcast 192.168.4.255

Using the following pf rules...

# allow untrusted -> trusted ssh & http traffic
untrust="sis2"
pass in log on $untrust inet proto tcp from $untrust:network to $trust:network port 22
pass in log on $untrust inet proto tcp from $untrust:network to $trust:network port 80

And this expands to the following...

@32 pass in log on sis2 inet proto tcp from 192.168.1.0/24 to 192.168.0.0/24 port = ssh flags S/SA
@33 pass in log on sis2 inet proto tcp from 192.168.1.0/24 to 192.168.0.0/24 port = www flags S/SA
@34 pass in log on sis2 inet proto tcp from 192.168.4.0/24 to 192.168.0.0/24 port = ssh flags S/SA
@35 pass in log on sis2 inet proto tcp from 192.168.4.0/24 to 192.168.0.0/24 port = www flags S/SA
@36 pass in log on sis1 inet proto tcp from 192.168.0.0/24 to 192.168.0.1 port = ssh flags S/SA

You will need to reapply your pf rules using pfctl but that's about all you have to do to account for aliased IP addresses assuming your macros and rules are correct.

Additionally, you can ignore all aliases on an interface in pf by listing it interface:0.