working module
Peter Molnar mail@petermolnar.net
Sun, 20 Sep 2026 15:50:04 +0100
3 files changed,
240 insertions(+),
0 deletions(-)
A
README.md
@@ -0,0 +1,102 @@
+# ngx-http-blocklistd + +This is a simple module for [nginx](https://nginx.org/) that communicates offending connections (IPs and ports) that visits honeypot locations to [blocklistd](https://man.netbsd.org/blocklistd.8). + +## Building and installing + +To build it and run it, you need the [source code of nginx](https://nginx.org/download/). To match your current system, run `nginx -V` and obtain the matching version. + +This is an example of building the module on a FreeBSD 15.1 system: + +```bash +mkdir -p /opt +cd /opt +git clone https://code.petermolnar.net/ngx-http-blocklistd +wget https://nginx.org/download/nginx-1.30.4.tar.gz +tar xf nginx-1.30.4.tar.gz +cd nginx +make clean +./configure --prefix=/usr/local/etc/nginx --with-cc-opt='-I /usr/local/include' --conf-path=/usr/local/etc/nginx/nginx.conf --sbin-path=/usr/local/sbin/nginx --pid-path=/var/run/nginx.pid --error-log-path=/var/log/nginx/error.log --user=www --group=www --with-compat --with-pcre --modules-path=/usr/local/libexec/nginx --with-file-aio --http-client-body-temp-path=/var/tmp/nginx/client_body_temp --http-fastcgi-temp-path=/var/tmp/nginx/fastcgi_temp --http-proxy-temp-path=/var/tmp/nginx/proxy_temp --http-scgi-temp-path=/var/tmp/nginx/scgi_temp --http-uwsgi-temp-path=/var/tmp/nginx/uwsgi_temp --http-log-path=/var/log/nginx/access.log --with-ld-opt='-L /usr/local/lib' --add-dynamic-module=/opt/ngx-http-blocklistd +make modules +cp -a objs/ngx_http_blocklistd_module.so /usr/local/libexec/nginx/ngx_http_blocklistd_module.so +``` + +Once done, add it to your `nginx.conf`: + +```nginx +load_module /usr/local/libexec/nginx/ngx_http_blocklistd.so; + +[...] +http { + [...] + server { + [...] + location xyz { + blocklistd; + } + } +} + +``` + +## Notes + +`nginx` needs a `restart` for all this to work properly. Changes, like including a new module were not picked up by `reload`. + +Also: the `blocklistd` keyword takes over the processing of the location, but not the access level stage. It means that for example, rate limiting can be applied. + +The module returns and internal HTTP 499 which terminates the connection as fast as possible. + +## Verifying + +To verify if it's running and sending signals you can either watch `blocklistctl dump` and/or turn on debug error logging in nginx by adding `debug` at the end of your `error_log` config line, like `error_log /var/log/nginx/error.log debug`. + +``` +blocklistctl dump -a +blocklistd 212.96.81.209/32:443 1/3 2026/09/19 14:26:39 +blocklistd 176.191.96.103/32:443 1/3 2026/09/19 14:49:16 +blocklistd 77.30.177.90/32:443 1/3 2026/09/19 15:05:50 +blocklistd 165.101.180.152/32:443 1/3 2026/09/19 15:19:37 +blocklistd 109.172.187.226/32:443 1/3 2026/09/19 16:04:49 +blocklistd 116.179.33.78/32:443 1/3 2026/09/19 16:20:22 +blocklistd 188.26.195.253/32:443 1/3 2026/09/19 16:49:16 +blocklistd 85.86.59.80/32:443 1/3 2026/09/19 17:15:08 +blocklistd 39.109.119.43/32:443 1/3 2026/09/19 18:06:57 +blocklistd 176.18.70.175/32:443 1/3 2026/09/19 14:04:56 +[...] +``` + + +## pf and blocklistd configuration + +For blocklistd to work with pf you need to add it to your `pf.conf`: + +``` +table <blocklistd> persist + +[...] + +anchor "blocklistd/*" +block in from <blocklistd> +``` + +You'll aso need to extend `/etc/blocklistd.conf` with http and https entries: + +```ini +[local] +ssh stream * * * 3 24h +ftp stream * * * 3 24h +smtp stream * * * 3 24h +submission stream * * * 3 24h +submissions stream * * * 3 24h +http stream * * * 3 24h +https stream * * * 3 24h + +``` + +To list the IPs: + +``` +pfctl -a blocklistd/80 -t port80 -T show +pfctl -a blocklistd/443 -t port443 -T show +```
A
config
@@ -0,0 +1,8 @@
+ngx_module_type=HTTP +ngx_addon_name=blocklistd +ngx_module_name=ngx_http_blocklistd_module +ngx_module_srcs="$ngx_addon_dir/ngx_http_blocklistd_module.c" +ngx_module_libs="-lblocklist" +CORE_LIBS="$CORE_LIBS $ngx_module_libs" + +. auto/module
A
ngx_http_blocklistd_module.c
@@ -0,0 +1,130 @@
+#include <ngx_config.h> +#include <ngx_core.h> +#include <ngx_http.h> +#include <blocklist.h> + +static struct blocklist *bl_state = NULL; + +static ngx_int_t ngx_http_blocklistd_handler(ngx_http_request_t *r); +static char *ngx_http_blocklistd( + ngx_conf_t *cf, + ngx_command_t *cmd, + void *conf +); +static ngx_int_t ngx_http_blocklistd_init_process(ngx_cycle_t *cycle); +static void ngx_http_blocklistd_exit_process(ngx_cycle_t *cycle); + + +static ngx_command_t ngx_http_blocklistd_commands[] = { + { ngx_string("blocklistd"), + NGX_HTTP_LOC_CONF|NGX_CONF_NOARGS, + ngx_http_blocklistd, + 0, + 0, + NULL + }, + ngx_null_command +}; + +static ngx_http_module_t ngx_http_blocklistd_module_ctx = { + NULL, /* preconfiguration */ + NULL, /* postconfiguration */ + NULL, /* create main configuration */ + NULL, /* init main configuration */ + NULL, /* create server configuration */ + NULL, /* merge server configuration */ + NULL, /* create location configuration */ + NULL /* merge location configuration */ +}; + + +ngx_module_t ngx_http_blocklistd_module = { + NGX_MODULE_V1, + &ngx_http_blocklistd_module_ctx, /* module context */ + ngx_http_blocklistd_commands, /* module directives */ + NGX_HTTP_MODULE, /* module type */ + NULL, /* init master */ + NULL, /* init module */ + ngx_http_blocklistd_init_process, /* init process */ + NULL, /* init thread */ + NULL, /* exit thread */ + ngx_http_blocklistd_exit_process, /* exit process */ + NULL, /* exit master */ + NGX_MODULE_V1_PADDING +}; + +static ngx_int_t ngx_http_blocklistd_init_process(ngx_cycle_t *cycle) { + bl_state = blocklist_open(); + if (bl_state == NULL) { + ngx_log_error( + NGX_LOG_ERR, + cycle->log, + 0, + "[blocklistd] init failed to open socket connection" + ); + } else { + ngx_log_error( + NGX_LOG_DEBUG, + cycle->log, + 0, + "[blocklistd] socket to blocklistd establised" + ); + } + return NGX_OK; +} + +static void ngx_http_blocklistd_exit_process(ngx_cycle_t *cycle) { + if (bl_state != NULL) { + blocklist_close(bl_state); + bl_state = NULL; + ngx_log_error( + NGX_LOG_DEBUG, + cycle->log, + 0, + "[blocklistd] socket to blocklistd stopped" + ); + + } +} + +static ngx_int_t ngx_http_blocklistd_handler(ngx_http_request_t *r) { + if (bl_state == NULL) { + ngx_log_error( + NGX_LOG_DEBUG, + r->connection->log, + 0, + "[blocklistd] socket connection lost? Trying to reconnect" + ); + bl_state = blocklist_open(); + } + + if (bl_state == NULL) { + ngx_log_error( + NGX_LOG_ERR, + r->connection->log, + 0, + "[blocklistd] no socket connection available" + ); + } else { + blocklist_r(bl_state, 1, r->connection->fd, "nginx"); + ngx_log_error( + NGX_LOG_DEBUG, + r->connection->log, + 0, + "[blocklistd] offense sent" + ); + } + + return NGX_HTTP_CLOSE; +} + +static char *ngx_http_blocklistd( + ngx_conf_t *cf, + ngx_command_t *cmd, + void *conf +){ + ngx_http_core_loc_conf_t *clcf; + clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module); + clcf->handler = ngx_http_blocklistd_handler; + return NGX_CONF_OK; +}