Hopm Install Guide
In this guide, we'll setup and configure hopm, an open proxy monitor that kills spam bots.
Advantages:
Pure C
Compatible with every IRC server
Fast scanning and DNSBL support
Disadvantages:
Occasionally bans innocent users because it cannot perform statistical analysis
Before you begin, you must read the README and [INSTALL docs. Before you begin, you must read the README and [INSTALL docs.
Installation
Upgrades from older versions of hopm can also follow these instructions. You can see the version running in the log file /home/hopm/hopm/var/log/hopm.log
.
Let's create the user hopm:
$ doas useradd -m -g =uid -c "hopm" -d /home/hopm -s /bin/ksh hopm
Then we switch to the user hopm and change to its home folder:
$ doas su hopm
$ cd
We download the latest release, extract it, then build it:
$ ftp https://github.com/ircd-hybrid/hopm/archive/1.1.10.tar.gz
$ tar xvzf 1.1.10.tar.gz
$ cd hopm-1.1.10
$ ./configure
$ make
$ make install
hopm will now be installed in ~/hopm
.
/home/hopm/hopm/etc/reference.conf contains a sample template.
We'll create a new /home/hopm/hopm/etc/hopm.conf from scratch to keep it short:
options {
pidfile = "var/run/hopm.pid";
command_queue_size = 64;
command_interval = 10 seconds;
command_timeout = 180 seconds;
negcache_rebuild = 12 hours;
dns_fdlimit = 64;
dns_timeout = 5 seconds;
scanlog = "var/log/scan.log";
};
The only thing we change is we uncomment scanlog so that we have a record of all users that connect. It will be stored in /home/hopm/hopm/var/log/scan.log
.
irc {
nick = "MyHopm";
realname = "Hybrid Open Proxy Monitor";
username = "hopm";
server = "127.0.0.1";
port = 16667;
tls = no;
readtimeout = 15 minutes;
reconnectinterval = 30 seconds;
nickserv = "SQUERY NickServ :IDENTIFY MyHopm PASSWORD";
oper = "MyHopm PASSWORD";
mode = "+BcFiIoqRsw";
away = "I'm a bot. Your messages will be ignored.";
channel {
name = "#hopm";
key = "somekey";
invite = "SQUERY ChanServ :INVITE #hopm";
};
connregex = "Client connecting: ([^ ]+) \\(([^##ENDCODEBLOCK##
+)@([^\\)]+)\\) \\[([0-9a-f\\.:]+)\\].*";
kline = "KLINE *@%25h 3600 :Open proxy found on your host. Please contact support@example.com if this is in error.";
notice = "To prevent spam and abuse, we scan users for open proxies.";
};
Change the nick
, realname
, username
. server
, port
, tls
specify how to connect to your ircd. You will want to use 127.0.0.1 port 16667 with no TLS.
ngircd uses SQUERY
for nickserv
: SQUERY NickServ :IDENTIFY MyHopm PASSWORD
-- you'll want to replace MyHopm
with the real nick and PASSWORD
with the real password. For oper: MyHopm PASSWORD
-- you'll want to replace MyHopm
and PASSWORD
with the operator name and password.
We change the mode to +BcFiIoqRsw
. I recommend you change channel's name
from #hopm
to your team channel. invite
has been modified to match ngircd; replace #hopm
with your team channel.
For kline
, make sure to replace *@%25i
with *@%25h
(to allow hopm to work with old cloak hostmasks, which have been broken since April 2020. Note that hopm will not work with +x cloaking). You must also change the order for kline: in ngircd, kline expects the hostmask before the time. You will also want to replace support@example.com
with your actual support email.
WARNING: You must change the order for kline for ngircd:
kline = "KLINE *@%25h 3600 :Open proxy found on your host. Please contact support@example.com if this is in error.";
The hostmask must come before the time.
opm {
In our OPM block, we will define a few blacklists: dronbl, efnet, and ircbl.
blacklist {
name = "dnsbl.dronebl.org";
address_family = ipv4, ipv6;
type = "A record reply";
ban_unknown = no;
reply {
2 = "Sample data used for heuristical analysis";
3 = "IRC spam drone (litmus/sdbot/fyle)";
5 = "Bottler (experimental)";
6 = "Unknown worm or spambot";
7 = "DDoS drone";
8 = "Open SOCKS proxy";
9 = "Open HTTP proxy";
10 = "ProxyChain";
11 = "Web Page Proxy";
12 = "Open DNS Resolver";
13 = "Automated dictionary attacks";
14 = "Open WINGATE proxy";
15 = "Compromised router / gateway";
16 = "Autorooting worms";
17 = "Automatically determined botnet IPs (experimental)";
18 = "Possibly compromised DNS/MX type hostname detected on IRC";
19 = "Abused VPN Service";
255 = "Uncategorized threat class";
};
kline = "KLINE *@%25h 3600 :You have a host listed in the DroneBL. For more information, visit https://dronebl.org/lookup_branded?ip=%25i&network=<your_network_name>";
};
The name of the first blacklist is dnsbl.dronebl.org. It supports both ipv4 and ipv6 addresses. We use A record replies. We don't want to ban unknown types.
Note: Replace
For the kline, we again make sure to put the hostmask before the time (as ngircd requires). We also use %25h instead of %25i to kline by hostmask instead of by IP, since ngircd may be cloaking user IPs.
blacklist {
name = "rbl.efnetrbl.org";
type = "A record reply";
ban_unknown = no;
reply {
1 = "Open proxy";
2 = "spamtrap666";
3 = "spamtrap50";
4 = "TOR";
5 = "Drones / Flooding";
};
kline = "KLINE *@%25h 3600 :Blacklisted proxy found. For more information, visit https://rbl.efnetrbl.org/?i=%25i";
};
blacklist {
name = "tor.efnetrbl.org";
type = "A record reply";
ban_unknown = no;
reply {
1 = "TOR";
};
kline = "KLINE *@%25h 3600 :TOR exit node found. For more information, visit https://rbl.efnetrbl.org/?i=%25i";
};
The two blacklists from efnet are the same.
blacklist {
name = "rbl.ircbl.org";
type = "A record reply";
reply {
2 = "Open proxy (2)";
6 = "Mail or NS server (6)";
10 = "D regex pattern (10)";
11 = "Drone / compromised (11)";
13 = "Join/part flood (13)";
14 = "Drone / compromised 2 (14)";
16 = "Spam bot (16)";
17 = "Drone (17)";
18 = "Drone 2 (18)";
19 = "Web abuse (19)";
20 = "Drone/flood bot (20)";
21 = "Compromised host (21)";
22 = "Open Proxy (22)";
23 = "Open Proxy (23)";
24 = "Mass advertising (24)";
30 = "Drone (30)";
31 = "Drone 2 (31)";
32 = "Open proxy (32)";
42 = "Open proxy (42)";
};
ban_unknown = yes;
kline = "KLINE *@%25h 3600 :Compromised host on this IP. See https://ircbl.org/lookup?ip=%25i&network=<your_network_name> for more information.";
};
blacklist {
name = "tor-irc.dnsbl.oftc.net";
type = "A record reply";
reply {
2 = "Tor exit server";
};
ban_unknown = yes;
kline = "KLINE *@%25h 3600 :Please use our tor onion addresses. If this is in error, please email support@ircnow.org";
};
};
Note: Again, replace
This is another blacklist.
Next, we define a scanner block. hopm will try to get the user to connect to the target_ip:target_port using the listed port/protocol. A target_string will be sent through the proxy and then checked. If the data is found, the user is an proxy.
NOTE: target_ip must be an actual ip address. Replace 127.0.0.1 with your public IPv4 address.
scanner {
name = "default";
protocol = HTTP:80;
protocol = HTTP:8080;
protocol = HTTP:3128;
protocol = HTTP:6588;
# protocol = HTTPS:443;
# protocol = HTTPS:8443;
protocol = SOCKS4:1080;
protocol = SOCKS5:1080;
protocol = ROUTER:23;
protocol = WINGATE:23;
protocol = DREAMBOX:23;
protocol = HTTPPOST:80;
# protocol = HTTPSPOST:443;
# protocol = HTTPSPOST:8443;
# bind = "127.0.0.1";
fd = 512;
max_read = 4 kbytes;
timeout = 30 seconds;
target_ip = "127.0.0.1";
target_port = 6667;
target_string = "NOTICE * :*** Looking up your hostname and checking ident";
};
Two more scanner blocks:
scanner {
name = "extended";
protocol = HTTP:81;
protocol = HTTP:8000;
protocol = HTTP:8001;
protocol = HTTP:8081;
protocol = HTTPPOST:81;
protocol = HTTPPOST:6588;
protocol = HTTPPOST:4480;
protocol = HTTPPOST:8000;
protocol = HTTPPOST:8001;
protocol = HTTPPOST:8080;
protocol = HTTPPOST:8081;
protocol = SOCKS4:4914;
protocol = SOCKS4:6826;
protocol = SOCKS4:7198;
protocol = SOCKS4:7366;
protocol = SOCKS4:9036;
protocol = SOCKS5:4438;
protocol = SOCKS5:5104;
protocol = SOCKS5:5113;
protocol = SOCKS5:5262;
protocol = SOCKS5:5634;
protocol = SOCKS5:6552;
protocol = SOCKS5:6561;
protocol = SOCKS5:7464;
protocol = SOCKS5:7810;
protocol = SOCKS5:8130;
protocol = SOCKS5:8148;
protocol = SOCKS5:8520;
protocol = SOCKS5:8814;
protocol = SOCKS5:9100;
protocol = SOCKS5:9186;
protocol = SOCKS5:9447;
protocol = SOCKS5:9578;
protocol = SOCKS5:10000;
protocol = SOCKS5:64101;
protocol = SOCKS4:29992;
protocol = SOCKS4:38884;
protocol = SOCKS4:18844;
protocol = SOCKS4:17771;
protocol = SOCKS4:31121;
fd = 400;
};
scanner {
name = "ssh";
protocol = SSH:22;
target_string = "SSH-1.99-OpenSSH_5.1";
target_string = "SSH-2.0-dropbear_0.51";
target_string = "SSH-2.0-dropbear_0.52";
target_string = "SSH-2.0-dropbear_0.53.1";
target_string = "SSH-2.0-dropbear_2012.55";
target_string = "SSH-2.0-dropbear_2013.62";
target_string = "SSH-2.0-dropbear_2014.63";
target_string = "SSH-2.0-OpenSSH_4.3";
target_string = "SSH-2.0-OpenSSH_5.1";
target_string = "SSH-2.0-OpenSSH_5.5p1";
target_string = "SSH-2.0-ROSSSH";
target_string = "SSH-2.0-SSH_Server";
};
user {
mask = "*!*@*";
scanner = "default";
};
user {
mask = "*!~*@*";
mask = "*!squid@*";
mask = "*!nobody@*";
mask = "*!www-data@*";
mask = "*!cache@*";
mask = "*!CacheFlowS@*";
mask = "*!*@*www*";
mask = "*!*@*proxy*";
mask = "*!*@*cache*";
scanner = "extended";
};
exempt {
mask = "*!*@127.0.0.1";
};
Run Hopm
$ /home/hopm/hopm/bin/hopm -d
Cronjob
Put this script in /home/hopm/hopm/bin/autohopm
#!/bin/sh
HOPMPATH=/home/hopm/hopm
if test -r $HOPMPATH/var/run/hopm.pid; then
HOPMPID=$(cat $HOPMPATH/var/run/hopm.pid)
if $(kill -0 $HOPMPID >/dev/null 2>&1)
then
exit 0
fi
fi
$HOPMPATH/bin/hopm &> /dev/null
Then make sure execute privileges are set:
$ chmod 754 /home/hopm/hopm/bin/autohopm
$ crontab -e
*/5 * * * * /home/hopm/hopm/bin/autohopm
(:ifend:)
Troubleshooting
If you see this error:
[2021-01-23T09:59:14-0600] IRC -> connect(): error connecting to username.coconut.ircnow.org: Connection refused
[2021-01-23T09:59:14-0600] IRC -> Connection to (username.coconut.ircnow.org) failed, reconnecting.
[2021-01-23T09:59:14-0600] IRC -> connect(): error connecting to username.coconut.ircnow.org: Connection refused
This may be due to a configuration issue with ngircd. In particular, if the hostname has an AAAA record, hopm may be trying to connect via IPv6 but ngircd does not listen to IPv6 connections.
$ doas pkg_add torsocks
$ torsocks nc irc.example.com 6667
nick toruser
user toruser * * :toruser
In the #hopm
channel, you should see:
23:16 <MyHopm> DNSBL -> toruser!~toruser@vps-16fb7987.vps.ovh.ca [51.79.69.241] appears in BL zone rbl.efnetrbl.org (TOR)
Run Hopm as System Daemon
After you've created the rc.d script, append to /etc/rc.conf.local:
hopm_user=hopm ##ENDCODEBLOCK##
# Syntax errors when hopm is running in foreground. This is either the result of missing brackets where needed in config file, or that the file has DOS encodings. See [[https://github.com/ircd-hybrid/hopm/issues/22#issuecomment-301276082]] here. The missing brackets where it was needed may come from the previous section, compared to the line/s where it is indicated by hopm when executed.
# If the service fails to start, check and make sure `/home/hopm/hopm/var/log/hopm.log` is owned by hopm.