|
OpenBSD Security Functionally paranoid! |
|
Thread Tools | Display Modes |
|
|||
PF: Two internal interfaces and routing
Hi,
I have a problem regarding my pf ruleset. My network setup looks as following: Code:
Internet ^ | if_wan [pppoe0] | v (client1..n) <-- if_wlan --> bsd-router <-- if_lan --> (clientn+1..m) I'd like to achieve the following state: 1a. if_lan can connect to the wlan-clients through if_wlan 1b. if_lan can connect to the sshd on the bsd-router 1c. if_lan can connect to the internet through if_wan 2a. if_wlan can connect to the dhcpd on the bsd-router 2b. if_wlan can connect to the internet Short: if_lan -> if_wan, if_wlan, bsd-router:ssh if_wlan -> if_wan, bsd-router:dhcp Coming from the iptables world, my current approach seems a little odd to me – although it seems to work out just fine. Anyways, the relevant lines are: Code:
# lan:network -> lan:ssh pass in quick on $if_lan proto tcp from $if_lan:network to $if_lan port ssh # lan -> {wlan, internet} block in log quick on $if_lan to $if_lan pass in quick on $if_lan from $if_lan:network to $if_wlan:network pass in quick on $if_lan from $if_lan:network # lan -> router:dhcp pass in log quick on $if_wlan proto { tcp, udp } from $if_wlan:network to $if_wlan port 67 pass in log quick on $if_wlan proto { tcp, udp } from $if_wlan:network to $if_wlan port 68 # wlan -> pppoe block in log quick on $if_wlan to $if_lan:network block in log quick on $if_wlan to $if_wlan:network pass in quick on $if_wlan from $if_wlan:network pass out quick on $if_wlan from $if_lan:network Code:
pass in quick on $if_lan from $if_lan:network to ($if_wan) # allow if_lan -> internet pass in quick on $if_lan from $if_lan:network to $if_wlan:network # allow if_lan -> if_wlan pass in quick on $if_lan from $if_lan:network to $if_lan port ssh (I wanted to post a link to the entire ruleset but unfortunately I can't because I need to have at least five posts. Instead I'll just post it here, sorry) The whole ruleset: Code:
# interfaces if_lan="vr0" if_wan="pppoe0" if_wlan="vr2" if_wan_bandwith="1400Kb" # tables table <private_nets> const { 127.0.0.0/8, 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16 } # qos definitions que_low_ports = "{ http, https, 8080, smtp, smtps, 6881:6889 }" # |-- SIP --| |ICQ| | Jabber | |-- Playstation Net --| que_int_ports_tcp = "{ ssh, 5060, 5061, 5190, 5222, 5223, irc, 3478, 3479, 3480, 5223 }" # |-- SIP --| |-- PSN --| que_int_ports_udp = "{ 5060, 5061, 3478, 3479 }" # options ############## # allow lo communication set skip on lo set block-policy drop # hygiene ############## # scrubbing match in all scrub (no-df random-id) match out on $if_wan all scrub (random-id) match on $if_wan scrub (max-mss 1440) # qos ############### altq on $if_wan priq bandwidth $if_wan_bandwith queue { que_low, que_def, que_int, que_dns, que_ack } queue que_low priq(default) qlimit 80 queue que_def priority 2 queue que_int priority 4 priq(red) queue que_dns priority 5 qlimit 25 queue que_ack priority 6 # nat ############### match out on $if_wan inet from { $if_lan:network, $if_wlan:network } to any nat-to ($if_wan) static-port # filtering ############### # block all packets block all # enable spoofing protection antispoof quick for { lo $if_wan $if_lan $if_wlan } # reject ipv6 block quick on $if_wan inet6 all # block private addresses on external interfaces block drop in quick on $if_wan from <private_nets> block drop out quick on $if_wan to <private_nets> # allow output for wan, fill queues pass out quick on $if_wan proto tcp to port $que_low_ports queue (que_low, que_ack) pass out quick on $if_wan proto tcp to port $que_int_ports_tcp queue (que_int, que_ack) pass out quick on $if_wan proto udp to port $que_int_ports_udp queue (que_int, que_ack) pass out quick on $if_wan proto { tcp, udp } to port domain queue (que_dns, que_ack) pass out quick on $if_wan queue (que_def, que_ack) # enable input # lan:network -> lan:ssh pass in quick on $if_lan proto tcp from $if_lan:network to $if_lan port ssh # lan -> {wlan, internet} block in log quick on $if_lan to $if_lan pass in quick on $if_lan from $if_lan:network to $if_wlan:network pass in quick on $if_lan from $if_lan:network # lan -> router:dhcp pass in log quick on $if_wlan proto { tcp, udp } from $if_wlan:network to $if_wlan port 67 pass in log quick on $if_wlan proto { tcp, udp } from $if_wlan:network to $if_wlan port 68 # wlan -> pppoe block in log quick on $if_wlan to $if_lan:network block in log quick on $if_wlan to $if_wlan:network pass in quick on $if_wlan from $if_wlan:network pass out quick on $if_wlan from $if_lan:network Sören |
|
|||
Hey jggimi, thanks for your reply.
I can understand other members not observing threads about pf as they seem to make up roughly 80% of the posts in this subforum. Just for clarification: The script as posted *appears* to work "just fine". I just have a strange feeling about the rules (especially in the excerpt), as they appear (to me) to follow the "enumerate badness" principle (instead of enumerate goodness). Thus I tried to tighten the rules but the results prevented me from connecting to the internet. Thank you for spending your time on this issue! |
|
||||
I do not clearly understand how the three rules you added for inter-LAN communication affected your egress traffic. They shouldn't. Perhaps I've misunderstood.
This may be review, but please keep in mind that whether or not you use standard or quick rules, position within the ruleset matters. In your case, whenever your quick rules are tested -- to establish a new stateful session, or for stateless traffic -- on the first match, rule inspection stops and the block or pass is applied. So perhaps the position of your three added rules affected function. It will probably take me until the weekend before I have time to recreate your environment, and test your rules with three networks. Meanwhile, you might consider adding the log option to all of your pass and block rules, so that you can inspect the behavior of your ruleset with your traffic, using tcpdump(8) and the pflog(4) interface. For example: # tcpdump -neti pflog0 action block will show you which block rule is blocking current traffic, by rule number. Numbers to rules can be mapped with # pfctl -vvsr Perhaps someone else will provide additional input for you, prior to the weekend. Last edited by jggimi; 12th December 2013 at 03:20 AM. Reason: clarity |
|
|||
Thank you, I'll try that out when I get home from work and then provide the output.
Cheers |
|
||||
I have set up a lab with 4 machines across three networks, and am testing with your PF configuration.
Code:
# wlan -> pppoe block in log quick on $if_wlan to $if_lan:network I am not clear why you are using explicit block quick rules throughout your ruleset, since you begin with a block all any traffic that does not match an explicit pass rule will be blocked. It makes your ruleset hard to read and understand. |
|
|||
Thanks for (trying) to reproduce my setup and sorry for the late answer – I had to replace my notebook that broke last week.
I was aware that those three lines that I posted separately are bogus. Your note about not being able to connect from Wifi to Lan is in my case not a bug rather intended behaviour. However, I am wondering why it was possible for you to connect to the internet from the lan and wlan interfaces while for me it was denied. Before I replied to your post, I spent a little time on simplifying the rules: Code:
.... pass out quick on $if_wan queue (que_def, que_ack) # lan:network -> lan:ssh pass in log quick on $if_lan proto tcp from $if_lan:network to $if_lan port ssh # wlan:network -> wlan:dhcp pass in quick on $if_wlan proto { tcp, udp } from $if_wlan:network to $if_wlan port 67 pass in quick on $if_wlan proto { tcp, udp } from $if_wlan:network to $if_wlan port 68 #********************************************************** # block any -> lan block in quick to $if_lan:network # block wlan -> wlan block in quick from $if_wlan:network to $if_wlan:network # pass lan -> any pass in quick on $if_lan from $if_lan:network # pass dmz -> any pass in quick on $if_wlan from $if_wlan:network EOF Code:
pass in quick on $if_lan from $if_lan:network to ($if_wan) Thank you for patience and guidance. |
|
||||
Quote:
LAN traffic -- inbound, the highlighted rule below: Code:
# lan -> {wlan, internet} block in log quick on $if_lan to $if_lan pass in quick on $if_lan from $if_lan:network to $if_wlan:network pass in quick on $if_lan from $if_lan:network Code:
# allow output for wan, fill queues pass out quick on $if_wan proto tcp to port $que_low_ports queue (que_low, que_ack) pass out quick on $if_wan proto tcp to port $que_int_ports_tcp queue (que_int, que_ack) pass out quick on $if_wan proto udp to port $que_int_ports_udp queue (que_int, que_ack) pass out quick on $if_wan proto { tcp, udp } to port domain queue (que_dns, que_ack) pass out quick on $if_wan queue (que_def, que_ack) Code:
# wlan -> pppoe block in log quick on $if_wlan to $if_lan:network block in log quick on $if_wlan to $if_wlan:network pass in quick on $if_wlan from $if_wlan:network pass out quick on $if_wlan from $if_lan:network Code:
# allow output for wan, fill queues pass out quick on $if_wan proto tcp to port $que_low_ports queue (que_low, que_ack) pass out quick on $if_wan proto tcp to port $que_int_ports_tcp queue (que_int, que_ack) pass out quick on $if_wan proto udp to port $que_int_ports_udp queue (que_int, que_ack) pass out quick on $if_wan proto { tcp, udp } to port domain queue (que_dns, que_ack) pass out quick on $if_wan queue (que_def, que_ack) Quote:
Your "cleanup" is a file fragment and I have not yet reviewed what you have done. As I've stated, you should not require "block quick" rules in among your various "pass quick rules, as you started with a standard block all rule. Please note that you have several rules that PF did not apply to your ruleset. They could never match so PF ignored them: I've highlighted them below, the rules above them negate their ever being matched: Code:
# lan -> {wlan, internet} block in log quick on $if_lan to $if_lan pass in quick on $if_lan from $if_lan:network to $if_wlan:network pass in quick on $if_lan from $if_lan:network # lan -> router:dhcp pass in log quick on $if_wlan proto { tcp, udp } from $if_wlan:network to $if_wlan port 67 pass in log quick on $if_wlan proto { tcp, udp } from $if_wlan:network to $if_wlan port 68 |
|
|||
Again, thanks for your reply!
The point with the 'quick' rules is simply that this behaviour is more common for me due to iptables. I wonder why you've been able to connect to the internet from any lan/wlan interface in my setup. Of course I used your commands for getting the output. Whenever I try to connect to the outside, the following rule prevents me from doing so: Code:
pflog0 rule 5/(match) block in on vr0: 192.168.0.2 > 8.8.8.8: icmp: echo request (DF) Code:
@5 block drop log all [ Evaluations: 159 Packets: 77 Bytes: 6468 States: 0 ] [ Inserted: uid 0 pid 14650 State Creations: 0 ] Code:
# pass lan -> any pass in log quick on $if_lan from $if_lan:network Thank you and greetings |
|
||||
That's easy. Your connectivity tests and mine were different.
You were getting blocked ICMP Echo Requests, which is of course the case because you did not have a pass rule that included ICMP. (ICMP Echo requests are how ping(8) communicates. ICMP is also helpful for informing users immediately when connections cannot be established, and it usually makes for a better browsing experience for people if they receive an immediate error rather than waiting 30 seconds for a TCP timeout. It's a key Internet protocol.) I was not testing with ping. I was testing with the TCP protocol, as I wanted to test state establishment and stateful functions. As this was just a lab experiment, I was using nc(1) as my testing tool. On the "Internet server" I used the options -l and -k, for example: $ nc -kl 1234 To connect to this "server" (at lab IP address 99.99.99.100) from platforms on the WLAN and LAN networks, I used: $ nc 99.99.99.100 1234
|
|
|||
It feels like I'm slowly slipping into insanity, although I see some progress by now.
I think the problem rather lies within stateful rules / nat than in icmp... I tried to open a tcp connection to a google webserver by using Code:
$ nc -v -w 1 74.125.132.106 80 Ncat: Version 6.40 ( http://nmap.org/ncat ) Ncat: Connection timed out. Code:
rule 5/(match) block in on vr0: 192.168.0.3.50118 > 74.125.132.106.80: S 1884520729:1884520729(0) win 29200 <mss 1460,sackOK,timestamp 6781807 0,nop,wscale 7> (DF) rule 5/(match) block in on vr0: 192.168.0.3.50118 > 74.125.132.106.80: S 1884520729:1884520729(0) win 29200 <mss 1460,sackOK,timestamp 6782808 0,nop,wscale 7> (DF) Code:
pass in log quick on $if_lan from $if_lan:network Does my ruleset maybe miss anything regarding NAT / stateful rules (which is my humble assumption) |
|
||||
You posted your changes in excerpt form, rather than as a complete ruleset, so it is difficult for me to see what has changed. If you post a complete ruleset, at least we will be comparing results of the same exact rules. I have only tested the rules you posted at the top of this thread.
Some additional thoughts.
|
|
|||
You are absolutely right about the difficulty to comprehend the compelte ruleset when I just post the new rules as excerpts. I will post the the complete ruleset when I'm home from work.
Thank you, Sören |
|
|||
jggimi, this is the head revision of my script:
Code:
# interfaces if_lan="vr0" if_wlan="vr2" if_wan="pppoe0" if_wan_bandwith="1400Kb" # tables table <private_nets> const { 127.0.0.0/8, 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16 } # qos definitions que_low_ports = "{ http, https, 8080, smtp, smtps, 6881:6889 }" que_int_ports_tcp = "{ ssh, 5060, 5061, 5190, 5222, 5223, irc, 3478, 3479, 3480, 5223 }" que_int_ports_udp = "{ 5060, 5061, 3478, 3479 }" # allow lo communication set skip on lo set block-policy drop # scrubbing match in all scrub (no-df random-id) match out on $if_wan all scrub (random-id) match on $if_wan scrub (max-mss 1440) # qos altq on $if_wan priq bandwidth $if_wan_bandwith queue { que_low, que_def, que_int, que_dns, que_ack } queue que_low priq(default) qlimit 80 queue que_def priority 2 queue que_int priority 4 priq(red) queue que_dns priority 5 qlimit 25 queue que_ack priority 6 # nat (use "static-port" for crappy Playstation Network) match out on $if_wan inet from { $if_lan:network, $if_wlan:network } to any nat-to ($if_wan) static-port # filtering # block all packets block log all # enable spoofing protection antispoof quick for { lo $if_wan $if_lan $if_wlan } # reject ipv6 block quick on $if_wan inet6 all # block private addresses on external interfaces block drop in quick on $if_wan from <private_nets> block drop out quick on $if_wan to <private_nets> # qos: fill queues pass out quick on $if_wan proto tcp to port $que_low_ports queue (que_low, que_ack) pass out quick on $if_wan proto tcp to port $que_int_ports_tcp queue (que_int, que_ack) pass out quick on $if_wan proto udp to port $que_int_ports_udp queue (que_int, que_ack) pass out quick on $if_wan proto { tcp, udp } to port domain queue (que_dns, que_ack) pass out quick on $if_wan queue (que_def, que_ack) # allow output # I guess this is point where I'm starting to mess up pass out quick # allow services # allow ssh from if_lan pass in quick on $if_lan proto tcp from $if_lan:network to $if_lan port ssh # allow dhcp from if_wlan pass in quick on $if_wlan proto { tcp, udp } from $if_wlan:network to $if_wlan port 67 pass in quick on $if_wlan proto { tcp, udp } from $if_wlan:network to $if_wlan port 68 # block any -> lan # explicitely blocking something seems absurd to me... block in quick to $if_lan:network # block wlan -> wlan block in quick from $if_wlan:network to $if_wlan:network # pass lan -> any # if I disable comment this rule, there's no connection to the internet from if_lan pass in quick on $if_lan from $if_lan:network # pass wlan -> any # if I disable comment this rule, there's no connection to the internet from if_wlan pass in quick on $if_wlan from $if_wlan:network |
|
||||
The configuration files below is, as I described, very minimal. Your general goals were used to create the rules. For clarity, I have added two macros, and for an improved experience I set a block policy to return TCP RST (for TCP traffic) or ICMP UNREACHABLE (for everything else).
1. I avoided quick. It wasn't needed. 2. I used tags for clarity when reading the rules, but also, for ease of defining outbound policy. 3. I left your queues alone, except I converted them to match rules so that queing could be separated from pass policy. Code:
# interfaces if_lan="vr0" if_wlan="vr2" if_wan="pppoe0" # other macros for convenience # these two added by jggimi: lan="em0:network" wlan="em1:network" if_wan_bandwith="1400Kb" que_low_ports = "{ http, https, 8080, smtp, smtps, 6881:6889 }" que_int_ports_tcp = "{ ssh, 5060, 5061, 5190, 5222, 5223, irc, 3478, 3479, 3480, 5223 }" que_int_ports_udp = "{ 5060, 5061, 3478, 3479 }" # loopback ignored set skip on lo # scrubbing match in all scrub (no-df random-id) match out on $if_wan all scrub (random-id) match on $if_wan scrub (max-mss 1440) # qos altq on $if_wan priq bandwidth $if_wan_bandwith queue { que_low, que_def, que_int, que_dns, que_ack } queue que_low priq(default) qlimit 80 queue que_def priority 2 queue que_int priority 4 priq(red) queue que_dns priority 5 qlimit 25 queue que_ack priority 6 # nat (use "static-port" for crappy Playstation Network) # simplified by jggimi: match out on $if_wan from !($if_wan) nat-to ($if_wan) static-port # filtering # this is where jggimi substituted a new set of rules to meet these goals: # # 1. pass traffic from $lan devices to $wlan, egress, and ssh daemon here. # 2. pass traffic from $wlan devices to egress and dhcp daemon here. # # jggimi's rules use the following guidelines: # # Blocked traffic will be polite and return ICMP UNREACHABLE or TCP RST. # Queues will be assigned by match rules. Queue assignments were unchanged. # Policy based rules set by tag, primarily for readability and clarity. # default block policy set block-policy return block log # queue assignments match out on $if_wan proto tcp to port $que_low_ports queue (que_low, que_ack) match out on $if_wan proto tcp to port $que_int_ports_tcp queue (que_int, que_ack) match out on $if_wan proto udp to port $que_int_ports_udp queue (que_int, que_ack) match out on $if_wan proto { tcp, udp } to port domain queue (que_dns, que_ack) match out on $if_wan queue (que_def, que_ack) ######## # 1. pass traffic from $lan devices to $wlan, egress, and ssh daemon here. ######## pass log from $lan tag external pass log from $lan to $wlan tag internal pass log proto tcp from $lan to self port 22 tag local ######## # 2. pass traffic from $wlan devices to egress and dhcp daemon here. ######## pass log from $wlan tag external pass log proto {tcp udp} from $wlan to self port bootps tag local pass log proto {tcp udp} from self to $wlan port bootpc tag local # pass the tagged traffic pass out log on {$if_lan $if_wlan} tagged internal pass out log on $if_wan tagged external Please read the rules and modify them to meet your actual needs, if you elect to use them. I may have misunderstood your goal of LAN client connecting to WLAN services -- it might be you intended the opposite. Last edited by jggimi; 18th December 2013 at 10:43 PM. Reason: clarity, typo |
|
|||
Many people who have to configure multiple NIC firewalls with pf have difficulties with understanding what according to pf is in and out.
Code:
/|\ | out | | in | | | \|/ | | +-----|-----------|-----+ | +-----------+ | | | PPPoE | | | +-----------+ | | | | +---+ +---+ | out | | | | | | out <------------| W | | |-----------> | | L | | L | | | | A | | A | | ----->-------| N | | N |------<----- in | | | | | | in | +---+ +---+ | | | | OpenBSD | | pf | | | +-----------------------+
Of course you will need some additional rules and refinements to allow the DCHP and SSH traffic from/to the OpenBSD pf box itself.
__________________
You don't need to be a genius to debug a pf.conf firewall ruleset, you just need the guts to run tcpdump |
|
||||
J65nko used tags as I did, but he also used quick, which you may prefer.
I'd like to highlight what I see as a value when using standard rules; which is that we are able to use a broad rule first then narrow focus for rules which follow to more specific traffic. An example of this is in the following fragment. These are the first 3 pass rules I provided above: Code:
######## # 1. pass traffic from $lan devices to $wlan, egress, and ssh daemon here. ######## pass log from $lan tag external pass log from $lan to $wlan tag internal pass log proto tcp from $lan to self port 22 tag local Last edited by jggimi; 19th December 2013 at 11:53 AM. Reason: clarity |
|
|||
Thank you both for your replies!
jggimi, I applied your rules to my ruleset, but I had to modify them: I had to change the following statement Code:
######## # 1. pass traffic from $lan devices to $wlan, egress, and ssh daemon here. ######## pass log from $lan tag external Code:
######## # 1. pass traffic from $if_lan:network devices to $if_wlan:network, egress, and ssh daemon here. ######## pass log from $lan to !($lan) tag external Further, I had to replace the following statement: Code:
######## # 2. pass traffic from $wlan devices to egress and dhcp daemon here. ######## pass log from $wlan tag external Code:
######## # 2. pass traffic from $if_wlan:network devices to egress and dhcp daemon here. ######## table <WLAN_PROHIBITED> { $lan, $wlan } pass log from $wlan to !<WLAN_PROHIBITED> tag external Now it seems to work just fine, thank you! |
|
|
Similar Threads | ||||
Thread | Thread Starter | Forum | Replies | Last Post |
two lan interfaces and one network | peric0 | OpenBSD General | 1 | 29th March 2012 02:16 AM |
Routing internal requests to external IPs | jdude | FreeBSD General | 1 | 9th July 2009 07:25 AM |
PPTP Server, no internet connectivity (routing between interfaces?) | godfrank | FreeBSD Ports and Packages | 5 | 15th April 2009 04:44 PM |
Redirect Internal Network to Internal Website | plexter | OpenBSD Security | 12 | 12th February 2009 08:00 PM |
PHP database interfaces | TerryP | Programming | 6 | 11th September 2008 01:03 PM |