Настройка сетевого интерфейса для TCP поверх TCP в Linux

Я портирую устаревшее встроенное приложение на Linux. Это приложение взаимодействует с удаленным сервером через TCP-соединение, используя собственный протокол. В дополнение к сообщениям, специфичным для приложения, этот протокол также реализует сообщения, которые позволяют туннелировать трафик TCP и UDP через сокет TCP, чтобы приложение могло обслуживать сторонних клиентов (например, встроенный веб-сервер). Это, по сути, индивидуальное решение VPN.

Поскольку исходное приложение работает на голой железной системе, не было другого выбора, кроме как реализовать все дополнительные сервисы как часть приложения.

Как часть моих При портировании я решил использовать драйвер TUN / TAP, предоставляемый ядром Linux, и направить все инкапсулированные фреймы TCP и UDP на интерфейс TUN. Однако это приводит к запуску TCP поверх TCP , вызывая все связанные с ним проблемы . Исходная реализация не имеет этой проблемы, потому что туннель не инкапсулирует полный стек TCIP / IP.

Итак, мой вопрос: можно ли настроить интерфейс TUN так, чтобы стек TCP / IP проходил через него не выполняет никаких очередей и повторных передач? Или я придерживаюсь той индивидуальной реализации, которую унаследовал? Мне известно только о проблеме повторной передачи TCP через TCP. Есть ли какие-либо другие проблемы, о которых мне нужно знать при использовании такого решения?

2
задан 15 January 2019 в 07:12
1 ответ

Это сложная ситуация. Я надеюсь, что вы в конечном итоге сможете заменить все приложение чем-то более разработанным.

На уровне TUN / TAP вы мало что можете сделать, потому что это слишком низкий уровень стека, чтобы понять, что такое повторные передачи. .

Однако есть кое-что, что вы можете сделать для реализации IP через TCP, чтобы в основном уменьшить проблему повторной передачи. Имейте в виду, что у меня не было необходимости реализовывать такую ​​вещь самому, поэтому могут возникнуть проблемы, которых я еще не осознал. Однако я могу объяснить, как эти идеи работают в теории.

Проблема в том, что как только внешнее TCP-соединение теряет какой-либо отдельный пакет, принимающая сторона будет заблокирована до тех пор, пока потерянный пакет не будет повторно передан. Это вызовет задержку внутренних пакетов, что может быть обнаружено как потеря пакета внутренним уровнем, вызывая повторную передачу и на внутреннем уровне, что без нужды потребляет дополнительную полосу пропускания.

На принимающей стороне

Моя лучшая идея о том, как Чтобы справиться с этим, нужно настроить принимающую сторону, чтобы частично обойти TCP-стек ядра. Вы по-прежнему устанавливаете TCP-соединение, используя реализацию TCP в ядре, как и в обычном случае. Но на принимающей стороне вы фактически не используете данные, которые получаете от сокета TCP. Вместо этого у вас будет поток или процесс, который постоянно читает из сокета TCP и отбрасывает все полученные данные.

Для доставки пакетов в интерфейс TUN / TAP вы используете необработанный сокет, который будет получать сегменты TCP. как видно на проводе. Этот процесс может использовать фильтры в ядре, чтобы видеть только те пакеты, которые ему нужны, и игнорировать любые лишние пакеты, если ядро ​​не может выполнять фильтрацию достаточно точно. Ваш процесс должен сделать достаточно самой повторной сборки TCP, чтобы извлечь внутренние пакеты, которые он затем может доставить в интерфейс TUN / TAP.

Здесь важно то, что когда внешний пакет теряется, только внутренние пакеты, на которые воздействует оно будет потеряно или отложено.Ваш процесс может продолжить сборку пакетов после потерянного, чтобы извлечь и доставить внутренние пакеты в интерфейс TUN / TAP. Внутренний стек TCP может повторно передать несколько пакетов, но не так много, как при остановке внешнего TCP-соединения.

Следует указать на несколько предостережений, которые могут быть или не быть очевидными:

  • Если получение окно или окно перегрузки заполняется TCP на передающей стороне остановится. Вы не можете предотвратить это, но вы можете снизить риск, убедившись, что внешнее TCP-соединение поддерживает выборочные подтверждения (SACK).
  • В зависимости от специфики туннельного протокола может быть сложно или даже невозможно точно определить границы пакета после потери пакет. Если это так для протокола, который вам нужно реализовать, возможно, вам не повезло. Я бы предложил изменить протокол, но я понимаю, что это не вариант для вас.

На отправляющей стороне

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

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

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

Теоретическая возможность, но, вероятно, требует много работы для реализации, заключается в том, что вы используете необработанный сокет, упомянутый выше, для отслеживания пакетов ACK. Таким образом вы сможете определить, какие внутренние пакеты все еще находятся в полете. Затем каждый внутренний TCP-пакет должен быть проверен на соответствие пакетам в полете, и если это повторная передача пакета, который еще не подтвержден внешним TCP-соединением, вы молча отбрасываете повторную передачу внутренним TCP-соединением.

Игнорирование проблема

Скорее всего, текущее приложение ничего из этого не делает. Вероятно, он просто выполняет TCP поверх TCP и надеется на лучшее. И если до сих пор это не было проблемой для вас, то, вероятно, не будет проблемой, если вы замените один конец соединения на новую реализацию того же протокола.

Таким образом, может быть более продуктивным просто попробуйте использовать известный неоптимальный протокол и исправляйте его только в том случае, если вы обнаружите, что он вызывает реальные проблемы. Это, конечно, зависит от того, какими будут последствия развертывания повторной реализации и возникновения проблем позже.

2
ответ дан 3 December 2019 в 11:24

Теги

Похожие вопросы