UDP-трекеры

Proposal 160
Закрыто
Author zzz
Created 2022-01-03
Last Updated 2025-06-25
Target Version 0.9.67

Статус

Одобрено на проверке 2025-06-24. Спецификация находится в UDP спецификации. Реализовано в zzzot 0.20.0-beta2. Реализовано в i2psnark начиная с API 0.9.67. Проверьте документацию других реализаций для получения информации о статусе.

Обзор

Данное предложение касается реализации UDP-трекеров в I2P.

Change History

Предварительное предложение по UDP tracker’ам в I2P было опубликовано на нашей странице спецификации bittorrent в мае 2014 года; это было до нашего формального процесса предложений, и оно так и не было реализовано. Данное предложение было создано в начале 2022 года и упрощает версию 2014 года.

Поскольку это предложение основывается на репликабельных датаграммах, оно было приостановлено, когда мы начали работать над предложением Datagram2 в начале 2023 года. Это предложение было одобрено в апреле 2025 года.

Версия данного предложения 2023 года определяла два режима: “совместимости” и “быстрый”. Дальнейший анализ показал, что быстрый режим был бы небезопасным, а также неэффективным для клиентов с большим количеством торрентов. Кроме того, BiglyBT выразил предпочтение режиму совместимости. Этот режим будет проще для реализации любым трекером или клиентом, поддерживающим стандартный BEP 15.

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

Поэтому текущая версия здесь дополнительно упрощена для удаления быстрого режима и удаления термина “совместимость”. Текущая версия переключается на новый формат Datagram2 и добавляет ссылки на протокол расширения UDP announce BEP 41.

Кроме того, в ответ на подключение добавлено поле времени жизни ID соединения для расширения преимуществ эффективности данного протокола.

Motivation

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

Bittorrent предложил UDP трекеры в BEP 15 BEP 15 в 2008 году, и подавляющее большинство трекеров в clearnet теперь работают только по UDP.

Сложно рассчитать экономию пропускной способности при использовании датаграмм по сравнению с потоковым протоколом. Запрос с возможностью ответа имеет примерно тот же размер, что и потоковый SYN, но полезная нагрузка примерно на 500 байт меньше, поскольку HTTP GET содержит огромную строку URL-параметров размером 600 байт. Необработанный ответ намного меньше потокового SYN ACK, что обеспечивает значительное снижение исходящего трафика трекера.

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

Post-Quantum шифрование и подписи, как предусмотрено в /en/proposals/169-pq-crypto/, существенно увеличат накладные расходы зашифрованных и подписанных структур, включая destinations, leasesets, streaming SYN и SYN ACK. Важно минимизировать эти накладные расходы везде, где это возможно, до принятия PQ криптографии в I2P.

Мотивация

Это предложение использует repliable datagram2, repliable datagram3 и raw datagrams, как определено в /en/docs/spec/datagrams/. Datagram2 и Datagram3 — это новые варианты repliable datagrams, определенные в Предложении 163 /en/proposals/163-datagram2/. Datagram2 добавляет защиту от повторного воспроизведения и поддержку автономных подписей. Datagram3 меньше по размеру, чем старый формат datagram, но без аутентификации.

BEP 15

Для справки, поток сообщений, определенный в BEP 15, следующий:

Client                        Tracker
    Connect Req. ------------->
      <-------------- Connect Resp.
    Announce Req. ------------->
      <-------------- Announce Resp.
    Announce Req. ------------->
      <-------------- Announce Resp.

Фаза подключения необходима для предотвращения подмены IP-адресов. Трекер возвращает идентификатор соединения, который клиент использует в последующих анонсах. Этот идентификатор соединения истекает по умолчанию через одну минуту на клиенте и через две минуты на трекере.

I2P будет использовать тот же поток сообщений, что и BEP 15, для облегчения внедрения в существующие кодовые базы клиентов, способных работать с UDP: для эффективности и по соображениям безопасности, обсуждаемым ниже:

Client                        Tracker
    Connect Req. ------------->       (Repliable Datagram2)
      <-------------- Connect Resp.   (Raw)
    Announce Req. ------------->      (Repliable Datagram3)
      <-------------- Announce Resp.  (Raw)
    Announce Req. ------------->      (Repliable Datagram3)
      <-------------- Announce Resp.  (Raw)
             ...

Это потенциально обеспечивает значительную экономию пропускной способности по сравнению с объявлениями через потоковую передачу (TCP). Хотя Datagram2 примерно такого же размера, как потоковый SYN, необработанный ответ значительно меньше потокового SYN ACK. Последующие запросы используют Datagram3, а последующие ответы являются необработанными.

