PyTCP — это полнофункциональный стек TCP/IP, написанный на Python. Он поддерживает транспорт на основе потоков TCP с надежной доставкой пакетов на основе механизма скользящего окна и базового контроля перегрузки. Он также поддерживает протоколы IPv6/ICMPv6 с конфигурацией адреса SLAAC. Он работает как программа пользовательского пространства, подключенная к интерфейсу Linux TAP. Он реализовал простую маршрутизацию и может отправлять и получать трафик через локальную сеть и Интернет.
Версия 2.7, в отличие от своих предшественников, содержит код стека PyTCP в виде библиотеки, поэтому его можно легко импортировать и использовать внешним кодом. Это должно сделать работу пользователя более плавной и в конечном итоге предоставить полную возможность заменить стандартные вызовы стека Linux (например, библиотеки сокетов) вызовами PyTCP в любом стороннем приложении.
Изначально этот проект начинался как чисто образовательная попытка, направленная на улучшение моих навыков Python и обновление знаний о сети в рамках подготовки к должности сетевого инженера в Facebook. С тех пор это стало больше похоже на «любимый проект», которому я посвящаю часть своего времени на несколько нерегулярной основе. Однако каждые месяц или два к нему обычно добавляется пара обновлений.
Я приветствую любые вклады и помощь от всех, кто интересуется сетевым программированием. Любой вклад приветствуется. Также помните, что некоторые функции стека могут быть реализованы лишь частично (по мере необходимости для работы стека). Они могут быть реализованы неоптимально или не на 100% RFC-совместимо (из-за нехватки времени), или они могут содержать ошибки, которые мне еще предстоит исправить.
Пожалуйста, не стесняйтесь проверить мои два других связанных проекта:
RusTCP — попытка переписать некоторые функции PyTCP в Rust и использовать их для создания лабораторного маршрутизатора IPv6/SRv6.
SeaTCP — попытка создать стек с низкой задержкой, используя языки C и Ассемблер.
Принцип работы и испытательная установка
Стек PyTCP зависит от интерфейса TAP Linux. Интерфейс TAP — это виртуальный интерфейс, который на стороне сети можно «подключить» к существующей инфраструктуре виртуальной сети через мост Linux или Open vSwitch. На внутренней стороне интерфейс TAP можно использовать, как и любой другой сетевой адаптер, программно отправляя и получая пакеты в/из него.
Если вы хотите протестировать стек PyTCP в своей локальной сети, я бы предложил создать следующую настройку сети, которая позволит вам одновременно подключить ядро Linux (по сути, вашу ОС Linux) и стек PyTCP к вашей локальной сети. .
После того, как пример программы (клиента или службы) запускает стек, он может взаимодействовать с ним через упрощенные сокеты BSD, такие как интерфейс API. Также существует возможность отправки пакетов напрямую, вызвав один из методов _*_phtx() из класса PacketHandler .
Клонирование PyTCP из репозитория GitHub
В большинстве случаев PyTCP следует клонировать непосредственно из репозитория GitHub, поскольку этот тип установки обеспечивает полную среду разработки и тестирования.
git clone http://github.com/ccie18643/PyTCP
После клонирования мы можем запустить один из включенных примеров:
Перейдите в корневой каталог стека (он называется «PyTCP»).
При необходимости запустите команду sudo make bridge , чтобы создать мост «br0».
Запустите команду sudo make tap , чтобы создать интерфейс Tap7 и назначить его мосту «br0».
Запустите команду make , чтобы создать подходящую виртуальную среду для разработки и тестирования.
Бегать . venv/bin/activate Команда . venv/bin/activate для активации виртуальной среды.
Выполните любой пример, например example/run_stack.py .
Нажмите Ctrl-C, чтобы остановить это.
Для точной настройки различных рабочих параметров стека отредактируйте файл pytcp/config.py соответствующим образом.
Установка PyTCP из репозитория PyPi
PyTCP также можно установить как обычный модуль из репозитория PyPi.
python -m pip install PyTCP
После установки убедитесь, что интерфейс TAP работает и добавлен в мост.
sudo ip tuntap add name tap7 mode tapsudo ip link set dev tap7 upsudo brctl addbr br0sudo brctl addif br0 tap7
Стек PyTCP можно импортировать и запустить, используя следующий код. Он запускает подсистемы стека и автоматически настраивает адреса протоколов IPv4 и IPv6 с использованием DHCPv4 и IPv6 SLAAC соответственно.
Подсистемы стека работают в своих собственных потоках. После запуска стек возвращает управление пользовательскому коду и может быть остановлен с помощью следующего вызова.
stack . stop ()
Функции
Уже реализовано:
Стек — быстрый анализатор пакетов с использованием подхода «нулевой копии».
Стек — быстрый ассемблер пакетов, использующий подход «нулевого копирования».
Стек — библиотека манипуляции MAC-адресами — совместима с протоколом буфера (Memoryview).
Стек — библиотека манипуляции адресами IPv4 — совместима с протоколом буфера (Memoryview) и не зависит от стандартной библиотеки Python.
Стек — библиотека манипуляции адресами IPv6 — совместима с протоколом буфера (Memoryview) и не зависит от стандартной библиотеки Python.
Код — модульное тестирование некоторых библиотек и модулей (на основе платформы Facebook Testslide).
Протокол Ethernet — поддержка стандартных кадров Ethernet II.
ICMPv6 — поддержка MLDv2 сейчас находится в полном беспорядке. Надо закончить.
Тестирование. Необходимо провести рефакторинг тестов потока пакетов (tests/packet_flow_.py ), чтобы использовать тот же формат и каталог, что и тесты FPA, основанные на test_frames.*
Тестирование — создание модульных тестов FPA для отчета MLDv2 (len, str, assemble).
IPv4 — повторная реализация дефрагментации пакетов для хранения целых пакетов в базе данных потока вместо копирования IP-заголовка и данных.
Стек — реализация поддержки сокетов RAW — для использования в качестве примера клиента ICMP-Echo.
Код — модульное тестирование остальных библиотек и модулей (на основе библиотеки Testslide от Facebook).
Код. Перепишите поддержку протокола DHCPv4, чтобы использовать стандартный подход FPA/FPP вместо устаревшего кода.
Стек. Вернитесь к реализации консоли отладки стека, чтобы определенную информацию о компонентах стека можно было отображать по запросу путем отправки команд. например, «показать кэш icmpv6 nd», «показать маршрут ipv6» и т. д. он также должен позволять вам запускать интерактивные команды, такие как ping или эхо-клиенты UDP/TCP стека.
Протокол QUIC — исследование и план внедрения. Это зависит от возможности создать для него лабораторную среду.
Протокол IPv6 — переработана обработка параметров RA PI и автоматическая настройка префикса ND для правильного использования флагов A и L. Некоторые исследования также необходимы, когда рекламируется префикс, отличный от /64.
Протокол IPv6. Проверка и, возможно, повторная реализация определенных механизмов/процессов IPv6 в соответствии с правилами RFC.
Протокол IPv6 — исследуйте заголовок параметров шаг-за-шагом и его связь с сообщением отчета MLD2, при необходимости реализуйте его для правильной работы MLD2.
Протокол ICMPv6 — реализация сообщения перенаправления ND.
Протокол ICMPv6 — полная реализация Multicast Listener Discovery v2 (MLDv2) <-- может потребоваться стеку для ответа на запросы MLD.
Протокол TCP. Правильная обработка пакетов RST в различных состояниях. Нужно это изучить. По этому поводу отправлен отчет об ошибке.
Протокол TCP. Необходимо переработать механизм системного вызова CLOSE, чтобы флаг FIN можно было устанавливать в последнем пакете данных, а не переносить в отдельном пакете.
Протокол TCP — повторная передача пакета ACK в случае, если мы получили повторную передачу FIN в состоянии TIME_WAIT. Нужно это расследовать.
Протокол TCP — реализовать правильный ответ на пакеты, содержащие старые номера SEQ и/или ACK. Нужно это расследовать.
Протоколы IPv6/IPv4 — правильный механизм маршрутизации, таблицы маршрутизации и т. д.
Протоколы IPv6/IPv4 — способность стека действовать как маршрутизатор
Кэш ARP — реализовать правильный FSM
Кэш ICMPv6 ND — реализация правильного FSM
Ведение журнала. Замените Loguru самодельным средством ведения журнала, чтобы повысить производительность и гибкость.
Стек. Преобразуйте стек PyTCP в библиотеку, чтобы внешние приложения могли легко его импортировать.
Стек — счетчики потока пакетов, помогающие собирать статистику пакетов и отслеживать поток пакетов для модульного тестирования.
Стек. Реализуйте механизм обратной связи для пути передачи, чтобы об ошибках отправки пакетов можно было сообщать сокетам.
Протокол IPv6 — возможность маршрутизировать трафик во внешние пункты назначения через шлюз по умолчанию.
Протокол TCP. Убедитесь, что передача событий из сеанса TCP в сокет работает правильно (например, сброс соединения одноранговым узлом).
Протокол IPv4 — необходимо усовершенствование механизма дефрагментации IP, обработка неупорядоченных фрагментов и очистка потерянных фрагментов.
Протокол UDP. Требуется клиент UDP Echo и механизм для сообщения о получении сообщения ICMP Port Unreachable в сокет UDP.
Сокеты UDP. Требуется капитальный ремонт, чтобы интерфейс «конечного пользователя» более точно соответствовал сокетам Беркли, чтобы сторонние приложения могли использовать его без переноса.
Сокеты TCP. Требуется капитальный ремонт, чтобы интерфейс «конечного пользователя» более точно соответствовал сокетам Беркли, чтобы сторонние приложения могли использовать его без переноса.
Примеры
Несколько пинг-пакетов и две обезьяны были доставлены по TCP по протоколу IPv6.
Стек пытается автоматически настроить свой локальный адрес канала. Он генерирует его как адрес EUI64. В рамках процесса DAD он присоединяется к соответствующей группе многоадресной рассылки запрошенного узла и отправляет запрос соседу для своего сгенерированного адреса.
Стек не получает никакой рекламы соседа для сгенерированного им адреса, поэтому он назначает его своему интерфейсу.
Стек пытается назначить предварительно настроенный статический адрес. В рамках процесса DAD он присоединяется к соответствующей группе многоадресной рассылки запрошенного узла и отправляет запрос соседям для статического адреса.
Другой хост с тем же уже назначенным адресом отвечает сообщением объявления соседа. Это сообщает стеку, что другой хост уже назначил адрес, который он пытается назначить, поэтому стек не может его использовать.
Стек отправляет сообщение запроса маршрутизатора, чтобы проверить, есть ли какие-либо глобальные префиксы, которые он должен использовать.
Стек пытается назначить адрес, сгенерированный на основе полученного префикса и части хоста EUI64. В рамках процесса DAD он присоединяется к соответствующей группе многоадресной рассылки запрошенного узла и отправляет запрос соседям для статического адреса.
Стек не получает никакой рекламы соседа для сгенерированного им адреса, поэтому он назначает его своему интерфейсу.
После того, как все адреса назначены, стек отправляет еще один отчет прослушивателя многоадресной рассылки, в котором перечислены все адреса многоадресной рассылки, которые он хочет прослушивать.
TCP Fast Retransmit в действии после потери пакета TX.
Исходящий пакет «теряется» из-за механизма имитации потери пакетов.
Узел замечает несоответствие в номерах SEQ пакетов и отправляет «запрос быстрой повторной передачи».
Стек получает запрос и повторно передает потерянный пакет.
Очередь вне очереди в действии во время потери пакета RX
Входящий пакет «теряется» из-за механизма имитации потери пакетов.
Стек замечает несоответствие в SEQ-номере входящего пакета и отправляет запрос на «быструю повторную передачу».
Прежде чем партнер получит запрос, он отправляет несколько пакетов с более высоким SEQ, чем ожидает стек. Стек ставит в очередь все эти пакеты.
Узел повторно передает потерянный пакет.
Стек получает потерянный пакет, извлекает все пакеты, хранящиеся в очереди вне очереди, и обрабатывает их.
Stacks отправляет пакет ACK для подтверждения последних пакетов, извлеченных из очереди.
Конечный автомат TCP — стек запускает службу TCP Echo.
Peer открывает соединение.
Пир отправляет данные.
Стек возвращает данные обратно.
Пир закрывает соединение.
Конечный автомат TCP — в стеке работает клиент TCP Echo.
Стек открывает соединение.
Стек отправляет данные.
Пир возвращает данные обратно.
Стек закрывает соединение.
Проверка работоспособности пакетов перед анализом в действии.
На первом скриншоте показан стек с отключенной проверкой работоспособности. Неверно сформированный пакет ICMPv6 может привести к его сбою.
На втором скриншоте показан стек с включенной проверкой работоспособности. Неверно сформированный пакет ICMPv6 отбрасывается перед передачей анализатору протокола ICMPv6.
На третьем снимке экрана показан искаженный пакет. В поле количества записей MA установлено значение 777, хотя пакет содержит только одну запись.
Механизм зондирования/объявления ARP.
Стек использует ARP-зонды для обнаружения возможных конфликтов для каждого настроенного IP-адреса.
Один из IP-адресов (192.168.9.102) уже занят, поэтому стек получает об этом уведомление и пропускает его.
Остальные IP-адреса свободны, поэтому стек запрашивает их, отправляя для каждого из них объявление ARP.
Разрешение ARP и обработка пинг-пакетов.
Хост 192.168.9.20 пытается пропинговать стек. Чтобы это сделать, он сначала отправляет пакет ARP-запроса, чтобы узнать MAC-адрес стека.
Стек отвечает отправкой пакета ответа ARP (стеку не нужно отправлять свой запрос, поскольку он уже записал MAC-адрес хоста из запроса хоста).
Хост отправляет ping-пакеты, а стек отвечает на них.
IP-фрагментация.
Хост отправляет датаграмму UDP размером 4 КБ, используя три фрагментированных IP-пакета (три фрагмента).
Стек получает пакеты и собирает их в единое целое, а затем передает их (через обработчик протокола UDP и сокет UDP) в службу UDO Echo.
Служба UDP Echo собирает данные и помещает их обратно в сокет UDP.
Датаграмма UDP передается обработчику протокола IP, который создает IP-пакет, и после проверки того, что он превышает канал, MTU фрагментирует его на три отдельных IP-пакета.
IP-пакеты инкапсулируются в кадры Ethernet и помещаются в кольцо TX.