Продолжая «цикл» заметок (1, 2, 3) хочу рассказать о новом опыте взаимодействия с «ИТ-Гигантами», которые либо самостоятельно создают большую нагрузку на сервис, либо позволяют это делать своим клиентам.
В какой-то момент полумеры уже не помогают и приходит понимание того, что ALICLOUD или TENCENT, а может и META надо банить целиком. Бан по USERAGENT на самом деле работает, но во-первых не всегда, т.к. большое количество запросов «из Алибабы» являются клиентскими, а не запросами от самого сервиса, а во-вторых, если миллион запросов в час вернут 403, это всё равно будет миллион запросов в час.
Код предложенный ниже не претендует в общем ни на универсальность ни даже на работоспособность, написан без новомодного AI и предназначен скорее для иллюстрации возможностей и проблем. Список «ИТ-Гигантов», и списки их AS я стрил вручную, ну а далее всё в общем довольно прозрачно. Комментарии написаны больше для наглядности в рамках данной заметки:
# Проверка прав суперпользователя
if [ "$EUID" -ne 0 ]; then
echo "Запустите скрипт с правами root (sudo)"
exit 1
fi
# Ассоциативный массив: Название компании -> Список ее ASN
declare -A GIANTS
GIANTS=(
["alicloud"]="AS37963 AS45102 AS135377"
["tencent"]="AS132203 AS133478 AS45090"
["huawei"]="AS136901 AS55990 AS136959"
["linode"]="AS63949 AS8075"
["amazon"]="AS16509 AS14618 AS8987 AS33070"
["meta"]="AS32934 AS63293"
)
for COMPANY in "${!GIANTS[@]}"; do
ASN_LIST=${GIANTS[$COMPANY]}
SET_NAME="bl_${COMPANY}"
TMP_SET_NAME="${SET_NAME}_tmp"
echo "=== Обработка $COMPANY ==="
# 1. Создаем временный ipset
ipset create $TMP_SET_NAME hash:net -exist
ipset flush $TMP_SET_NAME
# Флаг для отслеживания успешности наполнения подсетями
HAS_NETWORKS=false
# 2. Опрашиваем сервер WHOIS (RADB)
for ASN in $ASN_LIST; do
echo "Получение сетей для $ASN..."
# Исправленный синтаксис запроса с передачей параметров через -- ""
networks=$(whois -h whois.radb.net -- "-i origin $ASN" | awk '/^route:/ {print $2}')
# Проверяем, удалось ли получить хоть одну сеть для этой AS
if [ -n "$networks" ]; then
for net in $networks; do
ipset add $TMP_SET_NAME "$net" -exist 2>/dev/null
done
HAS_NETWORKS=true
fi
sleep 10 # <--- ДОБАВЬТЕ СЮДА ЭТУ СТРОКУ ДЛЯ ЗАЩИТЫ ОТ БАНА!
done
# Защита: если по всем AS компании получен пустой ответ (например, проблема с сетью)
if [ "$HAS_NETWORKS" = false ]; then
echo "Предупреждение: Не удалось получить данные из WHOIS для $COMPANY. Обновление отменено."
ipset destroy $TMP_SET_NAME
echo "------------------------------------------------"
continue
fi
# 3. Создаем основной ipset, если его нет
ipset create $SET_NAME hash:net -exist
# 4. Атомарно обновляем список (подмена старого списка новым)
ipset swap $TMP_SET_NAME $SET_NAME
# 5. Удаляем временный ipset
ipset destroy $TMP_SET_NAME
# 6. Интеграция с iptables
if ! iptables -C INPUT -m set --match-set $SET_NAME src -j DROP 2>/dev/null; then
echo "Добавление правила блокировки в iptables для $SET_NAME..."
iptables -I INPUT 1 -m set --match-set $SET_NAME src -j DROP
else
echo "Правило iptables для $SET_NAME уже активно."
fi
# --- ВЫВОД СПИСКА СЕТЕЙ И ТОЧНОГО СЧЕТЧИКА ---
echo "Заблокированные сети для $COMPANY:"
# Корректное вырезание служебного заголовка ipset
net_list=$(ipset list $SET_NAME | sed -e '1,/Members:/d')
if [ -n "$net_list" ]; then
# echo "$net_list" # <--- ЭТА СТРОКА ВЫВОДИТ САМ СПИСОК ПОД СЕТЕЙ
net_count=$(echo "$net_list" | wc -l)
else
echo "[Список пуст]"
net_count=0
fi
echo "Итого заблокировано сетей для $COMPANY: $net_count"
echo "------------------------------------------------"
done
Комментировать код выше едва ли нужно. Код ниже убирает всё то, что сделал код выше:
# Проверка прав суперпользователя
if [ "$EUID" -ne 0 ]; then
echo "Запустите скрипт с правами root (sudo)"
exit 1
fi
# Названия ИТ-гигантов должны точно совпадать со списком из первого скрипта
GIANTS=("alicloud" "tencent" "huawei" "linode" "amazon" "meta")
echo "=== Запуск процесса удаления правил блокировки ==="
for COMPANY in "${GIANTS[@]}"; do
SET_NAME="bl_${COMPANY}"
TMP_SET_NAME="${SET_NAME}_tmp"
echo "Обработка $COMPANY..."
# 1. Удаление правил из iptables
# Цикл while необходим на случай, если правило было случайно продублировано в INPUT несколько раз
while iptables -C INPUT -m set --match-set $SET_NAME src -j DROP 2>/dev/null; do
echo "Удаление правила iptables для $SET_NAME..."
iptables -D INPUT -m set --match-set $SET_NAME src -j DROP
done
# 2. Удаление временного списка ipset (если он остался после аварийного завершения основного скрипта)
if ipset list $TMP_SET_NAME &>/dev/null; then
echo "Удаление временного списка $TMP_SET_NAME..."
ipset destroy $TMP_SET_NAME
fi
# 2. Очистка и удаление основного списка ipset
if ipset list $SET_NAME &>/dev/null; then
echo "Очистка содержимого списка $SET_NAME..."
ipset flush $SET_NAME
echo "Уничтожение списка $SET_NAME..."
ipset destroy $SET_NAME
fi
echo "Все правила и списки для $COMPANY успешно удалены."
echo "------------------------------------------------"
done
echo "=== Очистка полностью завершена ==="
Если раскомментировать в первом скрипте одну строчку, то помимо количества сетей которые добавятся в ipset список, будет собственно еще и перечень, но там тысячи сетей, поэтому строчка закомментирована.
И казалось бы всё хорошо, но, в скрипте используется whois, что требует открытого 43 порта, а он много где закрыт. Это раз. Подобный опрос («А выдайте мне все айпишники фейсбука» — это сложный запрос) запросто может привести к 24 часам бана клиента, что тоже не очень здорово. И что же делать? А забыть об автоматизации и интерактивности и сделать как-нибудь так для бана:
# Функция для создания, очистки и заполнения индивидуального ipset
deploy_ipset() {
local set_name="$1"
local cidr_block="$2"
# Создаем персональный список, если он не существует
ipset create "$set_name" hash:net -exist
# Очищаем старые записи
ipset flush "$set_name"
# Построчно добавляем адреса
while read -r cidr; do
[[ -z "$cidr" || "$cidr" =~ ^# ]] && continue
ipset add "$set_name" "$cidr" -exist 2>/dev/null
done <<< "$cidr_block"
# Добавляем индивидуальные правила в iptables (Вход и Выход), если их нет
iptables -C INPUT -m set --match-set "$set_name" src -j DROP 2>/dev/null || iptables -I INPUT -m set --match-set "$set_name" src -j DROP
# iptables -C OUTPUT -m set --match-set "$set_name" dst -j DROP 2>/dev/null || iptables -I OUTPUT -m set --match-set "$set_name" dst -j DROP
# Считаем количество добавленных сетей
# local count=$(ipset list "$set_name" | grep -E -c "([0-9]{1,3}\.){3}[0-9]{1,3}")
local count=$(ipset list "$set_name" | grep "Number of entries" | awk '{print $4}')
echo "Список [$set_name] обновлен. Заблокировано сетей: $count"
}
echo "Запуск раздельной блокировки ИТ-гигантов (Offline режим)..."
echo "--------------------------------------------------------"
# --- БАЗЫ ДАННЫХ ДЛЯ КАЖДОГО "ПАРТНЁРА" ---
ALIBABA="
8.208.0.0/12
47.74.0.0/15
47.76.0.0/14
47.80.0.0/12
47.235.0.0/16
47.236.0.0/14
47.240.0.0/13
47.248.0.0/13
106.11.0.0/16
140.205.0.0/16
161.117.0.0/16
170.106.0.0/15
205.204.0.0/16
"
TENCENT="
43.128.0.0/12
49.51.0.0/16
81.68.0.0/14
101.32.0.0/14
119.28.0.0/15
124.156.0.0/16
129.226.0.0/16
150.109.0.0/16
152.136.0.0/16
159.75.0.0/16
162.14.0.0/16
203.205.128.0/17
"
BAIDU="
100.95.0.0/16
106.12.0.0/14
111.206.0.0/16
112.80.248.0/22
119.63.192.0/21
180.76.0.0/16
182.61.0.0/16
220.181.0.0/16
"
BYTEDANCE="
5.181.24.0/22
14.1.28.0/22
47.251.0.0/16
114.134.112.0/21
117.114.248.0/21
130.45.0.0/16
150.242.120.0/21
154.212.0.0/16
161.117.140.0/22
205.220.224.0/22
"
META="
31.13.24.0/21
31.13.64.0/18
45.64.40.0/22
66.220.144.0/20
69.63.176.0/20
69.171.224.0/19
74.119.76.0/22
102.132.96.0/20
103.4.96.0/22
129.134.0.0/16
157.240.0.0/16
173.252.64.0/18
179.60.192.0/22
185.60.216.0/22
204.15.20.0/22
"
AMAZON="
3.0.0.0/9
13.32.0.0/15
13.34.0.0/15
13.248.0.0/14
15.177.0.0/16
18.154.0.0/15
18.164.0.0/14
18.208.0.0/13
34.192.0.0/12
35.153.0.0/16
35.160.0.0/13
44.192.0.0/11
52.0.0.0/10
54.64.0.0/11
54.144.0.0/12
54.192.0.0/12
54.240.0.0/12
99.77.0.0/16
99.80.0.0/13
108.128.0.0/13
143.204.0.0/16
176.32.96.0/21
176.34.0.0/16
204.246.160.0/19
205.251.192.0/18
"
LINODE="
23.239.0.0/18
45.33.0.0/17
45.56.64.0/18
45.79.0.0/16
50.116.0.0/17
66.175.208.0/20
66.228.32.0/19
69.164.192.0/19
72.14.176.0/20
74.207.224.0/19
96.126.96.0/19
97.107.128.0/18
104.200.16.0/20
104.237.128.0/19
109.74.192.0/19
139.162.0.0/16
151.236.216.0/21
172.104.0.0/15
173.230.128.0/19
173.255.192.0/18
178.79.128.0/19
192.155.192.0/18
192.168.0.0/16
198.58.96.0/19
213.219.36.0/22
"
# --- РАЗВЕРТЫВАНИЕ ---
deploy_ipset "block_alibaba" "$ALIBABA"
deploy_ipset "block_tencent" "$TENCENT"
deploy_ipset "block_baidu" "$BAIDU"
deploy_ipset "block_bytedance" "$BYTEDANCE"
deploy_ipset "block_meta" "$META"
deploy_ipset "block_amazon" "$AMAZON"
deploy_ipset "block_linode" "$LINODE"
echo "--------------------------------------------------------"
echo "Все списки успешно изолированы и заблокированы в iptables."
И вот так для разбана:
# Функция, которая мгновенно открывает трафик, не ломая зависимости ядра
undeploy_ipset() {
local set_name="$1"
echo "Разблокировка трафика для [$set_name]..."
if ! ipset list "$set_name" &>/dev/null; then
echo "-> Список [$set_name] не найден. Пропускаем."
return 0
fi
# 1. Очищаем все IP-адреса внутри списка.
# Список остается пустым -> блокировка полностью снимается, трафик идет свободно.
if ipset flush "$set_name" 2>/dev/null; then
echo "-> Трафик разблокирован. Список [$set_name] очищен."
else
echo "[ОШИБКА] Не удалось очистить список [$set_name]."
fi
}
echo "Запуск разблокировки ИТ-гигантов..."
echo "--------------------------------------------------------"
undeploy_ipset "block_alibaba"
undeploy_ipset "block_tencent"
undeploy_ipset "block_baidu"
undeploy_ipset "block_bytedance"
undeploy_ipset "block_meta"
undeploy_ipset "block_amazon"
undeploy_ipset "block_linode"
echo "--------------------------------------------------------"
echo "Все списки очищены. Блокировки сняты, трафик полностью разрешен."
Понятно что списки не полны и не стоит использовать их как эталонные справочники, это скорее иллюстрация, чем готовый инструмент.
Чтобы понять на сколько не полнон список подсетей, можно посмотреть на пример работы «первого» скрипта:
=== Обработка meta ===
Получение сетей для AS32934...
Получение сетей для AS63293...
Добавление правила блокировки в iptables для bl_meta...
Заблокированные сети для meta:
Итого заблокировано сетей для meta: 539
------------------------------------------------
=== Обработка linode ===
Получение сетей для AS63949...
Получение сетей для AS8075...
Добавление правила блокировки в iptables для bl_linode...
Заблокированные сети для linode:
Итого заблокировано сетей для linode: 1922
------------------------------------------------
=== Обработка amazon ===
Получение сетей для AS16509...
Задержка.
Получение сетей для AS14618...
Получение сетей для AS8987...
Получение сетей для AS33070...
Добавление правила блокировки в iptables для bl_amazon...
Заблокированные сети для amazon:
Итого заблокировано сетей для amazon: 20497
------------------------------------------------
=== Обработка alicloud ===
Получение сетей для AS37963...
Задержка.
Получение сетей для AS45102...
Задержка.
Получение сетей для AS135377...
Добавление правила блокировки в iptables для bl_alicloud...
Заблокированные сети для alicloud:
Итого заблокировано сетей для alicloud: 47128
------------------------------------------------
=== Обработка huawei ===
Получение сетей для AS136901...
Получение сетей для AS55990...
Получение сетей для AS136959...
Добавление правила блокировки в iptables для bl_huawei...
Заблокированные сети для huawei:
Итого заблокировано сетей для huawei: 458
------------------------------------------------
=== Обработка tencent ===
Получение сетей для AS132203...
Получение сетей для AS133478...
Получение сетей для AS45090...
Добавление правила блокировки в iptables для bl_tencent...
Заблокированные сети для tencent:
Итого заблокировано сетей для tencent: 6213
------------------------------------------------
tomcat@elar:~#
По опыту администрируемых репозиториев могу сказать что пристальное внимание требуется за активностью MS BING, META и за китайскими товарищами. В случае с Amazon сам по себе Amazonbot тоже может доставлять неудобства, но заметном еньшие чем боты META, а вот клиенты AWS могут сильно нагружать сервис. Но, банить AWS целиком это наверное слишком круто.
[UPD]
Еще пара скриптов по бану и разбану автономками, но на системах с закрытым 43 портом
Бан:
# Проверка прав суперпользователя
if [ "$EUID" -ne 0 ]; then
echo "Запустите скрипт с правами root (sudo)"
exit 1
fi
# Проверка наличия jq и wget
for cmd in jq wget; do
if ! command -v $cmd &> /dev/null; then
echo "Ошибка: утилита $cmd не установлена."
exit 1
fi
done
# Ассоциативный массив: Название компании -> Список ее ASN
declare -A GIANTS
GIANTS=(
["alicloud"]="AS37963 AS45102"
["ucloud"]="AS135377"
["tencent"]="AS132203 AS133478 AS45090"
["huawei"]="AS136901 AS55990 AS136959"
["linode"]="AS63949 AS8075"
["amazon"]="AS16509 AS14618 AS8987 AS33070"
["meta"]="AS32934 AS63293"
)
# Разбиваем базовый рабочий URL на независимые части
PROTO="https://"
DOMAIN="stat.ripe.net"
PATH_URI="/data/announced-prefixes/data.json"
PARAM="?resource="
for COMPANY in "${!GIANTS[@]}"; do
ASN_LIST=${GIANTS[$COMPANY]}
SET_NAME="bl_${COMPANY}"
TMP_SET_NAME="${SET_NAME}_tmp"
echo "=== Обработка $COMPANY ==="
# 1. Создаем временный ipset
ipset create "$TMP_SET_NAME" hash:net -exist
ipset flush "$TMP_SET_NAME"
HAS_NETWORKS=false
# 2. Опрашиваем RIPE STAT API через wget и парсим jq
for ASN in $ASN_LIST; do
# Очищаем ASN, оставляя только цифры
ASN_NUM=$(echo "$ASN" | tr -d -c '0-9')
echo "Получение сетей для AS${ASN_NUM}..."
# Собираем чистый, оригинальный URL из сегментов
API_URL="${PROTO}${DOMAIN}${PATH_URI}${PARAM}${ASN_NUM}"
# Запрос к API RIPE
networks=$(wget -qO- "$API_URL" | jq -r '.data.prefixes[].prefix' 2>/dev/null)
if [ -n "$networks" ] && [ "$networks" != "null" ]; then
for net in $networks; do
# Исключаем IPv6 (содержат двоеточие)
if [[ ! "$net" =~ ":" ]]; then
ipset add "$TMP_SET_NAME" "$net" -exist 2>/dev/null
fi
done
HAS_NETWORKS=true
fi
done
# Защита: если по всем AS компании получен пустой ответ
if [ "$HAS_NETWORKS" = false ]; then
echo "Предупреждение: Не удалось получить данные из RIPE API для $COMPANY. Обновление отменено."
ipset destroy "$TMP_SET_NAME"
echo "------------------------------------------------"
continue
fi
# 3. Создаем основной ipset, если его нет
ipset create "$SET_NAME" hash:net -exist
# 4. Атомарно обновляем список
ipset swap "$TMP_SET_NAME" "$SET_NAME"
# 5. Удаляем временный ipset
ipset destroy "$TMP_SET_NAME"
# 6. Интеграция с iptables
if ! iptables -C INPUT -m set --match-set "$SET_NAME" src -j DROP 2>/dev/null; then
echo "Добавление правила блокировки в iptables для $SET_NAME..."
iptables -I INPUT 1 -m set --match-set "$SET_NAME" src -j DROP
else
echo "Правило iptables для $SET_NAME уже активно."
fi
# --- ВЫВОД СПИСКА СЕТЕЙ И ТОЧНОГО СЧЕТЧИКА ---
echo "Заблокированные сети для $COMPANY:"
net_list=$(ipset list "$SET_NAME" | sed -e '1,/Members:/d')
if [ -n "$net_list" ]; then
net_count=$(echo "$net_list" | wc -l)
else
echo "[Список пуст]"
net_count=0
fi
echo "Итого заблокировано сетей для $COMPANY: $net_count"
echo "------------------------------------------------"
done
Разбан:
# Проверка прав суперпользователя
if [ "$EUID" -ne 0 ]; then
echo "Пожалуйста, запустите скрипт с правами root (sudo)."
exit 1
fi
# Названия ИТ-гигантов должны точно совпадать со списком из первого скрипта
GIANTS=("alicloud" "ucloud" "tencent" "huawei" "linode" "amazon" "meta")
echo "=== Запуск процесса удаления правил блокировки ==="
for COMPANY in "${GIANTS[@]}"; do
SET_NAME="bl_${COMPANY}"
TMP_SET_NAME="${SET_NAME}_tmp"
echo "Обработка $COMPANY..."
# 1. Удаление правил из iptables
# Цикл while необходим на случай, если правило было случайно продублировано в INPUT несколько раз
while iptables -C INPUT -m set --match-set $SET_NAME src -j DROP 2>/dev/null; do
echo "Удаление правила iptables для $SET_NAME..."
iptables -D INPUT -m set --match-set $SET_NAME src -j DROP
done
# 2. Удаление временного списка ipset (если он остался после аварийного завершения основного скрипта)
if ipset list $TMP_SET_NAME &>/dev/null; then
echo "Удаление временного списка $TMP_SET_NAME..."
ipset destroy $TMP_SET_NAME
fi
# 3. Очистка и удаление основного списка ipset
if ipset list $SET_NAME &>/dev/null; then
echo "Очистка содержимого списка $SET_NAME..."
ipset flush $SET_NAME
echo "Уничтожение списка $SET_NAME..."
ipset destroy $SET_NAME
fi
echo "Все правила и списки для $COMPANY успешно удалены."
echo "------------------------------------------------"
done
echo "=== Очистка полностью завершена ==="
Оно по логике не сильно отличается от варианта с whois, но вроде работает там, где 43 порт закрыт. Как всегда, решение не претендует на изащнсоть и является только иллюстрацией.
