Cthulhu 19.04.2012 07:30 work

Пстач сетевой, а существует ли какой-то способ добиться следующего, не калеча код tcp/ip стека ядра?
1) При получении tcp-пакета с определенным признаком в заголовке (опции там, или установленные зарезервированные биты, или похуй чо) на определенный порт система должна автоматически установить коннект с отправляющим клиентом (т. е. сделать вид что получила от него SYN и ответила SYN+ACK, на самом деле этого не делая; пнуть слушающий на этом порту сокет, и использовать установленные в заголовке пакета seq и ack_seq в качестве начальных значений).
2) При наличии другого признака в заголовке пакета принять его, не отправляя в ответ подтверждение (ack);
3) Для непомеченных пакетов вести себя как обычно.

Clarification A: Да, проще всего вбить эту логику, поправив код сетевой подсистемы ядра, но такая реализация мне не нравится как минимум по двум причинам — из-за необходимости, собственно, пересобирать его на каждой ноде, и из-за необходимости мержить этот стремный патч при каждом его обновлении. А поскольку "stable api is nonsense", мне жаль потомков.

Clarification B: Я знаю про возможность сделать модуль, устанавливающий netfilter hook, который дропал бы нужные пакеты. Эта идея мне не нравится из-за второго пункта из предыдущего абзаца, бросающейся в глаза костыльности и неприемлемого оверхеда при реализации.

Clarification C: Да, я знаю, что такое в школе не проходят и я спросил не там, но вдруг.

Recommended by: @snakehoney
1. gelraen 19.04.2012 08:14

очевидно, нельзя. если очень хочется можно попытаться закостылировать каким-либо методом отправляя пакеты прямо в userspace, минуя TCP (но тогда проблема с сокетами).

Олсо, зачем нужна такая поебень?

2. Cthulhugelraen /1 19.04.2012 08:19 work

Для сервера, работающего в юзерспейсе, все это шаманство должно быть прозрачно, потому в эту сторону костылять нету смысла.

А нужно, ну... Есть access server, на котором развернут перепиленный lvs (он единственный из всего кластера доступен из внешней сети). Он принимает соединения от клиентов, парсит запрос, и в зависимости от его параметров выбирает из кластера ноду, которая будет этот запрос выполнять, и передает этой ноде заботу об открытом подключении (т. е. пакеты от клиента к ноде будут идти все еще через access server, а от ноды к клиенту уже напрямую). И, повторюсь, все это должно быть прозрачно как для клиента, так и для сервера на ноде.

3. gelraenCthulhu /2 19.04.2012 08:32 work

а зачем для этого какие-то флаги в пакетах и зачем калечить сетевой стек? Почему нельзя просто на все ноды кластера повесить ІР на который обращается клиент, тогда стек каждой ноды будет без всяких изъёбств отправлять пакеты нужному приложению. От access server в такой позе требуется только выставлять правильный L2-адрес для каждого пакета.

4. gelraengelraen /3 19.04.2012 08:40

а, ну да, это же линукс...

5. Cthulhugelraen /3 19.04.2012 08:41 work

Ну смотри. Предположим, что в качестве сервера на нодах у нас работает http. Аксес сервер должен работать в качестве L7 роутера (т. е. определять ноду в зависимости от параметров GET-запроса). На него прилетает SYN от клиента, он отвечает SYN+ACK, клиент кидает ему ACK и пакет с запросом. Он парсит запрос, определяет нужную ноду, и пересылает ей этот же запрос (а у нас его еще и поправить чуть придется — размер изменится, отсюда необходимость не отправлять в некоторых случаях ack — этим будет заниматься access, который знает оригинальный размер пакета; но на это пока можно забить) от имени клиента (т. е. нода должна начать слать клиенту данные сразу, без всяких там хендшейков). Потому что если она пошлет ему SYN+ACK — он охуеет и сбросит подключение.

6. gelraenCthulhu /5 19.04.2012 08:54 work

