Solved pf - time of day filter

I'd like to implement a time of day filter to effectively disable the Internet at certain times of the day. From what I gather, this isn't possible directly with pf; however, I need to use cron/crontab/at to switch over to new rules. This isn't conceptually difficult, but I am wondering if there is an alternative? Is it possible on ipfw / ipfilter? Or, is there a utility somewhere that already does this for pf (besides opnsense or pfsense)?
 
The easiest way I've found to do this is with an anchor that is modified by cron; something like anchor "sinkhole" out on $ext_if early in your pf filter rules, and with $ext_if as a macro pointing to your Internet connection, and then cron jobs like:

Code:
# Block new connections out (via 'anchor sinkhole out on $ext_if' in pf.conf) at 1AM
0 1 * * * root echo "block return quick" | pfctl -q -a sinkhole -f -
# Flush (cut off) any existing connections at 1:01
1 1 * * * root pfctl -q -F states
# Flush the rules from the sinkhole anchor (permit outgoing data)
0 7 * * * root pfctl -q -a sinkhole -F rules

(Note this is in the system crontab format.)

Alternatively, you could just really swing the hammer with service netif stop internet_interface and similar for start... the plus of using pf is that you can allow the connections you want by adding other rules or conditions on these rules to limit scope.
 
Ok, that got the wheels turning. I already use tables, so an anchor seems like the right way to go.

I won't drop the hammer as I want to keep maintenance stuff going.

Hmm, so, I think all I need to do is have an empty anchor, then at the start time, populate the anchor, at the end time, empty the anchor, and repeat.

That saved me a huge headache. I was contemplating generating the rules using cron and then switching over to a different ruleset based on the time.
 
Thanks - I'm wondering if you can help answer this pf question so I can test anchors.


I'm not sure this is right, I've tried many permutations of this, but to no avail. Essentially, what I'm trying to do with the rule below is allow traffic from the machine itself out to the Internet 24x7 as well as other machines identified by the lists. However, it is also matching my machine which is not in that list:

pass out quick on wan proto tcp from {$zone_Microsoft $zone_Apple $zone_TV self} to port {http https}

I think "self" is allowing all traffic through - if I just specific from self, all traffic gets through. The zone I'm on is zone_BSD. self is the "router", a workstation with 2 NICs doing NAT. If I remove "self" from that rule above, then nothing gets out. I have an empty anchor below which I can then dynamically add rules to, but I've yet to verify that since I cannot get this rule working as I expect.
 
Note that pf will keep allowing established states, even after you've modified the rules to deny traffic. New states will be blocked, but established ones will keep carrying traffic.
 
Note that pf will keep allowing established states, even after you've modified the rules to deny traffic. New states will be blocked, but established ones will keep carrying traffic.

Right. That’s what the pfctl -F states is for. But it’s a good thing to keep in mind when changing configuration and then looking for “what changed” — running connections will get to keep going (without a flush) even if new ones would be blocked.
 
Thanks - I'm wondering if you can help answer this pf question so I can test anchors.


I'm not sure this is right, I've tried many permutations of this, but to no avail. Essentially, what I'm trying to do with the rule below is allow traffic from the machine itself out to the Internet 24x7 as well as other machines identified by the lists. However, it is also matching my machine which is not in that list:



I think "self" is allowing all traffic through - if I just specific from self, all traffic gets through. The zone I'm on is zone_BSD. self is the "router", a workstation with 2 NICs doing NAT. If I remove "self" from that rule above, then nothing gets out. I have an empty anchor below which I can then dynamically add rules to, but I've yet to verify that since I cannot get this rule working as I expect.

For this setup, perhaps a ‘pass in quick on lan from ...’ for your different 24/7 zones that are “always on” followed by an ‘anchor foo in on lan’ and ‘pass in on lan’; then you can add/remove a drop quick rule to the anchor foo to disable non-24/7 addresses coming in locally. (Note your nat rule can’t have a pass on it, or it skips filtering rules; you could also reverse the order and drop the quicks.)

Be sure to consult the FreeBSD pf.conf(5) as there are differences from OpenBSD’s.
 
If it is web traffic you want to block, www/squid has time based ACLs. This would of course require that all your web traffic goes through your squid proxy, but as you were looking for alternatives, this is one.
 
If it is web traffic you want to block, www/squid has time based ACLs. This would of course require that all your web traffic goes through your squid proxy, but as you were looking for alternatives, this is one.
Yes - I was contemplating that if I couldn't get pf working the way I want; however, I think cron and pfctl will be perfect. I ran squid previously, but as everything is https now, it only ended up caching very little and some apps ignore proxy settings.

I'm still having issues with my rules:
block out quick on wan to <BAD_IPS>
further down

pass out quick on wan proto tcp from {$zone_BSD} to port {http https}
That doesn't work, it only works if I do
pass out quick on wan proto tcp from self to port {http https}

But, if I do that, then all devices can access the Internet. So, I tried:
pass in quick on lan proto tcp from {$zone_BSD} to port {http https}

I also tried pass out.

But, again, that doesn't work.

My NAT is well above that, does that matter?
nat on wan inet from lan:network to any -> (wan)

I use quick everywhere so the first rule that matches will cause it to stop processing. The last rule is a generic block rule.
 
Yes - I was contemplating that if I couldn't get pf working the way I want; however, I think cron and pfctl will be perfect. I ran squid previously, but as everything is https now, it only ended up caching very little and some apps ignore proxy settings.
Things that ignore a configured proxy can indeed become a hurdle, but caching aside, you get the added benefit of being able to filter on domain names and perform other kinds of access controls, a packet filter simply cannot do.

My NAT is well above that, does that matter?
NAT is translation and that happens before filtering in pf, so the filter gets to see the packets after any translations have been applied. You probably get better results trying to filter inbound traffic on your LAN interface, than outbound traffic on the WAN interface, as that most likely has already been NATed.
 
It also seems that this syntax:

Is not supported on FreeBSD, so I won't be able to filter NAT'd traffic? That seems very limiting.
 
I'm assuming it's a real firewall? As in, it only does filtering on this host for other machines on your network? So it has an incoming interface and an outgoing interface?

Code:
block out quick on wan to <BAD_IPS>
Block the traffic coming in on the LAN interface. If there's nothing coming in there's nothing going out either.
Code:
block in quick on lan to <BAD_IPS>

Same with these:
Code:
pass out quick on wan proto tcp from {$zone_BSD} to port {http https}
NAT happens before your rules are evaluated. So the source address is already translated at this point.
Code:
pass in quick on lan proto tcp from ${zone_BSD} to port {http, https}
Then you need to allow the outgoing traffic from the NATed address: (assuming you have a rule like nat on $wan from $int_net to any -> ($wan))
Code:
pass out quick on wan proto tcp from ($wan) to any port {http,https}
 
I'm assuming it's a real firewall? As in, it only does filtering on this host for other machines on your network? So it has an incoming interface and an outgoing interface?
Yes.

pass out quick on wan proto tcp from ($wan) to any port {http,https}
I don't want to allow all machines on the lan all the time to the Internet. I want to allow some devices only at a fixed time, hence why I had previously defined lists with devices. As my firewall wasn't truly doing anything before, I didn't find that out until I wanted to restrict access by time of day using anchors.

Is it possible to do that within pf on FreeBSD? I saw something on OpenBSD that might do it.
 
I think I'm making headway. The original question was answered.

I appreciate everyone's feedback. I think what is working is to allow everything out on the WAN interface that I want followed by blocking everything that doesn't match what I want to allow out. I was able to add an anchor and add/remove rules, thus with crontab, I can make the rules dynamic.
 
Back
Top