# 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
```