Запросы объявлений используют Datagram3, поэтому tracker не должен поддерживать большую таблицу сопоставления идентификаторов соединений с назначением объявления или хэшем. Вместо этого tracker может генерировать идентификаторы соединений криптографически из хэша отправителя, текущей временной метки (основанной на некотором интервале) и секретного значения. Когда получен запрос объявления, tracker проверяет идентификатор соединения, а затем использует хэш отправителя Datagram3 в качестве цели отправки.

История изменений

Для интегрированного приложения (router и клиент в одном процессе, например i2psnark и Java-плагин ZzzOT), или для I2CP-приложения (например BiglyBT), должно быть несложно реализовать и маршрутизировать streaming и datagram трафик отдельно. ZzzOT и i2psnark ожидаются как первые трекер и клиент, которые реализуют данное предложение.

Неинтегрированные трекеры и клиенты рассматриваются ниже.

Trackers

Существует четыре известные реализации I2P tracker:

  • zzzot, интегрированный плагин Java router, работающий на opentracker.dg2.i2p и нескольких других
  • tracker2.postman.i2p, работающий предположительно за Java router и HTTP Server tunnel
  • Старый C opentracker, портированный zzz, с закомментированной поддержкой UDP
  • Новый C opentracker, портированный r4sas, работающий на opentracker.r4sas.i2p и возможно других, работающий предположительно за i2pd router и HTTP Server tunnel

Для внешнего приложения tracker’а, которое в настоящее время использует HTTP server tunnel для получения announce-запросов, реализация может быть довольно сложной. Может быть разработан специализированный tunnel для преобразования датаграмм в локальные HTTP-запросы/ответы. Или может быть спроектирован специализированный tunnel, который обрабатывает как HTTP-запросы, так и датаграммы, и который будет перенаправлять датаграммы во внешний процесс. Эти решения по проектированию будут сильно зависеть от конкретных реализаций router’а и tracker’а и выходят за рамки данного предложения.

Clients

Внешние торрент-клиенты на основе SAM, такие как qbittorrent и другие клиенты на базе libtorrent, требуют SAM v3.3, который не поддерживается i2pd. Это также необходимо для поддержки DHT и достаточно сложно, поэтому ни один известный SAM торрент-клиент этого не реализовал. SAM-основанных реализаций данного предложения в ближайшее время не ожидается.

Connection Lifetime

BEP 15 указывает, что идентификатор соединения истекает через одну минуту на клиенте и через две минуты на трекере. Это не настраивается. Это ограничивает потенциальные преимущества в эффективности, если только клиенты не группируют анонсы, чтобы выполнить их все в течение одноминутного окна. i2psnark в настоящее время не группирует анонсы; он распределяет их во времени, чтобы избежать всплесков трафика. Сообщается, что опытные пользователи одновременно запускают тысячи торрентов, и отправка такого количества анонсов в течение одной минуты нереалистична.

Здесь мы предлагаем расширить ответ на подключение, добавив дополнительное поле времени жизни соединения. По умолчанию, если не указано, это одна минута. В противном случае время жизни, указанное в секундах, должно использоваться клиентом, и tracker будет поддерживать ID соединения на одну минуту дольше.

Compatibility with BEP 15

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

Единственное необходимое изменение — это формат информации о peer в ответе announce. Добавление поля lifetime в ответе connect не является обязательным, но настоятельно рекомендуется для эффективности, как объяснено выше.

BEP 15

Важной целью протокола UDP announce является предотвращение подмены адресов. Клиент должен фактически существовать и включать реальный leaseset. У него должны быть входящие tunnel’ы для получения Connect Response. Эти tunnel’ы могли бы быть нулевого перехода и построенными мгновенно, но это бы раскрыло создателя. Данный протокол достигает этой цели.

Поддержка Tracker/Client

  • Данное предложение не поддерживает слепые назначения (blinded destinations), но может быть расширено для этого. См. ниже.

Дизайн

Protocols and Ports

Repliable Datagram2 использует I2CP протокол 19; repliable Datagram3 использует I2CP протокол 20; необработанные датаграммы используют I2CP протокол 18. Запросы могут быть Datagram2 или Datagram3. Ответы всегда необработанные. Старый формат repliable datagram (“Datagram1”), использующий I2CP протокол 17, НЕ ДОЛЖЕН использоваться для запросов или ответов; они должны отбрасываться при получении на портах запросов/ответов. Обратите внимание, что протокол Datagram1 17 всё ещё используется для DHT протокола.

Запросы используют I2CP “to port” из announce URL; см. ниже. “From port” запроса выбирается клиентом, но должен быть ненулевым и отличаться от портов, используемых DHT, чтобы ответы могли быть легко классифицированы. Трекеры должны отклонять запросы, полученные на неправильном порту.