какое-то скрещивание ужа с ежом у тебя получается: тут мы L7-роутер, а тут L3-балансировщик. Наиболее корректный вариант — устанавливать самые обычные подключения между access server и нодами и пересылать данные по ним, но тогда ноды не видят реального адреса клиента (если конечно ты не передашь его отдельным заголовком). Второй вариант — сделать чтобы access server эмулировал подключение от имени клиента к ноде.
Вот на этом месте у меня начало возникать подозрение что ты пытаешься навелосипедить nginx в ядре.

7. Cthulhugelraen /6 19.04.2012 09:05 work

Ну в первую очередь мы все же л7-роутер, да.
Если я установлю обычное подключение с нодой — она будет слать пакеты мне. Я могу, конечно, сначала установить его, а потом каким-то образом сказать ей поменять destination у сокета на клиентский, но это плохая идея — лишний оверхед на установление подключения, которое уже какбэ установлено, как минимум.

Да, я хочу эмулировать подключение от имени клиента к ноде, с минимальным оверхедом. Собственно, затем весь этот изврат и был придуман.

8. gelraenCthulhu /7 19.04.2012 09:32 work

destination у сокета ты не поменяешь без насилования сетевого стека ноды. Ну и да, кто тебе мешает сэмулировать несколько пакетиков от имени клиента, а потом пересылать пакеты от клиента ноде?
Олсо, чем таки nginx в качестве http-балансировщика не угодил?

9. Cthulhugelraen /8 19.04.2012 09:58 work

Эмулировать пакеты никто не мешает, но.
Вот шлю я ноде SYN от имени клиента — она ему отвечает SYN+ACK. Он охуевает и ресетит подключение, потому что уже получил SYN+ACK от аксеса раньше. Следовательно, первая проблема — сказать ноде "не шли SYN+ACK". Ну или как-то перехватить его на пути к клиенту.
Дальше нода ждет от клиента ack для завершения хендшейка — окей, его тоже эмулируем. Уже имеем 2 (3) лишних пакета на каждое соединение.
Дальше мы пересылаем ноде гет-запрос от клиента. Поскольку мы его фиксили — размер изменился. И, когда она ответит клиенту ack, значение ack_seq в пакете не будет соответствовать оригинальному размеру. Следовательно, мы либо должны как-то сказать ноде "отвечай вот так", либо вообще отправить первый ack самостоятельно, сказав ноде молчать в ответ на этот пакет. Это вторая проблема.
А, ну еще seq в пакетах от ноды должен соответствовать тому, что мы отправили клиенту в первом пакете от аксеса при хендшейке — тобишь мы должны ей подсказать начальный номер последовательности.
В итоге пришли к тому, что и было в оп-посте )
Или все же есть менее костыльное решение для всего этого?

А про nginx — длинная история. Он не умеет часть того, что нам в итоге понадобится, ну и наша реализация будет быстрее в итоге )

10. gelraenCthulhu /9 19.04.2012 10:24 work

без подставляния костылей в стек ноды можно извратиться только с чем-то-вроде-NAT-но-не-NAT, которое таки будет через себя пропускать и ответы от ноды к клиенту, меняя в них seq/ack. Если именно nginx не подходит, то 1) почему его нельзя допилить до нужной кондиции? 2) почему не подходит схема с обычными бекендами, общающимися с балансировщиком по обычному HTTP/TCP ? Stateful forwarding на фронтенде всё равно придётся городить, как не крути, а в такой позе насиловать придётся только код балансировщика, не трогая ноды.

11. borman 20.04.2012 13:57

В Шаолине уже открыли отделение Computer Science?

12. L29Ahborman /11 20.04.2012 14:52 tkabber-mobix

Причём тут cs?

13. eorangedCthulhu /9 05.07.2012 19:45 Pidgin

Это прям как "мы навелосипедим свой бинарный XMPP и будет он в сто раз быстрее работать". И где они все?

По теме, если nginx не устраивает, то возьми HA Proxy и не парься. Проверенный софт гораздо лучше собственных велосипедов в большинстве случаев, а это как-раз такой.

Do you really want to delete ?