С некоторых пор мой сайт перестал справляться с нагрузкой. И как временную меру решил ограничить к нему доступ только для выделенных IP-адресов (публичный адрес домашней сетки, и адрес сети на работе). Для этого понадобилось загрузить в правила iptables публичный список адресов сканирования Google [1], представленный в формате JSON.
План такой:
1. Подготовить файл со списком разрешенных IP-адресов. Каждая строка в этом файле должна состоять из адреса сети и маски подсети: a.b.b.d/mask. Пример такого файла enabledIP:
# Возможно моя домашняя сеть будет среди этих IP:
95.31.169.0/24
# Публичные адреса сети на работе:
213.87.55.0/27
2. Загрузить список адресов ботов Google по ссылке [1] с помощью команды wget, сохранить его в файл.
3. Обработать загруженный на шаге 2 файл командой grep так, чтобы получился список из IP-адресов IPv4 с масками подсети, аналогичный списку сетей шага 1, и сохранить этот список в отдельный файл googleIP.
4. Сбросить текущие цепочки правил iptables командой iptables -F [2].
5. Загрузить для iptables в качестве разрешающих правил доступа подготовленные списки адресов enabledIP и googleIP, подготовленные на шагах 1 и 3. Загрузка адресов будет производиться командой:
iptables -I INPUT -s a.b.c.d/mask -j ACCEPT
Здесь "a.b.c.d/mask" это строка из файлов enabledIP и googleIP.
6. Добавить для iptables правило, отбрасывающее посторонний трафик командой:
iptables -A INPUT -p tcp --dport 80 -j DROP
[Реализация]
В результате получилась вот такая несложная программа:
// Эта программа была сделана для автоматического создания
// правил iptables из файла публичных адресов ботов Google,
// которые сканируют доступность сайтов. Этот файл доступен
// по ссылке:
// https://developers.google.com/search/apis/ipranges/googlebot.json
#include < stdio.h>
#include < stdlib.h>
#include < string.h>
#include < regex.h>
#include < stdbool.h>
#include < unistd.h>
#define GOOGLEBOTFILE "googlebot.json"
#define GOOGLEBOTFILECPY "googlebot.json.cpy"
#define GOOGLEBOTURL "https://developers.google.com/search/apis/ipranges/googlebot.json"
#define REGEXP "\"([0-9]{1,3}[\\.]){3}[0-9]{1,3}/[0-9]{1,2}\""
#define ENABLEDIPLIST "enabledIP"
#define GOOGLEIPLIST "googleIP"
bool fileexist (char *fn)
{
if (0 == access(fn, F_OK))
return true;
else
return false;
}
bool downloadGoogleList (char *gfn)
{
char command[256];
// Закачка файла:
strcpy(command, "wget ");
strcat(command, GOOGLEBOTURL);
system(command);
return fileexist(gfn);
}
void copyfile (char *src, char *dst)
{
char command[256];
strcpy(command, "cat ");
strcat(command, src);
strcat(command, " >");
strcat(command, dst);
system(command);
}
void makelist (char *src, char *dst)
{
char command[256];
strcpy(command, "grep -E -o ");
strcat(command, REGEXP);
strcat(command, " ");
strcat(command, src);
strcat(command, " >");
strcat(command, dst);
system(command);
}
void removefile (char *fn)
{
char command[256];
strcpy(command, "rm ");
strcat(command, fn);
system(command);
}
void iptables_flush (void)
{
char command[256];
strcpy(command, "iptables -F");
system(command);
}
void trim (char *s)
{
int i, j;
// Удаляем пробелы, табы, CR, LF с начала строки:
i = 0;
while ((' '==s[i])||('\t'==s[i])||('\r'==s[i])||('\n'==s[i])) i++;
if (i>0)
{
for(j=0; j < strlen(s); j++)
{
s[j] = s[j+i];
}
s[j] = 0;
}
// Удаляем пробелы, табы, CR, LF с конца строки:
i = strlen(s)-1;
while ((' '==s[i])||('\t'==s[i])||('\r'==s[i])||('\n'==s[i])) i--;
if (i < (strlen(s)-1))
s[i+1] = '\0';
}
void iptables_load_list (char *list)
{
char command[256];
FILE *fin;
char temp[80];
char *readresult;
fin = fopen(list, "r");
if (NULL == fin)
return;
// Обработаем список адресов построчно, и сформируем
// из его строк команды для iptables.
while(1)
{
readresult = fgets(temp, sizeof(temp)-1, fin);
if (NULL == readresult)
break;
trim(readresult);
// Пропуск пустых строк и строк комментариев:
if ((0 == strlen(readresult)) || ('#' == readresult[0]))
continue;
strcpy(command, "iptables ");
strcat(command, "-I INPUT -s ");
strcat(command, readresult);
strcat(command, " -j ACCEPT");
printf("%s\n", command);
system(command);
}
fclose(fin);
}
void iptables_restore (char *list)
{
char command[256];
// Добавление списка разрешенных адресов.
iptables_load_list(list);
// Всезапрещающее правило должно быть последним.
strcpy(command, "iptables -A INPUT -p tcp --dport 80 -j DROP");
printf("%s\n", command);
system(command);
}
int main (int argc, char **argv)
{
// Если файл закачался, то продолжим.
if (!downloadGoogleList(GOOGLEBOTFILE))
{
printf("%s download error\n", GOOGLEBOTFILE);
return 1;
}
// Сделаем копию файла:
copyfile(GOOGLEBOTFILE, GOOGLEBOTFILECPY);
// Обработка файла командой grep, чтобы
// выделить адреса:
makelist(GOOGLEBOTFILE, GOOGLEIPLIST);
// Удалим закачанный файл:
removefile (GOOGLEBOTFILE);
// Сброс правил iptables:
iptables_flush();
// Загрузка новых правил:
iptables_load_list(GOOGLEIPLIST);
// В конец добавятся правил из разрешенного списка,
// и правило для запрета посторонних обращений.
iptables_restore(ENABLEDIPLIST);
return 0;
}
[Дополнительная информация]
Как компилировать программу:
gcc mkiprules.c -o mkiprules
Как запускать (нужны права администратора):
После этого можно сделать загруженные правила постоянными командой:
iptables-save > /var/путь_до_автоматически_загружаемых_правил
Проверить корректность загрузки правил можно командой:
[Ссылки]
1. https://developers.google.com/search/apis/ipranges/googlebot.json. 2. Procedure to flush and delete ALL iptables firewall rules site:cyberciti.biz. 3. Защита Joomla с помощью iptables. 4. Добавление правил iptables для отражения атак на сервер. |