В данной статьей я кратко постараюсь объяснить, как устроен внутри Linux ядра механизм TCP Fast Open позволяющий обойтись без 3 этапного установления соединения.
Суть его сводится к тому, что если и клиент и сервер имеют поддержку TFO, о которой сообщают за счет специального флага в TCP пакете (а также сопровождающего его TFO Cookie - секретного ключа), который получают при установке обычного 3-х этапного соединения, то второе и последующие соединения с тем же сервером они могут осуществлять сразу высылая данные в SYN пакете, а не осуществляя повторную установку соединения. Авторизация что этот пакет является легитимным осуществляется за счет проверки TFO Cookie (который ранее был получен от сервера).
Во-первых! Чтобы активировать поддержку и клиентского и серверного TFO на обоих машинах для теста нужно сделать следующее:
sysctl -w net.ipv4.tcp_fastopen=3
Если не задано обратное, то генерация ключей для TFO cookie осуществляется автоматически.
Если же требуется задать ключ вручную, можно использовать спец переменную ядра:
cat /proc/sys/net/ipv4/tcp_fastopen_key
00000000-00000000-00000000-00000000
Обработчик записи в эту переменную (функция proc_tcp_fastopen_key, файл net/ipv4/sysctl_net_ipv4.c) вызывает функцию tcp_fastopen_reset_cipher с параметрами - переданный ключ и его длина. По дефалту генерируется рандомный ключ посредством функции net_get_random_once. После этого создается контекст для шифрования с данным ключем посредством aes алгоритма. Контекст сохраняется в переменной tcp_fastopen_ctx.
Генерация куки для IPv4.
Тут все просто, собирается массив из 4х 32 битных чисел. Два - src и dst IP адреса для данного соединения, два числа еще - нули. После этого все это дело шифруется aes.
Генерация куки для IPv6.
А вот тут немного магии (зовется она CBC MAC: http://en.wikipedia.org/wiki/CBC-MAC). Сначала шифруется IP адрес источника (уже без паддинга нулями - 4 32 битных целых числе). После этого мы берем результат шифрования (4 32 битных числа) и xor-им с соответствующими 32 битными частями целевого IP адреса. После этого результата еще раз шифруем токеном и получаем итоговую cookie.
Кроме этого, судя по тексту из патча:
A simple cookie scheme together with capping the number of outstanding TFO requests (still in TCP_SYN_RECV state) to a limit per listener forms the main line of defense against spoofed SYN
attacks.
Число, которое передается как параметр для listen сокета посредством функции setsockopt(sockfd, SOL_TCP, TCP_FASTOPEN, &qlen, sizeof(qlen)) используется, чтобы защититься от флуда TFO SYN'ами и перейти на обычный механизм установки соединения.
К сожалению, в процессе тестов мною было
убито ядро 3.16, проблема оказалась апстримной и я очень надеюсь, что скоро будет решена :)