This time quick and simple trick to make your node_exporter report on the number of blocked and allowed packets by iptables. It involves a tiny script, and a small configuration change to the node_exporter. Here we go:
On your linux machine, as root, create the file /opt/iptables_metrics.sh with the following content:
#!/usr/bin/env bash
set -euo pipefail
export LC_ALL=C
OUTDIR="/var/lib/node_exporter"
OUTFILE="${OUTDIR}/iptables.prom"
TMP="$(mktemp "${OUTFILE}.XXXXXX")"
emit() { printf '%s\n' "$*" >>"$TMP"; }
emit "# HELP iptables_packets_total Total packets by verdict across all chains (filter table)."
emit "# TYPE iptables_packets_total counter"
emit "# HELP iptables_bytes_total Total bytes by verdict across all chains (filter table)."
emit "# TYPE iptables_bytes_total counter"
parse_family() {
local cmd="$1" fam="$2"
if ! command -v "$cmd" >/dev/null 2>&1; then
emit "# ${fam}: $cmd not found"
return
fi
# capture output (avoid pipe subshell); ignore stderr to handle permission warnings
local out
if ! out="$($cmd -t filter -L -v -n -x 2>/dev/null)"; then
emit "# ${fam}: cannot list rules (need CAP_NET_ADMIN/root?)"
return
fi
[ -n "$out" ] || { emit "# ${fam}: empty ruleset"; return; }
# do all math in awk, print final metrics
printf '%s\n' "$out" | awk -v fam="$fam" '
BEGIN { accp=accb=rejp=rejb=drpp=drpb=0 }
/^Chain / {
if (match($0, /\(policy ([A-Z]+) ([0-9]+) packets, ([0-9]+) bytes\)/, m)) {
pol=m[1]; pk=m[2]; by=m[3];
if (pol=="ACCEPT") { accp+=pk; accb+=by }
else if (pol=="REJECT") { rejp+=pk; rejb+=by }
else if (pol=="DROP") { drpp+=pk; drpb+=by }
}
next
}
# rule lines: pkts bytes TARGET ...
/^[[:space:]]*[0-9]+[[:space:]]+[0-9]+[[:space:]]+[!-~]+/ {
pk=$1; by=$2; tgt=toupper($3);
if (tgt=="ACCEPT") { accp+=pk; accb+=by }
else if (tgt=="REJECT") { rejp+=pk; rejb+=by }
else if (tgt=="DROP") { drpp+=pk; drpb+=by }
# targets like DOCKER, RETURN, f2b-sshd are chain jumps → not counted here
}
END {
printf "iptables_packets_total{family=\"%s\",verdict=\"accept\"} %d\n", fam, accp
printf "iptables_packets_total{family=\"%s\",verdict=\"reject\"} %d\n", fam, rejp
printf "iptables_packets_total{family=\"%s\",verdict=\"drop\"} %d\n", fam, drpp
printf "iptables_bytes_total{family=\"%s\",verdict=\"accept\"} %d\n", fam, accb
printf "iptables_bytes_total{family=\"%s\",verdict=\"reject\"} %d\n", fam, rejb
printf "iptables_bytes_total{family=\"%s\",verdict=\"drop\"} %d\n", fam, drpb
}' >>"$TMP"
}
parse_family iptables ipv4
parse_family ip6tables ipv6
chmod 644 "$TMP"
mv -f "$TMP" "$OUTFILE"
Make sure the output directory is present and writeable by root: sudo mkdir -p /var/lib/node_exporter
Now, search for your node exporter service file, this is usually called /etc/systemd/system/node_exporter.service . Edit this file and make sure node_exporter scans the /var/lib/node_exporter directory:
[Unit] Description=Node Exporter Prometheus Metrics Wants=network-online.target After=network-online.target [Service] User=prometheus ExecStart=/opt/node_exporter/node_exporter \ --collector.textfile.directory=/var/lib/node_exporter [Install] WantedBy=default.target
Now the only thing missing is triggering the iptables_metrics.sh script. Simply make it run every minute by adding it to your crontab. Open the crontab editor with sudo crontab -e and add the following line at the end of the crontab entries:
* * * * * /opt/iptables_metrics.sh >> /var/log/iptables_metrics.log 2>&1
Please note that output is written to /var/log/iptables_metrics.log without any size limit, you might want to check that log file every once in a while. If all goes well, there should be no log entries in that file.
When everything is setup correctly, you will see the file /var/lib/node_exporter/iptables.prom appear with the following contents:
# HELP iptables_packets_total Total packets by verdict across all chains (filter table).
# TYPE iptables_packets_total counter
# HELP iptables_bytes_total Total bytes by verdict across all chains (filter table).
# TYPE iptables_bytes_total counter
iptables_packets_total{family="ipv4",verdict="accept"} 10409167
iptables_packets_total{family="ipv4",verdict="reject"} 1
iptables_packets_total{family="ipv4",verdict="drop"} 0
iptables_bytes_total{family="ipv4",verdict="accept"} 4554837838
iptables_bytes_total{family="ipv4",verdict="reject"} 60
iptables_bytes_total{family="ipv4",verdict="drop"} 0
iptables_packets_total{family="ipv6",verdict="accept"} 0
iptables_packets_total{family="ipv6",verdict="reject"} 0
iptables_packets_total{family="ipv6",verdict="drop"} 0
iptables_bytes_total{family="ipv6",verdict="accept"} 0
iptables_bytes_total{family="ipv6",verdict="reject"} 0
iptables_bytes_total{family="ipv6",verdict="drop"} 0
This data will be picked up by your node_exporter and should show up when you do a curl localhost:9100/metrics.
Please note that if you use fail2ban or docker, the counters can reset. For instance, fail2ban can take an ip address out of jail and modify the rules, thereby removing a rule and thus a counter. If you use rates in your monitoring setup (victoria metrics or prometheus), this will not be a problem, as a “rate” can handle resets.
This simple trick also lets you add other data you can gather with a script. Put it in a separate file with a logical name in the /var/lib/node_exporter folder and it will become parts of your metrics endpoint.
I hope this simple trick helps, cheers!