notes/iptables.md

302 lines
14 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

# iptables
- [iptables](#iptables)
- [Таблицы](#таблицы)
- [Цепочки](#цепочки)
- [Правила - условия и действия](#правила---условия-и-действия)
- [Просмотр](#просмотр)
- [Управление правилами и цепочками](#управление-правилами-и-цепочками)
- [Примеры](#примеры)
- [Пример первоначальной настройки](#пример-первоначальной-настройки)
- [Сброс всех правил цепочки filter](#сброс-всех-правил-цепочки-filter)
- [Отладка](#отладка)
- [Логирование отклоненных пакетов journald](#логирование-отклоненных-пакетов-journald)
- [Логирование отклоненных пакетов Rsyslog](#логирование-отклоненных-пакетов-rsyslog)
***
## Таблицы
- `filter` - основная таблица для фильтрации пакетов, используется по умолчанию;
- `nat` - управление преобразованием сетевых адресов;
- `mangle` - модификация и замена содержимого сетевых пакетов вне контекста NAT и фильтрации пакетов;
- `raw` - предназначена для работы с сырыми пакетами, пока они еще не прошли обработку
## Цепочки
Цепочки бывают базовые/встроенные и пользовательские (можно создать самому).
В новую цепочку можно направлять пакеты чтобы подвергуть их анализу правил. Например для отладки правил или настройки особого движения пакетов как это сделано в Docker
- `INPUT` - входящий трафик (адресованный локальному хосту);
- `FORWARD` - транзитный трафик поступающий на локальную машину с целью передачи его на другую машину (трафик передаваемый в docker контейнер тоже будет считаться транзитным), при этом транзитный трафик проходит в обоих направлениях;
- `OUTPUT` - исходящий из локального хоста трафик
## Правила - условия и действия
Правило - состоит из условия/критерия (если нет значит применяется ко всему трафику) действия (может не быть) и счетчика (для учета пакетов попавших под правило).
основные действия с правилами:
- `-A` - добавить правило в цепочку;
- `-С` - проверить все правила;
- `-D` - удалить правило;
- `-I` - вставить правило с нужным номером;
- `-L` - вывести все правила в текущей цепочке;
- `-S` - вывести все правила;
- `-F` - очистить все правила;
- `-N` - создать цепочку;
- `-X` - удалить цепочку;
- `-P` - установить действие по умолчанию.
Условия:
- `-p` - протокол (TCP, UDP, ICMP, ALL);
- `-s` - ip адрес источника (можно с маской 10.0.0.0/24), допускается отрицание (т.е. все кроме) `-s ! 10.0.0.0/24`;
- `-d` - ip адрес получателя (аналогично `-s`);
- `-i` - интерфейс с которого пришел пакет (только для `INPUT`, `FORWARD`, `PREROUTING`), например `ens3`, допускается указать `ens+` что означает все имена интерфейсов начинающиеся с заданной строки, допускается отрицание `-i ! ens+`;
- `-o` - интерфейс локального хоста, из которого выходит трафик (только для `OUTPUT`, `FORWARD`, `PREROUTING`);
- `--sport` - порт с которого был отправлен TCP/UDP пакет (допускаются имена служб из `/etc/services`), поддерживаются диапазоны вида `20:80` что значит от 20 до 80 порта, так же можно опустить одно из значений `:80` (от 0 до 80) или `20:` (от 20 до 65535), отрицание поддерживается даже к диапазонам `--sport ! 20:80`;
- `--dport` - аналогично `--sport` только речь идет про порт, которому адресован пакет;
- `--icmp-type` - тип ICMP сообщения (номер или название), поддерживается отрицание. RFC 792 или `iptables --protocol icmp --help`;
- `-m mac --mac-source` - MAC адрес устройства передавшего пакет, поддерживается отрицание;
- `-m state --state` - состояние соединения:
- `INVALID` - неизвестное соединение, возможно ошибочное;
- `NEW` - новое соединение;
- `ESTABLISHED` - уже установленное соединение;
- `RELATED` - пакет принадлежит уже существующему соединению, но он отправляется по новому
- `-m ttl` - Time To Live:
- `--ttl-eq N` - TTL пакета равен N;
- `--ttl-lt N` - TTL пакета меньше N;
- `--ttl-gt N` - TTL пакета больше N
- `-m multiport` - указать в правиле несколько портов, диапазон или набор:
- `-m multiport --dports 8080,22,80` - применяется к указанным портам;
- `-m multiport --dports 1024:65535` - применяется к диапазону портов
Действия:
- `ACCEPT` - пакет принят в текущей таблице;
- `DROP` - пакет сбрасывается и перестает движение в системе;
- `LOG` - пакет журналируется и продолжает дальнейшие движение по цепочке правил и таблицам (рассмотрим ниже)
- `REJECT` - аналогично DROP только отдает сообщение об ошибке на хост отправителя (работает на всех цепочках таблицы filter):
- `--reject-with` - тип ответа, RFC 793 или `iptables -j REJECT -h`
- `RETURN` - возврат пакета в вышестоящую цепочку для применения действия по умолчанию, при отсутствии вышестоящей цепочки применится действие по умолчанию
## Просмотр
- Просмотр текущих правил
```bash
iptables -L
```
только для конкретной цепочки
```bash
iptables -L INPUT
```
более наглядно
```bash
iptables -vnL --line-numbers
```
- Список текущих правил
```bash
iptables -S
```
- Очистка правил
```bash
iptables -F
```
очистка правил конкретной цепочки
```bash
iptables -F INPUT
```
**Стоит иметь ввиду, что очистка правил не изменяет правило по-умолчанию, если оно установлено в DROP, после очистки всех правил можно потерять доступ к узлу.**
- Для полной очистки правил и отключения фильтрации
```bash
iptables -P INPUT ACCEPT
iptables -P OUTPUT ACCEPT
iptables -P FORWARD ACCEPT
iptables -F
```
## Управление правилами и цепочками
Добавить правило (разрешить весь трафик с tun интерфейсов) в конец цепочки INPUT (-A, --append):
```bash
iptables -A INPUT -i tun+ -j ACCEPT
```
Вставить правило в позицию 2 цепочки INPUT (-I, --insert):
```bash
iptables -I INPUT 2 -i lo -j ACCEPT
```
Установить политику по умолчанию DROP для цепочки INPUT (-P, --policy):
```bash
iptables -P INPUT DROP
```
Создание новой цепочки правил:
```bash
iptables -N LOGGING
```
## Примеры
Предположим что для цепочки `INPUT` политика по умолчанию `DROP`, это значит что все входящие пакеты будут отброшены, но нам нужен некоторый входящий трафик.
Разрешим трафик на локальный DNS сервер, без этого могут быть долгие подключения по ssh:
```bash
iptables -A INPUT -p udp -m udp --dport 53 -j ACCEPT
```
Разрешим движение трафика из интерфейсов создаваемых Docker (при политиках по умолчанию `DROP`, контейнеры не смогут общаться с другими интерфейсами):
```bash
iptables -A INPUT -i br+ -j ACCEPT
```
Разрешим любой входящий трафик из `localhost` и откроем `http/https` порты (80/443), например для случая когда у нас есть веб-сервер и наши сайты должны быть доступны снаружи:
```bash
iptables -A INPUT -i lo -j ACCEPT
iptables -A INPUT -p tcp --dport 80 -j ACCEPT
iptables -A INPUT -p tcp --dport 443 -j ACCEPT
```
*Если не разрешить входящий трафик от `localhost` то могут быть странные задержки с ответами, а при дебаге можно увидеть отклоенные пакеты от 127.0.0.1*
Теперь локальный DNS на 53 порту доступен, docker контейнеры тоже, с localhost трафик разрешен, и для внешнего мира открыты 80 и 443 порты для наших сайтов. Но это все только для установления соединения и рукопожатия. Теперь нам нужно разрешить все установленные и связанные с ними соединения чтобы трафик действительно пошел (еще вот):
```bash
iptables -A FORWARD -m state --state RELATED,ESTABLISHED -j ACCEPT
```
### Пример первоначальной настройки
```bash
iptables -P INPUT ACCEPT
iptables -P OUTPUT ACCEPT
iptables -P FORWARD ACCEPT
iptables -F
iptables -A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
iptables -A INPUT -p tcp -m multiport --dports 8080,22,80 -j ACCEPT
iptables -A INPUT -p udp --dport 69 -j ACCEPT
iptables -A INPUT -p tcp --dport 5000:5678 -j ACCEPT
iptables -P INPUT DROP
iptables --line-numbers -L -v -n
```
### Сброс всех правил цепочки filter
```bash
iptables -P INPUT ACCEPT
iptables -P OUTPUT ACCEPT
iptables -P FORWARD ACCEPT
iptables -F
```
## Отладка
### Логирование отклоненных пакетов journald
Работа iptables происходит на уровне ядра ОС, соответственно все события логируются также на уровне ядра.
Добавляем правило логирования каждого пакета с префиксом:
```bash
iptables -A INPUT -j LOG --log-level info --log-prefix "IPTABLES-DROP: "
```
Вывод сообщений ядра
```bash
journalctl -k
```
или
```bash
journalctl -k -f
```
### Логирование отклоненных пакетов Rsyslog
*Полезно иметь возможно отладить свои правила, экономия времени и iptables становится понятнее.*
Суть отладки правил iptables такова:
создаем отдельную цепочку, куда будем перенаправлять весь трафик, который должен быть отклонен в новой цепочке ведем логирование и отклоняем пакеты
направляем запросы для теста правил и смотрим лог отклоенных пакетов
Создание новой цепочки:
```bash
iptables -N LOGGING
```
Добавляем правило логирования каждого пакета с префиксом:
```bash
iptables -A LOGGING -j LOG --log-prefix "ipt denied: "
```
Отклоняем пакет:
```bash
iptables -A LOGGING -j DROP
```
В цепочку, откуда будут приходить пакеты для отклонения добавляем новое правило перенаправления в новую цепочку логирования:
```bash
iptables -A INPUT -j LOGGING
```
Теперь добавим конфиг rsyslog:
```bash
nano /etc/rsyslog.d/10-iptables.conf
```
Вставим следующий текст:
```bash
:msg, contains, "ipt denied: " -/var/log/iptables.log
& ~
```
Сохраним и перезагрузим демона rsyslog:
```bash
service rsyslog restart
```
Теперь откроем файл и будем следить за 20 последних строк:
```bash
echo > /var/log/iptables.log
tail -f -n 20 /var/log/iptables.log
```