Тут было описан вариант GeoIP фильтрации с использованием xt_geoip из пакета раcширения xtables-addons для iptables, но практика показала частые ошибочные срабатывания на ip , которые должны быть разрешены + во многих дистрибутивах пакет xtables-addons идет “кривой” :(
В связи с выше изложенным, был найден более качественный вариант с использованием IPSET совместно с IPTABLES.
Все будет выполнено на шелл скриптах. Устанавливаем необходимое:
# sudo apt-get install ipset libnet-cidr-perl jq curl wget ipcalc grep gzip
Теперь пишем наш скрипт /etc/RU/block_noRU_geoip.sh для создания и обновления IPSET:
#!/bin/sh
echo "[start]"
# --- Тут не забудьте проверить правильность пути расположения программ
IPTABLES=/sbin/iptables
IPSET=/sbin/ipset
WGET=/usr/bin/wget
EGREP=/bin/egrep
GREP=/bin/grep
CAT=/bin/cat
SED=/bin/sed
CURL=/usr/bin/curl
GZIP=/bin/gzip
IPCALC=/usr/bin/ipcalc
JQ=/usr/bin/jq
BDDIR=/etc/RU
timestamp=$(date "+%Y-%m")
FILE=$BDDIR/$timestamp-ipcalc.ipv4
FIPSET=$BDDIR/$timestamp-ipset_ru.ipv4
echo "[1]"
# --- Получаем список ip для России
cd $BDDIR
#1#$WGET -q "https://download.db-ip.com/free/dbip-country-lite-$timestamp.csv.gz" -O- | \
#1# $GZIP -cd >$timestamp-dbip-country-lite.csv && $CAT $timestamp-dbip-country-lite.csv | \
#1# $GREP ',RU' | $SED 's/\,RU//g' | $SED 's/\,/-/g' | $GREP '\.' > $FILE
#2#$WGET -q "http://www.ipdeny.com/ipblocks/data/countries/ru.zone" -O $FIPSET
$CURL -k http://stat.ripe.net/data/country-resource-list/data.json?resource=ru | $JQ -c '.data.resources.ipv4[]' | $SED 's/\"//g' > $FIPSET
#1#if [ -f $FILE ]; then
#1# if [ -s $FILE ]; then
#1# echo "[2]"
#1# /usr/bin/perl -MNet::CIDR=range2cidr -lne 'print for range2cidr $_' $FILE > $FIPSET
# --- Переносим список ip сетей в ipset с именем таблиицы "russia_ru", а старый список в таблицу "russia_old"
if [ -f $FIPSET ]; then
if [ -s $FIPSET ]; then
echo "[3]"
$IPSET create russia_run hash:net
echo "[4]"
$IPSET create russia_old hash:net
echo "[5]"
$IPSET flush russia_old
echo "[6]"
$IPSET swap russia_run russia_old
echo "[7]"
for ippermitir in $($CAT $FIPSET)
do
$IPSET add russia_run $ippermitir
done
echo "[8]"
# --- На всякий случай добавляем серые сети ... можно не делать если Вам это не нужно
$IPSET add russia_run 10.0.0.0/8
$IPSET add russia_run 172.16.0.0/12
$IPSET add russia_run 192.168.0.0/16
fi
fi
#1# fi
#1#fi
echo "[stop]"
exit 0
Обращаем внимание, что в скрипте есть закомментированные строки в виде #1# или #2# - это разные источники списка ip адресов и соответственно их обработки для ipset.
Если Вам импонируют другие источники кроме RIPE, то предварительно закомментировав строку $CURL -k http://stat.ripe.net/data/country-resource-list/data.json?resource=ru | $JQ -c '.data.resources.ipv4[]' | $SED 's/\"//g' > $FIPSET
, раскомментируйте все #1# или #2# комментарии в зависимости от выбранного источника.
Проверить, что у нас все загрузилось правильно, можно командой
# ipset list
Теперь применяем наш список из IPSET в IPTABLES … в нашем случае для запрета всех пакетов с ip отсутствующих в таблице russia_ru для UDP SIP
# iptables -I INPUT -i eth0 -p udp -m multiport --dports 5000:50000 -m set ! --match-set russia_run src -j DROP
Обращаем внимание, что команда установит в самое начало списка наше правило, но это не всегда требуется, а иногда и вредно … вот пример заголовка моего файла конфигурации для iptables
-A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
-A INPUT -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
-A INPUT -i lo -j ACCEPT
-A INPUT -s 127.0.0.0/8 -j ACCEPT
-A INPUT -p gre -j ACCEPT
-A INPUT -p icmp -j ACCEPT
-A INPUT -i eth0 -s 10.0.0.0/8 -p udp -m udp --dport 5000:50000 -j ACCEPT
-A INPUT -i eth0 -s 172.16.0.0/12 -p udp -m udp --dport 5000:50000 -j ACCEPT
-A INPUT -i eth0 -p udp -m multiport --dports 5000:50000 -m set ! --match-set russia_run src -j LOG --log-prefix "BAD_SIP_No_Russia-IPSET: " --log-level 6
-A INPUT -i eth0 -p udp -m multiport --dports 5000:50000 -m set ! --match-set russia_run src -j DROP
…
Если у Вас будут вопросы, то связывайтесь со мной и постараюсь Вам помочь :)