Ответы используют I2CP “to port” из запроса. “From port” запроса является “to port” из запроса.

Announce URL

Формат URL для announce не указан в BEP 15, но как и в clearnet, UDP announce URL имеют вид “udp://host:port/path”. Путь игнорируется и может быть пустым, но обычно это “/announce” в clearnet. Часть :port должна всегда присутствовать, однако, если часть “:port” опущена, используйте порт I2CP по умолчанию 6969, поскольку это общий порт в clearnet. Также могут быть добавлены cgi параметры &a=b&c=d, они могут быть обработаны и предоставлены в запросе announce, см. BEP 41. Если нет параметров или пути, завершающий / также может быть опущен, как подразумевается в BEP 41.

Время жизни соединения

Все значения передаются в сетевом порядке байтов (big endian). Не ожидайте, что пакеты будут точно определенного размера. Будущие расширения могут увеличить размер пакетов.

Connect Request

Клиент к трекеру. 16 байт. Должно быть отвечаемым Datagram2. То же самое, что и в BEP 15. Без изменений.

Offset  Size            Name            Value
  0       64-bit integer  protocol_id     0x41727101980 // magic constant
  8       32-bit integer  action          0 // connect
  12      32-bit integer  transaction_id

Connect Response

Tracker к клиенту. 16 или 18 байт. Должно быть сырым. То же самое, что в BEP 15, за исключением отмеченного ниже.

Offset  Size            Name            Value
  0       32-bit integer  action          0 // connect
  4       32-bit integer  transaction_id
  8       64-bit integer  connection_id
  16      16-bit integer  lifetime        optional  // Change from BEP 15

Ответ ДОЛЖЕН быть отправлен на I2CP “to port”, который был получен как “from port” запроса.

Поле lifetime является необязательным и указывает время жизни connection_id клиента в секундах. По умолчанию это 60, и минимальное значение, если указано, составляет 60. Максимальное значение — 65535 или около 18 часов. Трекер должен поддерживать connection_id на 60 секунд дольше времени жизни клиента.

Announce Request

От клиента к tracker’у. Минимум 98 байт. Должна быть repliable Datagram3. Аналогично BEP 15, за исключением указанного ниже.

connection_id передается таким, как он был получен в ответе на подключение.

Offset  Size            Name            Value
  0       64-bit integer  connection_id
  8       32-bit integer  action          1     // announce
  12      32-bit integer  transaction_id
  16      20-byte string  info_hash
  36      20-byte string  peer_id
  56      64-bit integer  downloaded
  64      64-bit integer  left
  72      64-bit integer  uploaded
  80      32-bit integer  event           0     // 0: none; 1: completed; 2: started; 3: stopped
  84      32-bit integer  IP address      0     // default
  88      32-bit integer  key
  92      32-bit integer  num_want        -1    // default
  96      16-bit integer  port
  98      varies          options     optional  // As specified in BEP 41

Изменения по сравнению с BEP 15:

  • key игнорируется
  • port вероятно игнорируется
  • Секция options, если присутствует, определяется как в BEP 41

Ответ ДОЛЖЕН быть отправлен на “to port” I2CP, который был получен как “from port” запроса. Не используйте порт из запроса announce.

Announce Response

Трекер к клиенту. Минимум 20 байт. Должен быть в сыром виде. То же самое, что в BEP 15, за исключением отмеченного ниже.

Offset  Size            Name            Value
  0           32-bit integer  action          1 // announce
  4           32-bit integer  transaction_id
  8           32-bit integer  interval
  12          32-bit integer  leechers
  16          32-bit integer  seeders
  20   32 * n 32-byte hash    binary hashes     // Change from BEP 15
  ...                                           // Change from BEP 15

Изменения по сравнению с BEP 15:

  • Вместо 6-байтового IPv4+порт или 18-байтового IPv6+порт, мы возвращаем кратное 32-байтовым “компактным ответам” с бинарными SHA-256 хешами узлов. Как и с TCP компактными ответами, мы не включаем порт.

Ответ ДОЛЖЕН быть отправлен на I2CP “to port”, который был получен как “from port” запроса. Не используйте порт из запроса announce.

I2P дейтаграммы имеют очень большой максимальный размер около 64 КБ; однако, для надежной доставки следует избегать дейтаграмм размером более 4 КБ. Для эффективности пропускной способности трекеры, вероятно, должны ограничить максимальное количество пиров примерно до 50, что соответствует пакету размером около 1600 байт до накладных расходов на различных уровнях и должно укладываться в лимит полезной нагрузки двух tunnel сообщений после фрагментации.

