I'm trying to use pf with NAT for a home firewall, with a dialup ppp
connection to my ISP (and thence to the internet).  Everything is fine
(apart from the insecurity) when I use a test "NAT + pass-all-traffic"
pf ruleset, but when I enable a proper NAT+filtering ruleset, all traffic
on the ppp link is blocked.  I wonder if anyone can offer any suggestions
as to what I'm doing wrong and/or what I should be doing to get things
working.


The network setup
=================

Basically, I have a home network with a pair of OpenBSD machines and
an MS-Windows machine which I'd like to give "reasonably safe" access
to the internet.  I'm using static addresses in the the 192.168.105.0/24
private address space for all these machines, split into 192.168.105.0/25
for the Unix machines and 192.168.105.128/25 for the Windows ones.

The computers are
* osmium (192.168.105.2) currently runs OpenBSD 3.4-stable, and will
  go to 3.5-stable soon.  It's the firewall/router: it runs pf, has IP
  forwarding enabled, and has the dialup ppp link to my ISP and thence
  to the internet.
* cp (192.168.105.1) runs OpenBSD 3.5-stable.
* libby (192.168.105.129) runs MS Windows XP. :(

My configuration is this:

          +-----------
cp -------| ethernet |
          |          |
libby ----|    hub   |
          +-----------               +--- ISDN connection to ISP/internet
                |                    |
                |                    |
          +---------------------------------+
          |    rl0                  tun0    |
          |             osmium              |
          +---------------------------------+

For testing purposes, right now libby isn't connected, i.e. I'm just
dealing with the two OpenBSD machines cp and osmium.

The ISDN box (a Zyxel Omni TA128) is connected to osmium's serial port,
and supports a standard "AT" modem command set, so as far as osmium's
software is concerned it's just an ordinary modem.  I'm using the ppp(8)
userland ppp(8) system.  I am NOT using ppp(8)'s builtin NAT or packet
filtering capabilities -- I'm using pf for that.  When ppp(8) is running,
osmium talks to my ISP over interface tun0, using dhcp to get a dynamic
IP address.

With pf disabled everything works as expected:
* osmium and cp can communicate with each other (ping and ssh are ok)
* osmium can access the internet fine (ping, ssh, and web browsers are ok)


The pf setup
============

The firewall policy is simple:
* home Unix machines are allowed full access to the internet
* home Windows machine should be allowed web browsing access to the
  internet
* no outside machines are allowed any access to any of the home machines

The basic idea for the pf ruleset is for osmium to NAT the internal
network, with the NAT rules tagging packets UNIX or WINDOWS depending
on which subnet they come from.  Later filtering rules can then use
these tags to give the Unix subnet full access to the internet, and
limit the Windows subnet to just web browsing.

Based on a very helpful comp.unix.bsd.openbsd.misc posting from Daniel
Hartmeier last year, I've added 'log' to all my filtering rules
        [Alas, every place I've tried adding 'log' to my NAT
        rules gives a syntax error. :(  Is there a clever
        syntax for logging in a NAT rule, and if so, what
        FM should I have R-ed to learn about it?]
for help in debugging, and I'm using
   tcpdump -n -e -ttt -i pflog0
on osmium to watch packet flows in real time.


pf with a pass-everything ruleset
=================================

To check that I have the NAT working correctly, I first tried an test
pf ruleset which does NAT and then passes all traffic:

   # macros
   if_private = "rl0"
   if_outside = "tun0"
   if_all = "{" $if_private $if_outside "}"
   addr_private_us      = $if_private   # our addr on private network
   addr_private         = "192.168.105.0/24"
   addr_private_unix    = "192.168.105.0/25"
   addr_private_windows = "192.168.105.128/25"

   ##########################################################################

   # scrub all packets
   scrub in log all

   ##########################################################################

   # NAT anything outgoing from our private network to the outside interface
   nat on $if_outside from $addr_private_unix    tag UNIX    -> ($if_outside)
   nat on $if_outside from $addr_private_windows tag WINDOWS -> ($if_outside)

   ##########################################################################

   # allow all traffic
   pass in  log all
   pass out log all

With this ruleset everything is fine (apart from the insecurity): both
osmium and cp have full access to the internet.  For example, in a ppp
session where 'ifconfig tun0' showed

   tun0: flags=8011<UP,POINTOPOINT,MULTICAST> mtu 1524
           inet 145.254.62.42 --> 145.253.1.90 netmask 0xffffff00 

here's a tcpdump of first osmium, then cp, pinging our web server at work:

   Jun 21 12:27:31.080918 rule 1/0(match): pass out on tun0: 145.254.62.42 > 
194.94.224.107: icmp: echo request
   Jun 21 12:27:31.143322 rule 0/0(match): pass in on tun0: 194.94.224.107 > 
145.254.62.42: icmp: echo reply
   Jun 21 12:27:34.411740 rule 0/0(match): pass in on rl0: 192.168.105.1 > 
194.94.224.107: icmp: echo request
   Jun 21 12:27:34.411776 rule 1/0(match): pass out on tun0: 145.254.62.42 > 
194.94.224.107: icmp: echo request
   Jun 21 12:27:34.483569 rule 1/0(match): pass out on rl0: 194.94.224.107 > 
192.168.105.1: icmp: echo reply

An oddity here:  When cp pings I see the outgoing ICMP echo request
packet first come in on osmium's rl0, then out on osmium's tun0.  But
for the ICMP echo reply, I don't see it come in on osmium's tun0, only
going out on osmium's rl0.  Can anyone explain why this is the case?


pf with a filtering ruleset
===========================

Now for the problem:  For real use I've defined a pf ruleset which does
NAT and some filtering (and once I get things working I'll add additional
filtering rules for the Windows subnet):

   # macros
   if_private = "rl0"
   if_outside = "tun0"
   if_all = "{" $if_private $if_outside "}"
   addr_private_us      = $if_private   # our addr on private network
   addr_private         = "192.168.105.0/24"
   addr_private_unix    = "192.168.105.0/25"
   addr_private_windows = "192.168.105.128/25"
   
   ##########################################################################
   
   # scrub all packets
   scrub in log all
   
   ##########################################################################
   
   # NAT anything outgoing from our private network to the outside interface
   nat on $if_outside from $addr_private_unix    tag UNIX    -> ($if_outside)
   nat on $if_outside from $addr_private_windows tag WINDOWS -> ($if_outside)
   
   ##########################################################################
   
   # default = block all traffic
   block in  log all
   block out log all
   
   # allow everything on our loopback interface (overrides antispoof rule below)
   pass quick log on lo0 all
   
   # block spoofed traffic
   # ... can't use standard antispoof rules for tun0 because they
   #     block *all* traffic if tun0 doesn't have any address assigned
   #     (eg when ppp link is down)
   antispoof log for $if_private
   block in log on tun0 from $addr_private
   block in log on tun0 from localhost
   
   # allow arbitrary connections from local unix machines to us
   pass in log on $if_private from $addr_private_unix to $addr_private_us keep state
   
   # allow arbitrary connections from local unix machines to outside
   # ... due to NAT, these show up as ougoing from us on ($if_outside)
   pass out log on $if_outside tagged UNIX keep state
   
   # allow arbitrary connections initiated from localhost
   pass out log on $if_all from {localhost,$addr_private_us} keep state

With this ruleset loaded, osmium and cp can still communicate fine, but
neither osmium nor cp can access the internet (all packets are blocked).
Here's a tcpdump of the same pings as before (after loading the new pf
ruleset):

   Jun 21 12:28:44.412618 rule 1/0(match): block out on tun0: 145.254.62.42 > 
194.94.224.107: icmp: echo request
   Jun 21 12:28:49.020084 rule 0/0(match): block in on rl0: 192.168.105.1 > 
194.94.224.107: icmp: echo request
   Jun 21 12:29:12.435867 rule 0/0(match): block in on tun0: 145.254.225.99 > 
145.254.62.42: icmp: echo request

Notice that the packets are being blocked by rules 0 and 1, which are
the "default = block all traffic" ones in the ruleset.  That is, the
later rules which are supposed to filter the traffic aren't matching. :(

My basic question is, can anyone point me to what's going wrong here
(i.e. why aren't the later rules matching) and/or how to fix it?
I've read all the FMs I can find, including the (excellent) pf FAQ
and man pages, and Jacek Artymiak's "Building Firewalls with OpenBSD
and PF [2nd edition]", but so far to no avail.

More generally, is the basic concept of using the NAT rules to tag
packets, and later using those tags for further filtering, a reasonable
way to implement my firewall policy?


Some other strange packets
==========================

As well as the ICMP echo/reply packets, tcpdump also shows some other
slightly-suspicious packets being blocked:

   Jun 21 12:29:24.515801 rule 0/0(match): block in on tun0: 68.167.211.60.60313 > 
145.254.62.42.445: S 2872090282:2872090282(0) win 64240 <mss 1380,nop,nop,sackOK> (DF)
   Jun 21 12:29:33.446577 rule 0/0(match): block in on tun0: 68.167.211.60.60313 > 
145.254.62.42.445: S 2872090282:2872090282(0) win 64240 <mss 1380,nop,nop,sackOK> (DF)
   Jun 21 12:29:55.506366 rule 0/0(match): block in on tun0: 145.254.182.172.4146 > 
145.254.62.42.445: S 3207890295:3207890295(0) win 32767 <mss 1460,nop,nop,sackOK> (DF)
   Jun 21 12:29:57.881676 rule 0/0(match): block in on tun0: 145.254.182.172.4146 > 
145.254.62.42.445: S 3207890295:3207890295(0) win 32767 <mss 1460,nop,nop,sackOK> (DF)
   Jun 21 12:29:58.360052 rule 0/0(match): block in on tun0: 67.213.252.201.2754 > 
145.254.62.42.445: S 816938580:816938580(0) win 8760 <mss 1460,nop,nop,sackOK> (DF)

These packets are coming from 68.167.211.60 (an address I've never seen
before) and from 145.254.182.172 (another dialup address at my ISP);
they're are all addressed to tun0's dynamically assigned IP address
(145.254.62.42), port 445.

I don't know what these are, but I suspect they may be attacks from yet
another windoze-worm. :(
        [Some pieces of evidence:
        * these packets usually start arriving within
          30 seconds of starting a dialup session, and come
          at the rate of a pair every 10-15 seconds or so
        * /etc/services lists 445 as "Microsoft-DS"
        * google found me a Microsoft web page which says that
          445 is used for "Microsoft CIFS"]

Is there any reason to let these packets through?


Thanks, ciao,

-- 
-- "Jonathan Thornburg (remove -animal to reply)" <[EMAIL PROTECTED]>
   Max-Planck-Institut fuer Gravitationsphysik (Albert-Einstein-Institut),
   Golm, Germany, "Old Europe"     http://www.aei.mpg.de/~jthorn/home.html      
   "Washing one's hands of the conflict between the powerful and the
    powerless means to side with the powerful, not to be neutral."
                                      -- quote by Freire / poster by Oxfam

Reply via email to