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