Система отслеживания состояния соединений conntrack, часть 1
Conntrack – важная часть сетевого стека Linux ответственная за определение сетевых соединений и связывания с ними конкретных пакетов. На основе состояния соединения строится логика работы брандмауэра netfilter, а также высокоуровневых интерфейсов к нему, таких как iptables и nftables.
Несмотря на видимую простоту с работой conntrack связано множество заблуждений и в этой заметке мы постараемся разобрать некоторые из них.
Прежде всего соединения conntrack, равно как и их состояния существуют сугубо в пределах брандмауэра и нигде более. Кроме того, это исключительно Linux-технология и в среде других ОС она не применима.
В рамках пользовательского пространства доступно четыре состояния, это всем известные NEW, ESTABLISHED, RELATED и INVALID.
Трассировка соединений происходит в цепочке PREROUTING или OUTPUT, если пакет был порожден локальным процессом. Первый пакет соединения получает статус NEW.
И вот здесь есть один важный момент, как conntrack определяет, что этот пакет первый. Например, для TCP мы можем ориентироваться на флаг SYN, но как быть с UDP, где каждый пакет, по сути, первый и последний?
Тут все просто, анализируется адрес и порт источника, адрес и порт приемника и если такой записи в таблице трассировщика нет, то пакет становится первый и ему присваивается состояние NEW.
Таким образом если в брандмауэр придет TCP пакет уже установленного соединения (без SYN), то conntrack все равно повесит ему состояние NEW и отправит дальше по цепочкам.
Это позволяет подхватывать уже установленные TCP-соединения если таблица трассировщика была утеряна (скажем мы перезагрузили роутер).
Что будет с пакетом NEW дальше? Он пойдет по цепочкам брандмауэра и будет либо пропущен, либо отброшен.
С отброшен все понятно, соединение было отвергнуто с нашей стороны и все повторные попытки соединения снова получат состояние NEW.
А вот если пакет был пропущен, то ему присваивается состояние ESTABLISHED? А вот и нет. Для перехода соединения в состояние ESTABLISHED требуется, чтобы через conntrack прошел ответ на этот пакет.
И только при наличии ответа узла состояние соединения перейдет в установленное – ESTABLISHED. Причем данное состояние устанавливается как для TCP, так и для UDP, хотя последний в принципе не подразумевает установление соединений.
Но, напоминаем, все эти соединения живут только внутри брандмауэра Linux и никак не отражаются в самих пакетах.
Для времени жизни UDP соединения используется таймаут, если за указанное в нем время через соединение не прошел ни один пакет – оно считается закрытым. Если пакет прошел – то таймаут сбрасывается и начинается новый отсчет.
С TCP все немного сложнее, при нормальном завершении соединения после получения FIN соединение в брандмауэре переходит в состояние TIME OUT (буферное время) и еще в течении некоторого времени считается ESTABLISHED. Это сделано для того, чтобы через брандмауэр могли пройти пакеты «застрявшие» где-то там по дороге.
Если соединение было закрыто по RST, то оно сразу переходит в состояние закрытого без выделения буферного времени.
При аварийном завершении TCP-соединения его состояние в conntrack будет ESTABLISHED до истечения тайм-аута.
Еще интереснее с ICMP, может ли ICMP быть ESTABLISHED? Может, и даже становится. Почему? Потому что многие типы ICMP подразумевают ответ на запрос. Поэтому пришедший ICMP пакет получит состояние NEW, а ответ на него переведет соединение в состояние ESTABLISHED.
Однако conntrack понимает, что дальнейшей передачи данных такое «соединение» не подразумевает и после прохождения ответного пакета через netfilter запись о соединении из таблицы трассировщика удаляется.
Conntrack – важная часть сетевого стека Linux ответственная за определение сетевых соединений и связывания с ними конкретных пакетов. На основе состояния соединения строится логика работы брандмауэра netfilter, а также высокоуровневых интерфейсов к нему, таких как iptables и nftables.
Несмотря на видимую простоту с работой conntrack связано множество заблуждений и в этой заметке мы постараемся разобрать некоторые из них.
Прежде всего соединения conntrack, равно как и их состояния существуют сугубо в пределах брандмауэра и нигде более. Кроме того, это исключительно Linux-технология и в среде других ОС она не применима.
В рамках пользовательского пространства доступно четыре состояния, это всем известные NEW, ESTABLISHED, RELATED и INVALID.
Трассировка соединений происходит в цепочке PREROUTING или OUTPUT, если пакет был порожден локальным процессом. Первый пакет соединения получает статус NEW.
И вот здесь есть один важный момент, как conntrack определяет, что этот пакет первый. Например, для TCP мы можем ориентироваться на флаг SYN, но как быть с UDP, где каждый пакет, по сути, первый и последний?
Тут все просто, анализируется адрес и порт источника, адрес и порт приемника и если такой записи в таблице трассировщика нет, то пакет становится первый и ему присваивается состояние NEW.
Таким образом если в брандмауэр придет TCP пакет уже установленного соединения (без SYN), то conntrack все равно повесит ему состояние NEW и отправит дальше по цепочкам.
Это позволяет подхватывать уже установленные TCP-соединения если таблица трассировщика была утеряна (скажем мы перезагрузили роутер).
Что будет с пакетом NEW дальше? Он пойдет по цепочкам брандмауэра и будет либо пропущен, либо отброшен.
С отброшен все понятно, соединение было отвергнуто с нашей стороны и все повторные попытки соединения снова получат состояние NEW.
А вот если пакет был пропущен, то ему присваивается состояние ESTABLISHED? А вот и нет. Для перехода соединения в состояние ESTABLISHED требуется, чтобы через conntrack прошел ответ на этот пакет.
И только при наличии ответа узла состояние соединения перейдет в установленное – ESTABLISHED. Причем данное состояние устанавливается как для TCP, так и для UDP, хотя последний в принципе не подразумевает установление соединений.
Но, напоминаем, все эти соединения живут только внутри брандмауэра Linux и никак не отражаются в самих пакетах.
Для времени жизни UDP соединения используется таймаут, если за указанное в нем время через соединение не прошел ни один пакет – оно считается закрытым. Если пакет прошел – то таймаут сбрасывается и начинается новый отсчет.
С TCP все немного сложнее, при нормальном завершении соединения после получения FIN соединение в брандмауэре переходит в состояние TIME OUT (буферное время) и еще в течении некоторого времени считается ESTABLISHED. Это сделано для того, чтобы через брандмауэр могли пройти пакеты «застрявшие» где-то там по дороге.
Если соединение было закрыто по RST, то оно сразу переходит в состояние закрытого без выделения буферного времени.
При аварийном завершении TCP-соединения его состояние в conntrack будет ESTABLISHED до истечения тайм-аута.
Еще интереснее с ICMP, может ли ICMP быть ESTABLISHED? Может, и даже становится. Почему? Потому что многие типы ICMP подразумевают ответ на запрос. Поэтому пришедший ICMP пакет получит состояние NEW, а ответ на него переведет соединение в состояние ESTABLISHED.
Однако conntrack понимает, что дальнейшей передачи данных такое «соединение» не подразумевает и после прохождения ответного пакета через netfilter запись о соединении из таблицы трассировщика удаляется.
10👍10❤1🔥1