# Table in pf to Block IPs not Working



## Ruler2112 (Mar 9, 2010)

I have the following in my /etc/pf.conf:


```
table <other-blocked> persist file "/usr/local/etc/IPBlocks/Others"
block in log quick on $ext_if from <other-blocked> to any
```

Should this not block any incoming connections on my external interface (tun0 because I'm on DSL/PPPoE) from the IP addresses listed in the /usr/local/etc/IPBlocks/Others file?  I'm asking because it does not seem to be working.  I have a script that reports how many failed login attempts are on pop3 and includes a short report in the nightly cron job, then whois each and if the person is not located on the same continent, add their IP to the /usr/local/etc/IPBlocks/Others file and run [cmd=]pfctl -t other-blocked -Tr -f /usr/local/etc/IPBlocks/Others[/cmd] to update the table after changing the file.  I blocked a specific IP address on 2010-02-23 for trying to guess a username/password, but the same IP was reported in my maillog over the weekend doing the same thing.

Anyone see where I'm going wrong?


----------



## DutchDaemon (Mar 9, 2010)

Use [cmd=]pfctl -t other-blocked -Tt <ip>[/cmd] to test whether these IPs are actually in the table (-Ts to simply show the contents of the loaded table). There may be an error in the file causing the table to fail silently.

If the table is ok, something else/prior must be overruling the block rule.


----------



## Ruler2112 (Mar 10, 2010)

I did as you directed and the IPs in the file are indeed being listed in the output of [cmd=]pfctl -t other-blocked -Ts[/cmd], so I must've screwed up my firewall somewhere along the line.  

Here's my firewall script.  I went through it, but cannot see anything out of place, unless the rule allowing POP access overrides the blocking one; I thought the 'quick' directive was supposed to prevent further checking though.  Would you mind taking a peek when you get a minute?


```
# Set variables.
#ext_if = "nfe0"
ext_if = "tun0"
lcl_if = "lo0"
lcl_ip = "127.0.0.1/32"
int_if = "rl0"
int_ip = "192.168.20.1/24"
int_sip = "192.168.20.1/32"
adm_if = "vr0"
adm_ip = "192.168.5.2/32"
adm_sip = "192.168.5.1/32"

pop3_ports = "{ 110, 995 }"
imap_ports = "{ 143, 993 }"
mail_ports = "{ 110, 995, 143, 993 }"
smtp_ports = "{ 25, 2225 }"
bind_ports = "{ 53 }"
webi_ports = "{ 80 }"
webo_ports = "{ 443 }"
admn_ports = "{ 23, 10101 }"
icmp_types = "echoreq"

# Set defaults.
set block-policy return
#set loginterface $ext_if
set skip on $lcl_if
scrub in on { $ext_if, $int_if }

# Activate alternate queuing
altq on tun0 cbq bandwidth 512Kb queue { standard_out, dns_out, http_out, tcpack_out, \
                                         popimap_out, smtp_out, admintraffic_out, wifitraffic_out }

# Set up queues
queue standard_out bandwidth 72Kb priority 0 cbq(default, borrow)
queue dns_out bandwidth 20Kb priority 6 cbq(borrow)
queue http_out bandwidth 40Kb priority 5 cbq(borrow)
queue tcpack_out bandwidth 40Kb priority 7 cbq(borrow)
queue popimap_out bandwidth 100Kb priority 4 cbq(borrow)
queue smtp_out bandwidth 100Kb priority 3 cbq(borrow)
queue admintraffic_out bandwidth 90Kb priority 2 cbq(borrow)
queue wifitraffic_out bandwidth 50Kb priority 1 cbq(borrow)

# Allow internal interfaces to get to the internet.
nat on $ext_if from $int_ip to any -> ($ext_if)
nat on $ext_if from $adm_ip to any -> ($ext_if)
#nat-anchor "ftp-proxy/*"

# Allow local nets to FTP out.  Needed???
#rdr-anchor "ftp-proxy/*"
#rdr on $int_if proto tcp from any to any port 21 -> 127.0.0.1 port 8021
#rdr on $adm_if proto tcp from any to any port 21 -> 127.0.0.1 port 8021

# Block everything unless later explicitly allowed.
block in

# Keep state for established connections.
pass out keep state

# Allow local nets to FTP out.  Needed???
#anchor "ftp-proxy/*"

# Protect against IP spoofing on local network segments.
antispoof quick for { $lcl_if $int_if $adm_if }

# Block inbound traffic from IPs not valid for each interface.
block in quick on ! $int_if inet from $int_ip to any
block in quick on ! $adm_if inet from $adm_ip to any

# Nobody else is me - block attempts to make us think so.
block in quick on $int_if inet from $int_sip to any
block in quick on $adm_if inet from $adm_sip to any

# Assume administrator knows what he is doing.  Not necessarily true...
pass in quick on $adm_if from $adm_ip

# Block IPs classed as threats by EmergingThreats.org
table <emerging-threats> persist file "/usr/local/etc/IPBlocks/EmergingThreats"
block in log quick on $ext_if from <emerging-threats> to any
block out log quick on $ext_if from any to <emerging-threats>

# Block IPs that have tried to hack me
table <other-blocked> persist file "/usr/local/etc/IPBlocks/Others"
block in log quick on $ext_if from <other-blocked> to any

# Set up the rest of the rules
pass in on $ext_if inet proto tcp from any to ($ext_if) port $pop3_ports flags S/SA keep state
pass in on $ext_if inet proto tcp from any to ($ext_if) port $imap_ports flags S/SA keep state
pass in on $ext_if inet proto tcp from any to ($ext_if) port $smtp_ports flags S/SA keep state
pass in on $ext_if inet proto { tcp, udp } from any to ($ext_if) port $bind_ports
pass in on $ext_if inet proto tcp from any to ($ext_if) port $webi_ports flags S/SA keep state
pass in on $ext_if inet proto tcp from any to ($ext_if) port $webo_ports flags S/SA keep state
pass in on $int_if inet proto tcp from any to any port $pop3_ports flags S/SA keep state
pass in on $int_if inet proto tcp from any to any port $imap_ports flags S/SA keep state
pass in on $int_if inet proto tcp from any to any port $smtp_ports flags S/SA keep state
pass in on $int_if inet proto { tcp, udp } from any to any port $bind_ports
pass in on $int_if inet proto tcp from any to any port $webi_ports flags S/SA keep state
pass in on $int_if inet proto tcp from any to any port $webo_ports flags S/SA keep state
pass in inet proto icmp all icmp-type $icmp_types keep state

pass out on $ext_if inet proto { tcp udp } from ($ext_if) to any port $bind_ports keep state queue (dns_out, tcpack_out)
pass out on $ext_if inet proto tcp from ($ext_if) to any port $webi_ports keep state queue (http_out, tcpack_out)
pass out on $ext_if inet proto tcp from ($ext_if) to any port $mail_ports keep state queue (popimap_out, tcpack_out)
pass out on $ext_if inet proto tcp from ($ext_if) to any port $smtp_ports keep state queue (smtp_out, tcpack_out)
pass out on $ext_if inet proto tcp from ($adm_if) to any keep state queue (admintraffic_out, tcpack_out)
pass out on $ext_if inet proto tcp from ($int_if) to any keep state queue (wifitraffic_out, tcpack_out)
```


----------



## DutchDaemon (Mar 10, 2010)

Looks ok to me, though I like to put table definitions between the macros and options blocks, but that's not mandatory. 

How static is the block of IP addresses in the /usr/local/etc/IPBlocks/Others file? Once pf is started, file-based tables will not be re-read, so if new data is added to or removed from that file, the table needs to be reinitialised to contain the new additions/deletions. 

An easy way to check whether the file is in sync with the actual table (in memory):

[cmd=]cat /usr/local/etc/IPBlocks/Others | xargs pfctl -t other-blocks -Tt[/cmd]

If you don't get a 100% match (something like "2091/2091 addresses match"), the table in memory doesn't get updated, and you'll need to script a synchronisation step into the mechanism that maintains the file:

[cmd=]/sbin/pfctl -t other-blocks -Tr -f /usr/local/etc/IPBlocks/Others[/cmd]

Again: this goes for all file-based tables that are subject to change.


----------



## Ruler2112 (Mar 11, 2010)

The file isn't changed unless I do so manually.  I have a script that I use to do this:


```
/usr/bin/vi /usr/local/etc/IPBlocks/Others
/sbin/pfctl -t other-blocked -Tr -f /usr/local/etc/IPBlocks/Others
```

This is so the table is updated immediately after I change the file and I don't have to remember to do it myself.


Given that you didn't see anything wrong in the firewall script DD, I'm *really* scratching my head, wondering how somebody listed in the file/table was able to get through my firewall...  Since pf works on a 'last matching rule' approach, I'm going to try shoving the block lines down below the rest of the rules so that they're just above the queuing rules and see if that helps.  (Maybe the 'quick' isn't behaving the way I expect it to???)  I won't know for weeks/months, just because I don't know when somebody in my block list will try again.


----------



## DutchDaemon (Mar 11, 2010)

quick introduces a 'first match wins' condition, so moving the lines will not do anything .. Does the <emerging-threats> table work?


----------



## Ruler2112 (Mar 12, 2010)

That's what I thought the quick directive did... weird.  The emerging-threats table did work when I set it up for outbound at least (no way to test inbound), which is why I copied the lines for the other-blocked table.

I had an idea after my last post, called home, and had her load up a web page from my mail server.  I added my home IP to the other-blocked table via my script and had her hit reload - timed out and the number of packets recorded in /var/log/pflog increased.

There were three change made: I removed 'quick' from the three lines, moved them just before the queuing, and moved the table declarations just below the variables.  Don't see why any of those would make a difference, but the firewall is now working as expected.



It really is disheartening to feel I'm finally understanding BSD and the intricacies of how the different mechanisms work and then be hit with something like this where I don't have a clue as to why it's behaving the way it is.


----------



## Ruler2112 (Mar 16, 2010)

OK, now I'm starting to get really frustrated.  After verifying with my home IP that the table IS working as described in my last post, I had somebody from China try to log in repeatedly who was already listed in the other-blocked table show up in my logs _again_ today.

Here's the firewall script as it sits right now - anybody see how this is happening???

```
# Set variables.
#ext_if = "nfe0"
ext_if = "tun0"
#ext_if = "ng0"
lcl_if = "lo0"
lcl_ip = "127.0.0.1/32"
int_if = "rl0"
int_ip = "192.168.20.1/24"
int_sip = "192.168.20.1/32"
adm_if = "vr0"
adm_ip = "192.168.5.2/32"
adm_sip = "192.168.5.1/32"

pop3_ports = "{ 110, 995 }"
imap_ports = "{ 143, 993 }"
mail_ports = "{ 110, 995, 143, 993 }"
smtp_ports = "{ 25, 2225 }"
bind_ports = "{ 53 }"
webi_ports = "{ 80 }"
webo_ports = "{ 443 }"
admn_ports = "{ 23, 10101 }"
icmp_types = "echoreq"

# Set up tables.
table <emerging-threats> persist file "/usr/local/etc/IPBlocks/EmergingThreats"
table <other-blocked> persist file "/usr/local/etc/IPBlocks/Others"

# Set defaults.
set block-policy return
#set loginterface $ext_if
set skip on $lcl_if
scrub in on { $ext_if, $int_if }

# Activate alternate queuing
altq on tun0 cbq bandwidth 512Kb queue { standard_out, dns_out, http_out, tcpack_out, \
                                         popimap_out, smtp_out, admintraffic_out, wifitraffic_out }

# Set up queues
queue standard_out bandwidth 72Kb priority 0 cbq(default, borrow)
queue dns_out bandwidth 20Kb priority 6 cbq(borrow)
queue http_out bandwidth 40Kb priority 5 cbq(borrow)
queue tcpack_out bandwidth 40Kb priority 7 cbq(borrow)
queue popimap_out bandwidth 100Kb priority 4 cbq(borrow)
queue smtp_out bandwidth 100Kb priority 3 cbq(borrow)
queue admintraffic_out bandwidth 90Kb priority 2 cbq(borrow)
queue wifitraffic_out bandwidth 50Kb priority 1 cbq(borrow)

# Allow internal interfaces to get to the internet.
nat on $ext_if from $int_ip to any -> ($ext_if)
nat on $ext_if from $adm_ip to any -> ($ext_if)
#nat-anchor "ftp-proxy/*"

# Allow local nets to FTP out.  Needed???
#rdr-anchor "ftp-proxy/*"
#rdr on $int_if proto tcp from any to any port 21 -> 127.0.0.1 port 8021
#rdr on $adm_if proto tcp from any to any port 21 -> 127.0.0.1 port 8021

# Block everything unless later explicitly allowed.
block in

# Keep state for established connections.
pass out keep state

# Allow local nets to FTP out.  Needed???
#anchor "ftp-proxy/*"

# Protect against IP spoofing on local network segments.
antispoof quick for { $lcl_if $int_if $adm_if }

# Block inbound traffic from IPs not valid for each interface.
block in quick on ! $int_if inet from $int_ip to any
block in quick on ! $adm_if inet from $adm_ip to any

# Nobody else is me - block attempts to make us think so.
block in quick on $int_if inet from $int_sip to any
block in quick on $adm_if inet from $adm_sip to any

# Assume administrator knows what he is doing.  Not necessarily true...
pass in quick on $adm_if from $adm_ip

# FOR DEBUGGING ONLY!!!  Should be commented under normal circumstances
#pass in quick on $int_if from $int_ip to ($ext_if) port not 25 flags S/SA keep state
#pass in quick on $int_if from $int_ip flags S/SA keep state

# Set up the rest of the rules
pass in on $ext_if inet proto tcp from any to ($ext_if) port $pop3_ports flags S/SA keep state
pass in on $ext_if inet proto tcp from any to ($ext_if) port $imap_ports flags S/SA keep state
pass in on $ext_if inet proto tcp from any to ($ext_if) port $smtp_ports flags S/SA keep state
pass in on $ext_if inet proto { tcp, udp } from any to ($ext_if) port $bind_ports
pass in on $ext_if inet proto tcp from any to ($ext_if) port $webi_ports flags S/SA keep state
pass in on $ext_if inet proto tcp from any to ($ext_if) port $webo_ports flags S/SA keep state
pass in on $int_if inet proto tcp from any to any port $pop3_ports flags S/SA keep state
pass in on $int_if inet proto tcp from any to any port $imap_ports flags S/SA keep state
pass in on $int_if inet proto tcp from any to any port $smtp_ports flags S/SA keep state
pass in on $int_if inet proto { tcp, udp } from any to any port $bind_ports
pass in on $int_if inet proto tcp from any to any port $webi_ports flags S/SA keep state
pass in on $int_if inet proto tcp from any to any port $webo_ports flags S/SA keep state
pass in inet proto icmp all icmp-type $icmp_types keep state

# Block IPs classed as threats by EmergingThreats.org
block in log on $ext_if from <emerging-threats> to any
block out log on $ext_if from any to <emerging-threats>

# Block IPs that have tried to hack me
block in log on $ext_if from <other-blocked> to any

pass out on $ext_if inet proto { tcp udp } from ($ext_if) to any port $bind_ports keep state queue (dns_out, tcpack_out)
pass out on $ext_if inet proto tcp from ($ext_if) to any port $webi_ports keep state queue (http_out, tcpack_out)
pass out on $ext_if inet proto tcp from ($ext_if) to any port $mail_ports keep state queue (popimap_out, tcpack_out)
pass out on $ext_if inet proto tcp from ($ext_if) to any port $smtp_ports keep state queue (smtp_out, tcpack_out)
pass out on $ext_if inet proto tcp from ($adm_if) to any keep state queue (admintraffic_out, tcpack_out)
pass out on $ext_if inet proto tcp from ($int_if) to any keep state queue (wifitraffic_out, tcpack_out)
```


----------



## Ruler2112 (Mar 16, 2010)

Ugh.... I think I might have just found the solution.  I had a firewall running some time ago before I implemented traffic shaping.  After putting traffic shaping into place, I changed the name of the pf config file so that I could fall back on the old one should I need to.  However, when pppd re-authenticates to my ISP every ~20 hours, it runs the commands in /etc/ppp/ppp.linkup, which still had the original config file name in it to refresh the firewall after the link comes back up.  This explains everything that I've observed thus far.


----------



## DutchDaemon (Mar 16, 2010)

How many new swear words have you invented?

Anyway: put your 'block in quick' rules back on top, where they belong.


----------



## Ruler2112 (Mar 17, 2010)

DutchDaemon said:
			
		

> How many new swear words have you invented?



You don't even want to know...  

Thanks for your patience and help with this DD.


----------

