How to permanently BLACKHOLE a large number of IP addresses and ranges?

I've always used route add to instantly BLACKHOLE malicious incoming IP addresses, which works fine (apache's not installed....so I don't believe .htaccess is an option):
# route add -net 123.456.789.0/24 127.0.0.1 -blackhole

But the BLACKHOLING only lasts 'til the next reboot and/or network restart. In addition, I need a way to BLACKHOLE new IPs daily and, aside from it's being a temporary remedy, route add is also rather labour intensive.

Question: Is there a way to enter all of the day's IP addresses into, say, a text file (e.g., list.txt) and, then, export the IPs from list.txt via route add or some other simpler option to automate and simplify the process of BLACKHOLING numbers of new IP addresses?

p.s. I apologize if there's an existing solution, but I didn't see this answered previously and I've been out of the BSD world for some time. I'm trying to assist some friends who run an old UK music site. Thanks in advance for any useful assistance!
 
we would use pf tables for this. something like
Code:
table <adios> file "/etc/adios"
# and then at the top of the rules
block drop from <adios>
# then the rest of your rules
then you can edit the file and use pfctl -t adios -T replace -f /etc/adios to enact it
 
atax1a: Actually, I've used pf previously:
pfctl -t badhosts -T add <ip address>
....which seemed to work as well as route add. But, still, it only lasted 'til the next reboot.

Can you explain how the Code you posted above the pfctl statement (i.e., table....) works?
 
those statements go into pf.conf as part of a bigger ruleset. the file clause makes pf load the table from the file at boot. the pfctl statement reloads the table from the file.
 
those statements go into pf.conf as part of a bigger ruleset. the file clause makes pf load the table from the file at boot. the pfctl statement reloads the table from the file.
I think I follow you...and it looks like they've already got something similar to what you've suggested....

/etc/pf.conf:
table <badhosts> persist file "/etc/badguys"
block on vr0 from <badhosts> to any
block on sis0 from <badhosts> to any

Again, the following command DOES work, but NOT after reboot:
pfctl -t badhosts -T add <ip address>

QUESTION: As you can see, the first block in pf.conf references "vr0", but shouldn't this be "dc0" (as per ifconfig output below)?? Could that be why the BLACKHOLED IPs are getting through after reboots?


ifconfig:
dc0: flags=8843<UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST> mtu 1500
options=8<VLAN_MTU>
inet 10.0.0.1 netmask 0xffffff00 broadcast 10.0.0.255
ether 00:04:5a:70:e0:a2
media: Ethernet autoselect (100baseTX <full-duplex>)
status: active
sis0: flags=8843<UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST> mtu 1500
options=8<VLAN_MTU>
inet <server IP> netmask 0xfffffff8 broadcast <gateway IP>
ether 00:40:f4:3b:8c:e0
media: Ethernet autoselect (100baseTX <full-duplex>)
status: active
plip0: flags=108810<POINTOPOINT,SIMPLEX,MULTICAST,NEEDSGIANT> mtu 1500
lo0: flags=8049<UP,LOOPBACK,RUNNING,MULTICAST> mtu 16384
inet6 fe80::1%lo0 prefixlen 64 scopeid 0x4
inet6 ::1 prefixlen 128
inet 127.0.0.1 netmask 0xff000000
pflog0: flags=141<UP,RUNNING,PROMISC> mtu 33160
status: active
plip0: flags=108810<POINTOPOINT,SIMPLEX,MULTICAST,NEEDSGIANT> mtu 1500
lo0: flags=8049<UP,LOOPBACK,RUNNING,MULTICAST> mtu 16384
inet6 fe80::1%lo0 prefixlen 64 scopeid 0x4
inet6 ::1 prefixlen 128
inet 127.0.0.1 netmask 0xff000000
pflog0: flags=141<UP,RUNNING,PROMISC> mtu 33160
 
ah, see, you're not editing the file. pfctl -T add only adds to the kernel table, not the file. if you want it to stick, you have to add it to the file.

also we wouldn't put an on clause for these blocks, since you just want them to go away regardless of interface
 
ah, see, you're not editing the file. pfctl -T add only adds to the kernel table, not the file. if you want it to stick, you have to add it to the file.

also we wouldn't put an on clause for these blocks, since you just want them to go away regardless of interface
Okay, that makes sense.
But how do I use pfctl to add IPs to /etc/badhosts...and make the entries in badhosts permanent? Do I have the command wrong, or do I need a different command?

I've removed the "on" from the section of /etc/pf.conf:
table <badhosts> persist file "/etc/badguys"
block vr0 from <badhosts> to any
block sis0 from <badhosts> to any
 
