Assuming CSF wasn't going to tank your incoming requests and you still wanted to solve this problem of ACLing based on a dynamic list of incoming IP addresses, I would set up a server block in nginx (vhost) that directs you to the desired (or perhaps for the client, undesired) page. Then, I would set up an iptables rule that checks for the IP and on match, uses -j REDIRECT to send the client to the unusual port. I would use ipset (
http://ipset.netfilter.org/ ) to store the list of ips to redirect.
Requirements:
- ipset is not a kernel builtin for ovz, you need an HVM (Xen HVM, ESXi, KVM) to use custom kernel modules
- Enough free time to figure out how to build ipset and load it up.
Assumptions:
- The redirect IP file contains only single ip addresses (not CIDR 10.50.128.0/23 style address ranges), one per line.
- addresses in the IP file are retained until the IP should be removed from the redirect list.
script - mkIpset.sh
#!/bin/sh
REDIRECTFILE=/var/lib/redirect.lst
IPSETNAME=redirectlist
if ipset -n --list redirectlist > /dev/null
then
sort -u $REDIRECTFILE | awk 'BEGIN{print "-N '"$IPSETNAME"'-new iptreemap";} {print "-A '"$IPSETNAME"'-new $1";} END{print "COMMIT";}' | ipset -R
ipset -W "$IPSETNAME" "$IPSETNAME"-new
ipset -X "$IPSETNAME"-new
else
sort -u $REDIRECTFILE | awk 'BEGIN{print "-N '"$IPSETNAME"' iptreemap";} {print "-A '"$IPSETNAME"' $1";} END{print "COMMIT";}' | ipset -R
fi
iptables updates:
#!/bin/sh
#change this to match your system
IN_IP=10.0.0.20
IN_IF=eth0
IN_PORT=80
RD_PORT=82
IPSETNAME=redirectlist
iptables -t nat -A PREROUTING -i $IN_IF -p tcp --dport $IN_PORT -d $IN_IP -m set --match-set $IPSETNAME -j REDIRECT --to-port $RD_PORT
script - redirect_new.sh:
#!/bin/sh
REDIRECTFILE=/var/lib/redirect.lst
IPSETNAME=redirectlist
if [ "$#" == "0" ]; then
echo "Usage $0 ip [ip..ip]"
exit 1
fi
while (( "$#" )); do
if expr match "$1" '[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}' > /dev/null
then
echo "$1" >> "$REDIRECTFILE"
ipset -A "$IPSETNAME" "$1"
else
echo "Invalid IPv4:" $1
fi
shift;
done
script - unredirect.sh:
#!/bin/sh
REDIRECTFILE=/var/lib/redirect.lst
IPSETNAME=redirectlist
if [ "$#" == "0" ]; then
echo "Usage $0 ip [ip..ip]"
exit 1
fi
while (( "$#" )); do
if expr match "$1" '[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}' > /dev/null
then
TMP=`mktemp`
ipset -D "$IPSETNAME" "$1"
grep -v "$1" "$REDIRECTFILE" > "$TMP"
mv "$TMP" "$REDIRECTFILE"
else
echo "Invalid IPv4:" $1
fi
shift;
done
nginx_vhost: #adjust to preference
server {
listen 82 default_server;
server_name localhost;
root /var/www/redirectserver;
location / {
try_files $uri /blockpage.html;
}
}
Ipset is pretty flexible. I use it with pg2ipset.c with bluetack level1 lists for *coughbtcough*, from which I yanked most of the code. I wrote this up as a thought experiment though, so you might need to tweak it so it actually works right. ^^; If you're dealing with ipv6s, you'll have to use ip6tables, and make appropriate script changes. It would take very little to modifiy this to pull down say, a list of TOR exit nodes, and dump them in an ipset w/ redirect.
I would do it this way because unless you sit down with the nginx module api and implement red/black trees in memory, you're going to lose a lot of performance with every connection doing the disk hit for the redirect-or-not lookup. Better if you stored it in say bdb, worse if you do a list scan (ip block list volume dependent). Generally speaking, the conntrack table is going to be big enough to handle all your redirects and ipset lookup is extremely fast.
best regards,
-tw
edit: I would prefer if you folks did *not* delete this thread.