XEP-0065: SOCKS5 Bytestreams

From JaWiki (Jabber/XMPP wiki)
Revision as of 08:15, 26 April 2009 by Vindicar (Talk | contribs) (Отношение к XMPP: внутренние ссылки на XMPP Core & XMPP IM)

Jump to: navigation, search


Внимание

Этот текст не является официальным переводом документа XEP-0065: SOCKS5 Bytestreams и может не соответствовать оригиналу. Для разработки программ используйте официальный текст.

Этот документ определяет расширение протокола XMPP для установление внеканального байтового потока между двумя произвольными сущностями Jabber.

ПРИМЕЧАНИЕ: Настоящий протокол имеет статус "Черновик". Его реализации поощряются, и протокол подходит для развёртывания в производственных системах, но прежде, чем он станет Окончательным Стандартом, в протоколе могут произойти некоторые изменения.

Contents

Входные данные

Информация о документе

Информация об авторах

Надлежащее уведомление

На это расширение протокола XMPP распространяется авторское право 1999–2007 Организации Стандартизации XMPP. Документ полностью соответствует Стратегии XSF в Области Интеллектуальной Собственности (XSF's Intellectual Property Rights Policy, http://www.xmpp.org/extensions/ipr-policy.shtml). Этот материал может распространься только в соответствии с установленной далее Лицензией Творческих Общин «Указание Авторства» (Creative Commons Attribution License, http://creativecommons.org/licenses/by/2.5/)

ToDo: Почитать все эти документы и восстановить справедливость

Место обсуждения

Рекомендуется вести обсуждение данного документа в почтовом списке обсуждения Стандартов (http://mail.jabber.org/mailman/listinfo/standards)

Поскольку расширение протокола XMPP нормативно ссылается на технологии IETF, обсуждение в почтовом списке XSF-IETF также может затрагивать данный документ (см. http://mail.jabber.org/mailman/listinfo/jsf-ietf).

Отношение к XMPP

Расширяемый протокол передачи сообщений и информации о присутствии (XMPP) определён в документах «Основы XMPP» (RFC 3920) и «Обмен сообщениями в XMPP» (RFC 3921), внесённых Организацией Стандартизации XMPP в Процесс Стандартизации Интернета (Internet Standards Process), который управляется IETF в соответствии с RFC 2026. Каждый протокол, определённый в этом документе, разработан вне Процесса Стандартизации Интернета и должен рассматриваться как дополнение к XMPP, а не как развитие, продолжение самого XMPP.

Слова соответствия

Следующие ключевые слова, используемые в настоящем документе, долны интерпретироваться в соответствии с RFC 2119:

«ДОЛЖЕН»/«ДОЛЖНА»/«ДОЛЖНО»/«ДОЛЖНЫ», «ОБЯЗАТЕЛЕН»/«ОБЯЗАТЕЛЬНА»/«ОБЯЗАТЕЛЬНО»/«ОБЯЗАТЕЛЬНЫ»;
«НЕ ДОЛЖЕН»/«НЕ ДОЛЖНА»/«НЕ ДОЛЖНО»/«НЕ ДОЛЖНЫ»;
«СЛЕДУЕТ», «РЕКОМЕНДУЕТСЯ»;
«СЛЕДУЕТ НЕ», «РЕКОМЕНДУЕТСЯ НЕ»;
«МОЖЕТ»/«МОГУТ», «НЕОБЯЗАТЕЛЬНЫЙ»/«НЕОБЯЗАТЕЛЬНАЯ»/«НЕОБЯЗАТЕЛЬНОЕ»/«НЕОБЯЗАТЕЛЬНЫЕ».

Описание протокола

Введение

XMPP разработан для пересылки сравнительно малых кусков XML между сетевыми сущностями (см. «Основы XMPP») и не предназначен для пересылки двоичных данных. Тем не менее, иногда требуется передать двоичные данные другой сущности, найденной в сети XMPP (например, передать файл). Поэтому в сообществе Jabber многие признают, что было бы полезно иметь общий протокол для пересылки двоичных данных между двумя произвольными сущностями в сети. Основным приложением такой технологии передачи была бы передача файлов, для которой в настоящее время есть несколько несовместимых протоколов (что выливается в отсутствие совместимости). Тем не менее, возможны и другие приложения, из-за которых важно разработать общий протокол, а не ограниченный частным применением, таким, передача файлов. Этот документ определяет протокол, удовлетворяющий следующим условиям:

  • Байтовые потоки устанавливаются поверх стандартных соединений TCP (RFC 793) или UDP (RFC 768), причём поддержка TCP ОБЯЗАТЕЛЬНА, а поддержка UDP НЕОБЯЗАТЕЛЬНА.
  • Сокеты могут быть прямыми (peer-to-peer) или опосредованными (устанавливаемыми через передающий сервис).
  • Где возможно, используются стандартные протоколы передачи.

Конкретно, данный документ предполагает, что сообщество Jabber пользуется протоколом SOCKS 5 — технологией передачи данных, принятой IETF и совместимой с IPv6. (Примечание: Предлагаемая технология использует подмножество протокола SOCKS 5, специально адаптированное для передачи данных в Jabber, поэтому существующие SOCKS 5 прокси-серверы не могут использоваться для её реализации без соответствующей доработки.)

Терминология

В документе используются следующие термины.

Термин Описание
Инициатор Сущность Jabber, которая желает установить сеанс передачи данных с другой Сущностью.
Цель Сущность, с которой Инициатор пытается установить сеанс передачи.
Посредник Сущность Jabber, не находящаяся за NAT-маршрутизатором или межсетевым экраном и желающая выступать промежуточным звеном при передаче файлов между Инициатором и Целью.
ВедущийУзел Система, к которой подключается Цель и которая управляет передачей. ВедущимУзлом может быть либо Инициатор, либо Посредник.
ИдПередачи Относительно уникальный идентификатор передачи для этого соединения. Он генерируется Инициатором и используется для контроля передачи. Его длина ДОЛЖНА быть меньше 128 символов.

Narrative

ToDo: Как перевести название?

Возможны два сценария, для которых предназначен этот протокол:

  1. прямое соединение (т.е. ВедущийУзел — Инициатор);
  2. опосредованное соединение (т.е. ВедущийУзел — Посредник).

Нормальный ход этих сценариев описан ниже для простоты понимания. Полное описание этих сценариев зафиксировано в разделеQuestion.gifПроверить: Formal Use Case. Здесь описывается только TCP-соединение, UDP-связь описывается в разделеQuestion.gifПроверить: Optional UDP Support настоящего документа.

Прямое соединение

Простейший случай — это прямое соединение. В этой ситуации ВедущимУзлом выступает Инициатор (ВедущийУзел/Инициатор). Это означает, что Инициатор знает сетевой адрес ВедущегоУзла и способ активации передачи. Процесс установки соединения и передачи в этом случае следующий:

  1. Инициатор посылает Цели IQ-запрос (set), указывая полный JID ВедущегоУзла/Инициатора, а также ИдПередачи предлагаемого канала передачи.
  2. Цель открывает TCP-соединение по указанному сетевому адресу.
  3. Цель запрашивает соединение через SOCKS5 со значениями адреса приёмника (DST.ADDR) и порта приёмника (DST.PORT), указанными ниже.
  4. ВедущийУзел/Инициатор посылает подтверждение успешного соединения с Целью по SOCKS5.
  5. Цель отправляет IQ-ответ (result) Инициатору, используя в нём идентификатор начальной IQ-последовательности.
  6. ВедущийУзел/Инициатор активирует передачу.
  7. Инициатор и Цель могут начать пересылку данных.

Опосредованное соединение

Опосредованное соединение немного сложнее. В этом случае ВедущимУзлом является не Инициатор, а Посредник; это означает, что Инициатор должен узнать сетевой адрес ВедущегоУзла перед посылкой начального запроса IQ-set, должен согласовать соединение с ВедущимУзлом таким же образом, как и Цель, и должен запросить, чтобы ВедущийУзел активировал канал передачи прежде, чем он может быть использован. Процесс установки каналов передачи таков:

  1. (Необязательный пункт) Инициатор узнаёт сетевой адрес ВедущегоУзла внутри канала XMPP.
  2. Инициатор посылает Цели запрос IQ-set с указанием полного JID и сетевого адреса ВедущегоУзла, а также ИдПередачи (StreamID, SID) предлагаемого канала передачи.
  3. Цель открывает соединение TCP с выбранным ВедущимУзлом.
  4. Цель устанавливает соединение по SOCKS5 со значениями адреса приёмника (DST.ADDR) и порта приёмника (DST.PORT), определёнными ниже.
  5. ВедущийУзел посылает подтверждение успешного соединения с Целью по SOCKS5.
  6. Цель посылает Инициатору результат IQ-result, используя идентификатор (параметр 'id') исходного запроса IQ-set.
  7. Инициатор открывает соединение TCP с ВедущимУзлом.
  8. Инициатор устанавливает соединение по SOCKS5 со значениями адреса приёмника (DST.ADDR) и порта приёмника (DST.PORT), определёнными ниже.
  9. ВедущийУзел посылает подтверждение успешного соединения с Инициатором по SOCKS5.
  10. Инициатор посылает IQ-set ВедущемуУзлу с запросом активации ВедущимуУзлом канала передачи, связанного с ИдПередачи.
  11. ВедущийУзел активирует канал передачи. (Данные теперь перенаправляются посредником [прокси] из одного соединения SOCKS5 в другое.)
  12. ВедущийУзел посылает результат IQ-result Инициатору, подтверждающий, что канал передачи активирован (или сообщающий об ошибке).
  13. Инициатор и Цель могут начинать использовать канал передачи.

Протокол

Инициатор запрашивает Цель о поддержке передачи данных

Перед попыткой создания канала передачи данных Инициатор может захотеть знать, поддерживает ли Цель протокол передачи. Он может сделать это, используя обнаружение сервисов следующим образом:

Пример 1. Инициатор посылает Цели запрос обнаружения сервисов.

<iq     type='get' 
        from='initiator@host1/foo' 
        to='target@host2/bar' 
        id='hello'>
    <query xmlns='http://jabber.org/protocol/disco#info'/>
</iq>

Если Цель поддерживает передачу данных, она ДОЛЖНА указать это в ответе на запрос обнаружения сервисов.

Пример 2. Цель отвечает за запрос обнаружения сервисов.

<iq     type='result' 
        from='target@host2/bar' 
        to='initiator@host1/foo' 
        id='hello'>
    <query xmlns='http://jabber.org/protocol/disco#info'>
        <identity 
                category='proxy'
                type='bytestreams'
                name='SOCKS5 Bytestreams Service'/>
        ...
        <feature var='http://jabber.org/protocol/bytestreams'/>
        ...
    </query>
</iq>

Инициатор запрашивает Посредников у сервера

Перед попыткой создания канала передачи данных Инициатору надо найти посредника (прокси). Он может сделать это, используя обнаружение сервисов следующим образом:

Пример 3. Инициатор посылает серверу запрос обнаружения сервисов (Servce Discovery).

<iq     type='get' 
        from='initiator@host1/foo'
        to='host1' 
        id='server_items'>
    <query xmlns='http://jabber.org/protocol/disco#items'/>
</iq>

Сервер вернёт все известные JIDы в своём списке сервисов.

Пример 4. Сервер отвечает на запрос обнаружения сервисов.

<iq     type='result' 
        from='host1' 
        to='initiator@host1/foo' 
        id='server_items'>
    <query xmlns='http://jabber.org/protocol/disco#items'>
        ...
        <item jid='proxy.host3' name='Bytestreams Proxy'/>
        ...
    </query>
</iq>

Инициатор спрашивает посредника, является ли он посредником

ToDo: Что автор хотел этим сказать? // Сыр Российский 19:42, 25 October 2007 (CEST)

Каждый элемент списка результатов disco#items Инициатор должен запросить, является ли он посреднико передачи данных. Он может сделать это, используя обнаружение сервисов (Service Discovery) следующим образом:

Пример 5. Инициатор посылает посреднику запрос обнаружения сервисов.

<iq     type='get' 
        from='initiator@host1/foo'
        to='proxy.host3' 
        id='proxy_info'>
    <query xmlns='http://jabber.org/protocol/disco#info'/>
</iq>

Посредник вернёт сведения о себе. Инициатору СЛЕДУЕТ исследовать каждуюQuestion.gifПроверить: личность и посмотреть, содержится ли в этих сведенияхQuestion.gifПроверить: личность категории "proxy" (свойство 'category') и типа "bytestreams" (свойство 'type').

Пример 6. Сервер отвечает на запрос обнаружения сервисов.

<iq     type='result' 
        from='proxy.host3' 
        to='initiator@host1/foo' 
        id='proxy_info'>
    <query xmlns='http://jabber.org/protocol/disco#info'>
        ...
        <identity
                category='proxy'
                type='bytestreams'
                name='SOCKS5 Bytestreams Service'/>
        ...
        <feature var='http://jabber.org/protocol/bytestreams'/>
        ...
    </query>
</iq>

Инициатор узнаёт сетевой адрес ВедущегоУзла

Если ВедущимУзлом выступает Посредник, Инициатор сначала должен запросить полный сетевой адрес, используемый для передачи данных (очевидно, этого не требуется в случае, сли ВедущимУзлом является Инициатор). Это делается посылкой посреднику запроса IQ-get в пространстве имён bytestreams как в следующем примере:

Пример 7. Инициатор запрашивает у Посредника сетевой адрес.

<iq     type='get' 
        from='initiator@host1/foo' 
        to='proxy.host3' 
        id='discover'>
    <query xmlns='http://jabber.org/protocol/bytestreams'/>
</iq>

Элемент <streamhost/>, указывающий сетевой адрес, ДОЛЖЕН иметь следующие атрибуты:

  • jid = JID ВедущегоУзла для соединения через Jabber

Дополнительно, элемент <streamhost/> ДОЛЖЕН включать:

ЛИБО

  • host = сетевое имя или IP-адрес ВедущегоУзла для SOCKS5-соединения через TCP
  • port = порт, связанный с сетевым именем или IP-адресом, для SOCKS5-соединения через TCP

ЛИБО

  • zeroconf = идентификатор zeroconf, к которому может подключиться сущность, для которой идентификатору службы и названию протокола СЛЕДУЕТ быть "_jabber.bytestreams".

Пример 8. Посредник сообщает Инициатору сетевой адрес.

<iq     type='result' 
        from='proxy.host3' 
        to='initiator@host1/foo' 
        id='discover'>
    <query xmlns='http://jabber.org/protocol/bytestreams'>
        <streamhost 
                jid='proxy.host3' 
                host='24.24.24.1' 
                zeroconf='_jabber.bytestreams'/>
    </query>
</iq>

Если у Инициатора нет права инициировать передачу данных на Посреднике по любой причине (например, реализация посредника может позволять администраторам запрещать JIDам или доменам использование Посредника), Посредник ДОЛЖЕН вернуть ошибку <forbidden/> («запрещено») Инициатору (за информацией о синтаксисе ошибок обращайтесь к XEP-0086: Error Condition Mappings):

Пример 9. Посредник возвращает Иициатору ошибку.

<iq     type='error' 
        from='initiator@host1/foo' 
        to='proxy.host3' 
        id='discover'>
    <query xmlns='http://jabber.org/protocol/bytestreams'/>
        <error code='403' type='auth'>
        <forbidden xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/>
    </error>
</iq>

Если Посредник не может выступать в качестве ВедущегоУзла, ему СЛЕДУЕТ вернуть Инициатору ошибку <not-allowed/> («не разрешено»):

Пример 10. Посредник возвращает Инициатору ошибку.

<iq     type='error' 
        from='initiator@host1/foo' 
        to='proxy.host3' 
        id='discover'>
    <query xmlns='http://jabber.org/protocol/bytestreams'/>
        <error code='405' type='cancel'>
        <not-allowed xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/>
    </error>
</iq>

Инициатор сообщает Цели о ВедущихУзлах

Чтобы организовать передачу данных между Инициатором и Целью, Инициатор должен предоставить Цели сведения о сетевом адресе ВедущегоУзла (или узлов). Это совершается внутри канала с помощью одного набора IQ-set, который должен содержать следующие сведения:

  • Сетевой адрес по меньшей мере одного ВедущегоУзла, к которому может попытаться подключиться Цель.
  • ИдПередачи для этого соединения.
  • Использующийся режим (mode), обычно "tcp", но при определённых условиях может быть "udp" (см.Question.gifПроверить: #Optional UDP Support).

Формат протокола показан ниже.

Пример 11. Начало взаимодействия.

<iq     type='set'
        from='initiator@host1/foo'
        to='target@host2/bar'
        id='initiate'>
    <query  xmlns='http://jabber.org/protocol/bytestreams'
            sid='mySID'
            mode='tcp'>
        <streamhost
                jid='initiator@host1/foo'
                host='192.168.4.1'
                port='5086'/>
        <streamhost
                jid='proxy.host3'
                host='24.24.24.1'
                zeroconf='_jabber.bytestreams'/>
    </query>
</iq>

Если Цель не желает принимать передачу, она ДОЛЖНА вернуть Инициатору ошибку <not-acceptable/> («не принято»).

Пример 12. Цель отклоняет передачу.

<iq     type='error'
        from='target@host2/bar'
        to='initiator@host1/foo'
        id='initiate'>
    <error code='406' type='auth'>
        <not-acceptable xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/>
    </error>
</iq>

Цель устанавливает соединение SOCKS5 с ВедущимУзлом

Если Цель согласна принять поток данных, она ДОЛЖНА попытаться открыть стандартный сокет TCP на сетевом интерфейсе ВедущегоУзла, соединённого с Инициатором. Если Инициатором было предложено несколько ВедущихУзлов, Цели СЛЕДУЕТ попытаться соединиться с ними в том порядке, в котором они указаны.

Если Цель пытается, но не может соединиться ни с каким из ВедущихУзлов и не желает пытаться установить соединение со своей стороны
ToDo: сомневаюсь в правильности перевода: it does not wish to attempt a connection from its side
, она ДОЛЖНА вернуть Инициатору ошибку <item-not-found/> («элемент не найдён»).

Пример 13. Цель не может соединиться ни с каким из ВедущихУзлов и желает завершить транзакцию.

<iq     type='error' 
        from='target@host2/bar' 
        to='initiator@host1/foo' 
        id='initiate'>
    <error code='404' type='cancel'>
        <item-not-found xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/>
    </error>
</iq>

Если Цель может открыть сокет TCP на ВедущемУзле, она ДОЛЖНА использовать протокол SOCKS5, описанный в RFC 1982 для установления соединения с ВедущимУзлом. В соответствии с RFC по SOCKS5, у Цели МОЖЕТ быть затребован пароль для доступа к прокси-серверу. Тем не менее, всё, что касается аутентификации, находится за пределами этого документа.

Когда Цель будет успешно аутентифицирована на Посреднике (даже анонимно), ей СЛЕДУЕТ послать запрос CONNECT соответствующему узлу, чтобы продолжить процесс установления соединения. При этом применяются следующие правила:

  1. Имя узла (hostname) должно быть SHA1(ИдПередачи + JID Инициатора + JID Цели), где хэш-функция SHA-1 определена согласно RFC 3174 и её выход записывается в шестнадцатеричной системе счисления (не двоичным кодом).
  2. Порт (port) ДОЛЖЕН быть 0 (ноль).
  3. Указанные Jabber-идентификаторы ДОЛЖНЫ быть идентификаторами, использующимися для обмена IQ-стансами, которые могут быть полными JID (node@domain.tld/resource) или голыми JID (node@domain.tld).
  4. Перед применением алгоритма хэширования SHA-1 к Jabber-идентификаторам ДОЛЖНЫ быть применены соответствующие профили stringprep (как указано в «Основах XMPP»).

Пример 14. Цель соединяется с ВедущимУзлом

CMD = X'01'
ATYP = X'03'
DST.ADDR = SHA1 Hash of: (SID + Initiator JID + Target JID)
DST.PORT = 0

Пример 15. ВедущийУзел принимает соединение

STATUS = X'00'

При ответе клиенту, в соответствии с разделом 6 RFC 1928, ВедущемуУзлу СЛЕДУЕТ выставить параметры BND.ADDR и BND.PORT в значения, предоставленные клиентом в запросе соединения.

Цель подтверждает соединение SOCKS5

После того как Цель будет аутентифицирована ВедущимУзлом, она ДОЛЖНА послать Инициатору IQ-результат, сообщающий о том, какой ВедущийУзел она использует.

Пример 16. Цель уведомляет Инициатора о соединении.

<iq     type='result' 
        from='target@host2/bar' 
        to='initiator@host1/foo' 
        id='initiate'>
    <query xmlns='http://jabber.org/protocol/bytestreams'>
        <streamhost-used jid='proxy.host3'/>
    </query>
</iq>

Здесь Инициатор узнаёт, какой ВедущийУзел использует Цель.

Инициатор устанавливает соединение SOCKS5 с ВедущимУзлом

Если ВедущийУзел использует Посредника, Инициатор ДОЛЖЕН аутентифицировать и установить соединение с ВедущимУзлом перед запросом активации потока передачи данных. Инициатор установит соединение с прокси-сервером SOCKS5 тем же способом, что и Цель (указывая те же значения в запросе CONNECT), как показано в следущих примерах.


Пример 17. Инициатор соединяется с ВедущимУзлом.

CMD = X'01'
ATYP = X'03'
DST.ADDR = SHA1 Hash of: (SID + Initiator JID + Target JID)
DST.PORT = 0


Пример 18. ВедущийУзел принимает соединение Инициатора.

STATUS = X'00'

Activation of Bytestream

In order for the bytestream to be used, it MUST first be activated by the StreamHost. If the StreamHost is the Initiator, this is straightforward and does not require any in-band protocol. However, if the StreamHost is a Proxy, the Initiator MUST send an in-band request to the StreamHost. This is done by sending an IQ-set to the Proxy, including an <activate/> element whose XML character data specifies the full JID of the Target.

Example 19. Initiator Requests Activation of Bytestream <iq type='set'

   from='initiator@host1/foo' 
   to='proxy.host3' 
   id='activate'>
 <query xmlns='http://jabber.org/protocol/bytestreams' sid='mySID'>
   <activate>target@host2/bar</activate>
 </query>

</iq>


Using this information, with the SID and from address on the packet, the Proxy is able to activate the stream by hashing the SID + Initiator JID + Target JID. This provides a reasonable level of trust that the activation request came from the Initiator.

If the Proxy can fulfill the request, it MUST then respond to the Initiator with an IQ-result.

Example 20. Proxy Informs Initiator of Activation <iq type='result'

   from='proxy.host3' 
   to='initiator@host1/foo' 
   id='activate'/>
   

If the Proxy cannot fulfill the request, it MUST return an IQ-error to the Initiator; the following conditions are defined: <item-not-found/> error if the from address does not match that of the Initiator's full JID <not-allowed/> error if only one party (either Initiator or Recipient, but not both) is connected to the Proxy <internal-server-error/> error if the proxy cannot activate the bytestream because of some internal malfunction

Formal Use Case

This is a formal representation of the narrative information provided above. The primary actor is the Initiator and the goal is to establish a bytestream between the Initiator and the Target. (Note: "UCE" stands for "Use Case Ends" (success is assumed unless otherwise specified), "P" stands for "Primary Flow", and "A" stands for "Alternate Flow".)

Primary Flow

Initiator wishes to establish a bytestream with Target Initiator sends an IQ-set to Target specifying a StreamID and the network addresses of one or more StreamHosts [A1] Target wishes to establish a bytestream with Initiator [A2] Target requests TCP connection with a StreamHost [A3] Target receives TCP acknowledgement from StreamHost [A4] Target provides authentication credentials to StreamHost via SOCKS5 Target receives acknowledgement of authentication with StreamHost via SOCKS5 [A5] Target requests connection with StreamHost via SOCKS5 Target receives acknowledgement of successful connection with StreamHost via SOCKS5 [A7] Target sends IQ-result to Initiator announcing successful connection to StreamHost [A6] Use Case Ends (bytestream is established and ready for use)

Alternate Flows

A1. Initiator does not know the full network address of a StreamHost (i.e., Proxy) Initiator sends IQ-get to Proxy Initiator receives IQ-result from Proxy containing network address [A9][A10] Return to P2

A2. Target does not wish to establish a bytestream with Initiator Initiator receives <not-acceptable/> error from Target UCE unsuccessfully

A3. No more StreamHosts in list (Target is unable to reach any of the provided StreamHosts) Target returns <remote-server-not-found/> error to Initiator UCE unsuccessfully

A4. Target cannot reach StreamHost Return to P4

A5. Target authentication with StreamHost fails Return to P4

A6. Proxy is unwilling to act as a StreamHost for Initiator Initiator receives <forbidden/> error from Proxy Return to P2

A7. Proxy is unable to act as a StreamHost for Initiator Initiator receives <not-allowed/> error from Proxy Return to P2

A8. Target connects to a Proxy Initiator reaches Proxy [A9] Target receives TCP acknowledgement from StreamHost [A9] Initiator authenticates with Proxy via SOCKS5 Initiator receives acknowledgement of authentication with Proxy via SOCKS5 [A10] Initiator requests connection with Proxy via SOCKS5 Initiator receives acknowledgement of successful connection with Proxy via SOCKS5 [A11] Initiator sends IQ-set to Proxy requesting activation of bytestream Initiator receives IQ-result from Proxy acknowledging activation of bytestream [A12] Return to P9

A9. Initiator is unable to reach Proxy UCE unsuccessfully

A10. Initiator is unable to authenticate with Proxy UCE unsuccessfully

A11. Initiator is unable to connect to Proxy UCE unsuccessfully

A12. Proxy is unable to activate bytestream Initiator receives <internal-server-error/> error from Proxy UCE unsuccessfully

Formal Description

<query/> Element

The <query/> element is the container for all in-band communications. This element MUST be in the namespace "http://jabber.org/protocol/bytestreams". This element has a single attribute for the stream session identifier, and contains multiple <streamhost/> elements, a single <streamhost-used/> element, or a single <activate/> element.

The "sid" specifies the bytestream session identifier. This attribute MUST be present. The value of this attribute is any character data.

The "mode" specifies the mode to use, either 'tcp' or 'udp'. If this attribute is missing, the default value of "tcp" MUST be assumed.

The <streamhost/> element conveys the network connection information. At least one instance MUST be present in the initial IQ-set from the Initiator to the Target. If multiple instances of this element are present, each one MUST be a separate host/port combination.

The <streamhost-used/> element transports the out-of-band token. It MUST be present in the IQ-set from the Target to the Initiator, and there MUST be only one instance.

The <activate/> element is used to request activation of a unidirectional or bidirectional bytestream. It MUST be present in the IQ-set sent from the Initiator to the StreamHost after the Initiator receives an IQ-result from the Target, and there MUST be only one instance.

<streamhost/> Element

The <streamhost/> element contains the bytestream connection information. This element has attributes for the StreamHost's JID, network host/address, and network port. This element MUST NOT contain any content nodes.

The "jid" attribute specifies the StreamHost's JID. This attribute MUST be present, and MUST be a valid JID for use with an <iq/>.

The "host" attribute specifies the host to connect to. This attribute MUST be present. The value MUST be either a resolvable domain name or the "dotted decimal" IP address (e.g. "1.2.3.4").

The "port" attribute specifies the port to connect to. This attribute MAY be present. The value MUST be a valid port number in decimal form.

The "zeroconf" attribute specifies the zero-configuration service available for bytestreaming. This attribute SHOULD be present. The value SHOULD be '_jabber.bytestreams'.

When communicating the available hosts, the Initiator MUST include EITHER the host and port OR the zeroconf information.

<streamhost-used/> Element

The <streamhost-used/> element indicates the StreamHost connected to. This element has a single attribute for the JID of the StreamHost to which the Target connected. This element MUST NOT contain any content node.

The "jid" attribute specifies the full JID of the StreamHost. This attribute MUST be present, and MUST be a valid JID for use with an <iq/>.

<activate/> Element

The <activate/> element is a flag to trigger a Proxy to complete a connection.

Optional UDP Support

Support for UDP associations is strictly OPTIONAL. However, implementations that support UDP associations MUST adhere to the profile described in this section.

Discovering UDP Support

If an implementation supports UDP associations, it MUST advertise that separately by returning a feature of 'http://jabber.org/protocol/bytestreams#udp' in response to Service Discovery information requests.

Example 21. Initiator Sends Service Discovery Request to Target <iq type='get'

   from='initiator@host1/foo' 
   to='target@host2/bar' 
   id='hello2'>
 <query xmlns='http://jabber.org/protocol/disco#info'/>

</iq>


If the Target supports UDP associations, it MUST answer to that effect in the service discovery result.

Example 22. Target Replies to Service Discovery Request <iq type='result'

   from='target@host2/bar' 
   to='initiator@host1/foo' 
   id='hello2'>
 <query xmlns='http://jabber.org/protocol/disco#info'>
   <identity 
       category='proxy'
       type='bytestreams'
       name='SOCKS5 Bytestreams Service'/>
   ...
   <feature var='http://jabber.org/protocol/bytestreams'/>
   <feature var='http://jabber.org/protocol/bytestreams#udp'/>
   ...
 </query>

</iq>

Requesting UDP Mode

UDP associations are requested by setting the 'mode' attribute to a value of "udp" rather than "tcp".

Example 23. Initiation of Interaction (UDP) <iq type='set'

   from='initiator@host1/foo' 
   to='target@host2/bar' 
   id='initiate'>
 <query xmlns='http://jabber.org/protocol/bytestreams' 
        sid='mySID' 

mode='udp'>

   <streamhost 
       jid='initiator@host1/foo' 
       host='192.168.4.1' 
       port='5086'/>
 </query>

</iq>

UDP Process

There is one main difference between UDP mode and TCP mode: rather than simply establishing a TCP connection, the Target and/or Initiator MUST (1) establish a UDP association and then (2) initialize the UDP channel. In particular: If direct connection is followed, Target MUST complete UDP association and initialization of the UDP channel before informing Initiator of success via the <streamhost-used/> element. If mediated connection is followed, (1) Target MUST complete UDP association and initialization of the UDP channel before informing Initiator of success via the <streamhost-used/> element, and (2) Initiator MUST complete UDP association and initialization of the UDP channel before asking StreamHost to activate the bytestream.

The processes for establishing the UDP association and for initializing the UDP channel are described below.

Establishing the UDP Association

Once the Target has successfully authenticated with the Proxy (as described under Target Establishes SOCKS5 Connection with StreamHost), it MUST send a UDP ASSOCIATE (rather than CONNECT) request to the host identified by the algorithm defined above.

Example 24. Target Requests UDP Association with StreamHost CMD = X'03' ATYP = X'03' DST.ADDR = SHA1 Hash of: (SID + Initiator JID + Target JID) DST.PORT = 0


The StreamHost then acknowledges this request:

Example 25. StreamHost Acknowledges Request STATUS = X'00'

Initializing the UDP Channel

After connecting to the StreamHost, the Target (direct connection) or both Target and Initiator (mediated connection) MUST initialize the UDP channel. In order to do so, each sending entity MUST send a SOCKS5 UDP packet to the StreamHost on the same port used for the initial TCP connection (in the foregeoing example, a host of 192.168.4.1 and port of 5086), with DST.PORT set to '1' and DATA containing the sending entity's JID (i.e, the JID of either the Target or Initiator).

Example 26. Target or Initiator Sends UDP Initialization Packet to StreamHost ATYP = X'03' DST.ADDR = SHA1 Hash of: (SID + Initiator JID + Target JID) DST.PORT = 1 DATA = Target or Initiator JID


Upon successful receipt by the StreamHost, the StreamHost MUST reply with a message notification indicating success:

Example 27. StreamHost Notifies Target or Initiator of UDP Success <message

   from='proxy.host3' 
   to='target@host2/bar' 
   id='initiate'>
 <udpsuccess xmlns='http://jabber.org/protocol/bytestreams' dstaddr='Value of Hash'/>

</message>


The <udpsuccess/> element indicates that the StreamHost has received a UDP initialization packet. This element has a single attribute containing the DST.ADDR that was used in the UDP packet.

If Target is unable to initialize the UDP channel, it MUST return a <remote-server-not-found/> error to Initiator.

Note: Since UDP is not reliable, the Target SHOULD resend the UDP packet if the reply notification is not received within a short time (a 5-second retry is RECOMMENDED). The StreamHost SHOULD ignore duplicate UDP initialization packets once it has replied with a notification.

Exchanging UDP Packets

Once the UDP association is established, UDP packets can be exchanged with the StreamHost. When a UDP packet is sent by either party, it MUST contain a 4-byte header (in addition to other possible headers, such as that of SOCKS5), which consists of the source virtual port and then the destination virtual port of the packet, both 16-bit values in network byte order. This allows the peers to multiplex many packets for different purposes over one session. The actual application data should follow this header, and thus the payload size will always be "Application Data Size + 4".

For all packets sent to the StreamHost, DST.PORT is set to 0, and DATA contains the payload.

Example 28. Sending UDP to StreamHost ATYP = X'03' DST.ADDR = SHA1 Hash of: (SID + Initiator JID + Target JID) DST.PORT = 0 DATA = (payload)


UDP packets sent from the StreamHost do not have any SOCKS5 headers, and so the payload should be delivered as-is.

The programming interface for a SOCKS5 Bytestreams-aware UDP MUST report an available buffer space for UDP datagrams that is smaller than the actual space provided by the operating system and SOCKS5 layer if applicable. In other words, 4 more octets smaller.

Implementation Notes

StreamHost Requirements

A StreamHost MUST support TCP connections.

A StreamHost SHOULD: Allow bi-directional bytestreaming between the Initiator and Target. Allow only one Target to connect to a bytestream (i.e., disallow multicasting). Track sessions based on a combination of the StreamID and the Initiator's full JID, thus allowing an Initiator to create more than one simultaneous session. Ignore but not drop any bytes sent before the bytestream is activated. Prefer to use zero-configuration IP networking if supported.

A StreamHost MAY: Support UDP associations in addition TCP connections. Ignore the DST.ADDR and DST.PORT parameters if desired.

SOCKS5 Parameter Mapping

To facilitate the usage of SOCKS5, command parameters MUST be mapped to the appropriate values. Parameters not specified in the table below SHOULD be used as defined in RFC 1928.

Table 2: Request/Parameter Mapping for CONNECTParameter Value CMD 1 (CONNECT) ATYP Hardcoded to 3 (DOMAINNAME) in this usage DST.ADDR SHA1 Hash of: (SID + Initiator JID + Target JID) DST.PORT 0


Table 3: Request/Parameter Mapping for UDP ASSOCIATEParameter Value CMD 3 (UDP ASSOCIATE) ATYP Hardcoded to 3 (DOMAINNAME) in this usage DST.ADDR SHA1 Hash of: (SID + Initiator JID + Target JID) DST.PORT 0


Table 4: Request/Parameter Mapping for UDP PacketsParameter Value ATYP Hardcoded to 3 (DOMAINNAME) in this usage DST.ADDR SHA1 Hash of: (SID + Initiator JID + Target JID) DST.PORT 0 or 1, for payload or initialization packets, respectively.

Security Considerations

This proposal does not include a method for securing or encrypting SOCKS5 bytetreams. If such security is desired, it MUST be negotiated over the bytestream (once established) using standard protocols such as SSL or TLS. Negotiation of such security methods is outside the scope of this document.

IANA Considerations

This document requires no interaction with the Internet Assigned Numbers Authority (IANA) [10].

XMPP Registrar Considerations

Protocol Namespaces

The XMPP Registrar [11] includes 'http://jabber.org/protocol/bytestreams' in its registry of protocol namespaces.

Service Discovery Features

The XMPP Registrar shall includes 'http://jabber.org/protocol/bytestreams#udp' in its registry of service discovery features.

Service Discovery Category/Type

The XMPP Registrar includes the "proxy" category and associated "bytestreams" type in the Service Discovery registry. The registry submission is as follows:

 <category>
   <name>proxy</name>
   <desc>Proxy servers or services</desc>
   <type>
     <name>bytestreams</name>
     <desc>A proxy for SOCKS5 bytestreams</desc>
     <doc>XEP-0065</doc>
   </type>
 </category>
   

Schema

<?xml version='1.0' encoding='UTF-8'?>

<xs:schema

   xmlns:xs='http://www.w3.org/2001/XMLSchema'
   targetNamespace='http://jabber.org/protocol/bytestreams'
   xmlns='http://jabber.org/protocol/bytestreams'
   elementFormDefault='qualified'>
 <xs:annotation>
   <xs:documentation>
     The protocol documented by this schema is defined in
     XEP-0065: http://www.xmpp.org/extensions/xep-0065.html
   </xs:documentation>
 </xs:annotation>
 <xs:element name='query'>
   <xs:complexType>
     <xs:choice>
       <xs:element ref='streamhost' minOccurs='0' maxOccurs='unbounded'/>
       <xs:element ref='streamhost-used' minOccurs='0'/>
       <xs:element name='activate' type='empty' minOccurs='0'/>
     </xs:choice>
     <xs:attribute name='sid' type='xs:string' use='optional'/>
     <xs:attribute name='mode' use='optional' default='tcp'>
       <xs:simpleType>
         <xs:restriction base='xs:NCName'>
           <xs:enumeration value='tcp'/>
           <xs:enumeration value='udp'/>
         </xs:restriction>
       </xs:simpleType>
     </xs:attribute>
   </xs:complexType>
 </xs:element>
 <xs:element name='streamhost'>
   <xs:complexType>
     <xs:simpleContent>
       <xs:extension base='empty'>
         <xs:attribute name='jid' type='xs:string' use='required'/>
         <xs:attribute name='host' type='xs:string' use='required'/>
         <xs:attribute name='zeroconf' type='xs:string' use='optional'/>
         <xs:attribute name='port' type='xs:string' use='optional'/>
       </xs:extension>
     </xs:simpleContent>
   </xs:complexType>
 </xs:element>
 <xs:element name='udpsuccess'>
   <xs:complexType>
     <xs:simpleContent>
       <xs:extension base='empty'>
         <xs:attribute name='dstaddr' type='xs:string' use='required'/>
       </xs:extension>
     </xs:simpleContent>
   </xs:complexType>
 </xs:element>
 <xs:element name='streamhost-used'>
   <xs:complexType>
     <xs:simpleContent>
       <xs:extension base='empty'>
         <xs:attribute name='jid' type='xs:string' use='required'/>
       </xs:extension>
     </xs:simpleContent>
   </xs:complexType>
 </xs:element>
 <xs:simpleType name='empty'>
   <xs:restriction base='xs:string'>
     <xs:enumeration value=/>
   </xs:restriction>
 </xs:simpleType>

</xs:schema>

Выходные данные

Notes

1. RFC 3920: Extensible Messaging and Presence Protocol (XMPP): Core <http://tools.ietf.org/html/rfc3920>.

2. RFC 793: Transmission Control Protocol <http://tools.ietf.org/html/rfc0793>.

3. RFC 768: User Datagram Protocol <http://tools.ietf.org/html/rfc0768>.

4. XEP-0030: Service Discovery <http://www.xmpp.org/extensions/xep-0030.html>.

5. Zeroconf is a set of protocols that enable IP networking without the need for configuration. For further information, refer to <http://www.zeroconf.org/>.

6. XEP-0086: Error Condition Mappings <http://www.xmpp.org/extensions/xep-0086.html>.

7. RFC 1928: SOCKS Protocol Version 5 <http://tools.ietf.org/html/rfc1928>.

8. RFC 3174: US Secure Hash Algorithm 1 (SHA1) <http://tools.ietf.org/html/rfc3174>.

9. RFC 3920: Extensible Messaging and Presence Protocol (XMPP): Core <http://tools.ietf.org/html/rfc3920>.

10. The Internet Assigned Numbers Authority (IANA) is the central coordinator for the assignment of unique parameter values for Internet protocols, such as port numbers and URI schemes. For further information, see <http://www.iana.org/>.

11. The XMPP Registrar maintains a list of reserved protocol namespaces as well as registries of parameters used in the context of XMPP extension protocols approved by the XMPP Standards Foundation. For further information, see <http://www.xmpp.org/registrar/>.

Revision History

Version 1.7 (2007-05-21)

Incorporated errata: specified format for SHA1 output; specified BND.ADDR and BND.PORT for SOCKS5 reply; removed extraneous SOCKS5 acknowledgement example from Section 4.9; clarified rules for creation of SOCKS5 connection request in Section 4.6; added examples to Section 4.8; specified that ATYP value is hardcoded to 3 in this usage. (psa) Version 1.6 (2004-11-12)

Added UDP support (OPTIONAL). (ds/psa) Version 1.5 (2004-06-29)

Added requirement to apply stringprep profiles before SHA1 hashing; added reference to RFC 3174. (psa) Version 1.4 (2004-06-28)

Cleaned up narratives to reflect current practices and removed unnecessary authentication references; fixed mismatch SOCKS5 parameter table values. (ds) Version 1.3 (2003-09-24)

Added disco#info <identity/> and corresponding XMPP Registrar submission; added XMPP error handling. (psa) Version 1.2 (2003-07-15)

Removed SIDs from the result queries, you should key off the IQ 'id' attribute instead. Added the disco exchange for finding available proxies. (rwe) Version 1.1 (2003-07-09)

Changed srvid to zeroconf; cleaned up use cases; updated the schema. (ds) Version 1.0 (2003-04-21)

Per a vote of the Jabber Council, advanced status to Draft. (psa) Version 0.7 (2003-03-04)

Clarified that this proposal uses an adaptation of the SOCKS5 protocol, not the full protocol; replaced DTD with schema; added security considerations. (psa) Version 0.6 (2003-01-27)

Added service discovery example; added 'srvid' attribute to streamhost element and required inclusion of either 'srvid' or 'port' attribute; improved the algorithms for generating SOCKS5 UNAME and PASSWD parameters; specified that the DST.ADDR and DST.PORT parameters may be ignored; removed references to connected/disconnected notification, bidirectional bytestreams, and multiple targets; updated implementation notes. (psa/ds) Version 0.5 (2002-12-20)

Specified option of "reversing the connection" (Target becomes Initiator); added more error cases; resurrected and cleaned up formal use case. (psa) Version 0.4 (2002-12-19)

Added section on connected/disconnected notifications sent from Proxy to Initiator; cleaned up several examples; specified more error conditions; clarified the formal descriptions; added implementation notes and future considerations. (psa, mm) Version 0.3 (2002-12-17)

Added lots of detail to the narrative and protocol. (psa) Version 0.2 (2002-12-16)

Added SOCKS info. (ds) Version 0.1 (2002-12-13)

Initial version. (ds)

END