Как и в BEP 15, не включен счетчик количества адресов пиров (IP/порт для BEP 15, хеши здесь), которые следуют далее. Хотя это не предусмотрено в BEP 15, можно определить маркер конца пиров из всех нулей, чтобы указать, что информация о пирах завершена и далее следуют некоторые данные расширения.

Чтобы расширение было возможно в будущем, клиенты должны игнорировать 32-байтный хэш из всех нулей и любые данные, которые следуют за ним. Tracker’ы должны отклонять объявления от хэша из всех нулей, хотя этот хэш уже заблокирован Java router’ами.

Scrape

Запрос/ответ Scrape из BEP 15 не требуется данным предложением, но может быть реализован при желании, изменения не требуются. Клиент должен сначала получить connection ID. Запрос scrape всегда является репликабельным Datagram3. Ответ scrape всегда необработанный.

Трекеры

Tracker к клиенту. Минимум 8 байт (если сообщение пустое). Должно быть raw. То же самое, что в BEP 15. Без изменений.

Offset  Size            Name            Value
  0       32-bit integer  action          3 // error
  4       32-bit integer  transaction_id
  8       string          message

Extensions

Биты расширений или поле версии не включены. Клиенты и трекеры не должны предполагать, что пакеты имеют определенный размер. Таким образом, дополнительные поля могут быть добавлены без нарушения совместимости. Формат расширений, определенный в BEP 41, рекомендуется при необходимости.

Ответ на подключение изменен для добавления опционального времени жизни идентификатора соединения.

Если требуется поддержка blinded destination, мы можем либо добавить blinded 35-байтовый адрес в конец запроса announce, либо запросить blinded хеши в ответах, используя формат BEP 41 (параметры уточняются). Набор blinded 35-байтовых peer-адресов может быть добавлен в конец ответа announce после 32-байтового хеша из нулей.

Implementation guidelines

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

Совместимость с BEP 15

Для данного имени хоста tracker’а клиент должен предпочитать UDP перед HTTP URL и не должен объявляться на оба одновременно.

Клиенты с существующей поддержкой BEP 15 должны требовать только небольших модификаций.

Если клиент поддерживает DHT или другие протоколы datagram, он вероятно должен выбрать другой порт в качестве “исходного порта” запроса, чтобы ответы возвращались на этот порт и не смешивались с сообщениями DHT. Клиент получает только необработанные datagram’ы в качестве ответов. Трекеры никогда не отправляют repliable datagram2 клиенту.

Клиенты со стандартным списком opentrackers должны обновить список, добавив UDP URL-адреса после того, как станет известно, что известные opentrackers поддерживают UDP.

Клиенты могут реализовывать или не реализовывать повторную передачу запросов. Повторные передачи, если они реализованы, должны использовать начальный тайм-аут не менее 15 секунд и удваивать тайм-аут для каждой повторной передачи (экспоненциальная задержка).

Клиенты должны отступить после получения ответа об ошибке.

Анализ безопасности

Трекеры с существующей поддержкой BEP 15 должны требовать лишь небольших модификаций. Данное предложение отличается от предложения 2014 года тем, что трекер должен поддерживать прием repliable datagram2 и datagram3 на одном и том же порту.

Чтобы минимизировать требования к ресурсам tracker’а, этот протокол разработан таким образом, чтобы исключить любое требование к tracker’у хранить сопоставления хешей клиентов с идентификаторами соединений для последующей проверки. Это возможно, потому что пакет announce request является отвечаемым пакетом Datagram3, поэтому он содержит хеш отправителя.

Рекомендуемая реализация:

  • Определите текущую эпоху как текущее время с разрешением времени жизни соединения, epoch = now / lifetime.
  • Определите криптографическую хэш-функцию H(secret, clienthash, epoch), которая генерирует 8-байтовый вывод.
  • Сгенерируйте случайную константу secret, используемую для всех соединений.
  • Для ответов на подключение генерируйте connection_id = H(secret, clienthash, epoch)
  • Для запросов announce проверьте полученный connection ID в текущей эпохе, убедившись что connection_id == H(secret, clienthash, epoch) || connection_id == H(secret, clienthash, epoch - 1)

Migration

Существующие клиенты не поддерживают UDP announce URL и игнорируют их.

Существующие трекеры не поддерживают прием отвечаемых или сырых датаграмм, они будут отброшены.

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

Rollout

Ожидается, что первые реализации будут в ZzzOT и i2psnark. Они будут использоваться для тестирования и верификации данного предложения.

Другие реализации последуют по мере необходимости после завершения тестирования и верификации.