A bit of an update..

After I removed the "on" from the block lines in /etc/pf.conf..
pfctl -nf /etc/pf.conf
returned a syntax error.

After readding the "on", the error's gone.

Also, I see that the /etc/badguys file (referenced in the table in /etc/pf.conf) has not updated for nearly a year even though they've been adding new IPs into it nearly every day.

# ls -l badguys
-rw-r--r-- 1 root wheel 77 Aug 5 2025 badguys
 
Okay, that makes sense.
But how do I use pfctl to add IPs to /etc/badhosts...and make the entries in badhosts permanent? Do I have the command wrong, or do I need a different command?

I've removed the "on" from the section of /etc/pf.conf:
you don't use pfctl to add IP's to that file. pfctl only deals with the in-memory copy. when you reboot, anything you did with pfctl -T add goes away.

you have use an editor on the file, like ee /etc/badguys, put the IP's in the file, and then you use pfctl -t badguys -T replace -f /etc/badguys to cause pf to re-read the file.

when the system starts up, it does the spiritual equivalent of that pfctl command as part of loading the rules.

and as far as the syntax error goes, you have to remove the whole on clause. block from <badguys> to any
 
you don't use pfctl to add IP's to that file. pfctl only deals with the in-memory copy. when you reboot, anything you did with pfctl -T add goes away.

you have use an editor on the file, like ee /etc/badguys, put the IP's in the file, and then you use pfctl -t badguys -T replace -f /etc/badguys to cause pf to re-read the file.

when the system starts up, it does the spiritual equivalent of that pfctl command as part of loading the rules.

and as far as the syntax error goes, you have to remove the whole on clause. block from <badguys> to any

Re adding IPs to /etc/badguys: So, rather than adding IPs via:
pfctl -t badhosts -T add <ip address>
....they'll need to manually enter each new IP they want to BLACKHOLE to /etc/badguys....then, run:
pfctl -t badhosts -T replace -f /etc/badguys

Re the block clause: So I need to delete both of the entire block lines in /etc/pf.conf....and leave only the table line?
 
re: the first thing, yes, assuming that's where the badguys file lives.

re: the block rule, on clause: no. you need the table line and the block rule, but the block rule can be simplified to block from <badguys> to any instead of having two rules that reference interfaces that may or may not exist

you should probably read pf.conf(5) (and we mean, like, actually read, not have chatgpt summarize for you)
 
re: the first thing, yes, assuming that's where the badguys file lives.

re: the block rule, on clause: no. you need the table line and the block rule, but the block rule can be simplified to block from <badguys> to any instead of having two rules that reference interfaces that may or may not exist

you should probably read pf.conf(5) (and we mean, like, actually read, not have chatgpt summarize for you)
My apologies. I'm a dyslexic and not very good with text-heavy man files, which is why I ask so many questions (and I'm one of the last six people who don't learn via chatbots). But I'll give the pf.conf man file a go..

I've changed pf.conf as you suggested....and now no syntax error! Brilliant! Thank you!!


I'm trying to simplify the process of BLACKHOLING new IPs for these guys so they don't have to edit /etc/badguys via a Windows text editor and, then, upload the updated file to their server. They access the server via ssh (Tera Term VT from Windows 11). I'd like to be able to have them edit /etc/badguys with nano via the ssh login and, then, run:
pfctl -t badhosts -T replace -f /etc/badguys

I recall that there's a way to add text (e.g., an IP address) to a text file (e.g., /etc/badguys) via an ssh login, but I can't remember the format?? Is it:
cat <ip address> >> /etc/badguys
Does that make sense??

Oh, and one more question: Can each IP address in /etc/badguys be placed on a single line with a space between each IP, or does each IP need to be on a separate line?
 
each IP needs to be on a separate line. We'd write a script like this and install it as something like /usr/local/bin/blackhole:
sh:
#!/bin/sh
for ip in "$@" ; do
  echo $ip >> /etc/badguys
done
pfctl -t badguys -T replace -f /etc/badguys

then they could do this:
blackhole 203.0.113.1 192.0.2.10
 
each IP needs to be on a separate line. We'd write a script like this and install it as something like /usr/local/bin/blackhole:
sh:
#!/bin/sh
for ip in "$@" ; do
  echo $ip >> /etc/badguys
done
pfctl -t badguys -T replace -f /etc/badguys

then they could do this:
blackhole 203.0.113.1 192.0.2.10
Wow, if it's that easy to append new IPs to the end of /etc/badguys....can I purchase this script from you to give them? This would be so much simpler than what they've been doing...
 
Back
Top