October 30th, 2017

404

Разрыв TCP если у remote поменялся mac (с тем же IP)

А нет ли в линуксах такого странного режима, который бы рвал все tcp-сессии с ip, если у него поменялся адрес в neighbors? (ARP или его аналог в ipv6)? Мне бы очень хотелось, чтобы при перетаскивании IP с одного сервера на другой, все клиенты, у которых открыта молчаливая tcp-сессия, после первого же grace arp, радостно все коннекты оборвали без ожидания таймаутов.
404

RFC: instant reconnect on VIP migration

В ходе обсуждения проблемы обнаружения переноса VIP, у меня родилась суперидея, и мне интересны её последствия, так что пишу RFC (в оригинальном смысле, request for comments).

Конфигурация:

два сервера, дублирующие друг друга. На сервера выделен virtual IP, который перемещается corosync/pacekeeper между серверами. Все клиенты коннектятся к VIP. В случае дауна VIP переползает на passive сервер, который становится новым active. Клиенты обнаруживают, что соединение закрыто, и переустанавливают его.

Проблема: если клиенты долго не получают никаких данных, то в случае дауна первого сервера, второй сервер не знает, что "где-то там есть клиент, который думает, что у нас с ним есть TCP сессия". Кроме клиента про эту сессию знал только первый сервер, а он сейчас умер.

Как только клиент пошлёт данные, он получит RST и переподключится и всё будет хорошо. Но пока клиент не послал данных, TCP живёт. Если стиль работы клиента таков, что он долго ждёт и ничего не шлёт, то может быть ситуация, что VIP перенесли на живой сервер, а клиенты "мёртвые", потому что не переподключились.

Дополнительная информация: мы знаем, что при переезде VIP у него меняется MAC-адрес, и все клиенты получают grace ARP. Очевидно, что речь идёт про один L2-сегмент, и про directly connected клиентов и сервер.

Идеи: При обнаружении grace ARP клиент посылает fake TCP segment серверу, который:

а) Если номер последовательности (sequence number) соответствует ожидаемому, то обрабатывает его (игнорирует, или даже присылает левый ack).
б) Если номер сегмента не соответствует активному соединению, присылает RST клиенту.

Если клиент получает лишний ack, то он его игнорирует (максимум, слегка кривит TCP из-за duplicate ack).
Если клиент получает RST, то он закрывает соединение и открывает его заново.

Ключевое тут, что если соединение с сервером настоящее, то наш "лишний сегмент" ничего не делает. Если клиент думает, что соединение есть, а его нет, то ему новый сервер присылает RST и заставляет переподключиться.

Наше "приложение" посылает лишний сегмент только если у IP (с которым есть TCP-сессии) поменял mac-адрес, при этом все остальные соединения (с другими IP) остаются unaffected.

Смену mac'а мы можем узнать через netsocket с ядром (мне уже ссылку из debian-users@ дали).
Получить список активных tcp-соедиений с заданным IP мы можем (привет, netstat).
Отправить фейковый tcp-сегмент мы так же можем (привет, hping3). Более того, если мы получили grace ARP, то это означает, что с той стороны уже есть отвечающий IP, который может сделать нам RST на "незнакомую TCP-сессию".

Не решённые вопросы:
а) Как выглядит "безопасный tcp-сегмент"
б) можем ли мы узнать все нужные нам данные (включая номер сегмента)
в) что будет, если мы пошлём пакет с кривым sequence от балды
г) Какая комбинация флагов наиболее безопасно.
д) Будет ли к нам приходить RST.

Альтернативно, пакет можно инжектить локально и заставлять клиента его ack'ать (а ack вызывает RST на кривых соединениях - в этом случае нам не надо угадывать sequence для удалённого сервиса)

Комментарии? Предолжения? Критика?