1
0
mirror of https://github.com/moparisthebest/xeps synced 2024-11-24 10:12:19 -05:00
git-svn-id: file:///home/ksmith/gitmigration/svn/xmpp/trunk@4155 4b5297f7-1745-476d-ba37-a9c6900126ab
This commit is contained in:
Peter Saint-Andre 2010-04-13 14:05:56 +00:00
parent 3188fd4ced
commit edb367a4e2

View File

@ -11,6 +11,7 @@
&LEGALNOTICE; &LEGALNOTICE;
<number>0065</number> <number>0065</number>
<status>Draft</status> <status>Draft</status>
<interim/>
<type>Standards Track</type> <type>Standards Track</type>
<sig>Standards</sig> <sig>Standards</sig>
<dependencies> <dependencies>
@ -30,8 +31,8 @@
&stpeter; &stpeter;
&infiniti; &infiniti;
<revision> <revision>
<version>1.8rc1</version> <version>1.8rc2</version>
<date>in progress, last updated 2010-03-15</date> <date>in progress, last updated 2010-04-13</date>
<initials>psa</initials> <initials>psa</initials>
<remark> <remark>
<ul> <ul>
@ -40,6 +41,10 @@
<li>Removed 'sid' attribute from address query examples because it is unnecessary in that use case.</li> <li>Removed 'sid' attribute from address query examples because it is unnecessary in that use case.</li>
<li>Removed the anomalous Formal Use Case text for consistency with all other XEPs.</li> <li>Removed the anomalous Formal Use Case text for consistency with all other XEPs.</li>
<li>Refactored the text in various ways to make it more readable.</li> <li>Refactored the text in various ways to make it more readable.</li>
<li>Added text about use in Multi-User Chat, including new 'dstaddr' attribute.</li>
<li>Removed requirement that the StreamHost should not drop any bytes sent before the bytestream is activated, since that behavior introduced the possibility of a denial of service attack.</li>
<li>Removed length limit on 'sid' attribute.</li>
<li>Defined the security considerations in a more thorough manner.</li>
</ul> </ul>
</remark> </remark>
</revision> </revision>
@ -136,18 +141,18 @@
</header> </header>
<section1 topic='Introduction' anchor='intro'> <section1 topic='Introduction' anchor='intro'>
<p>XMPP is designed for sending relatively small fragments of XML between network entities (see &xmppcore;) and is not designed for sending binary data. However, sometimes it is desirable to send binary data to another entity that one has discovered on the XMPP network (e.g., to send a file). Therefore it is valuable to have a generic protocol for streaming binary data between any two entities on an XMPP network. The main application for such a bytestreaming technology is file transfer as specified in &xep0096; and &xep0234;. However, other applications are possible, which is why it is important to develop a generic protocol rather than one that is specialized for a particular application such as file transfer.</p> <p>XMPP is designed for sending relatively small chunks of XML between network entities and is not designed for sending binary data. However, sometimes it is desirable to send binary data to another entity that one has discovered on the XMPP network (e.g., to send a file). Therefore it is valuable to have a generic protocol for streaming binary data between any two entities on an XMPP network. The main application for such a bytestreaming technology is file transfer as specified in &xep0096; and &xep0234;. However, other applications are possible, which is why it is important to develop a generic protocol rather than one that is specialized for a particular application such as file transfer.</p>
<p>This document defines a protocol that meets the following conditions:</p> <p>This document defines a protocol that meets the following conditions:</p>
<ul> <ul>
<li>Bytestreams are established over standard TCP connections (&rfc0793;) or UDP associations (&rfc0768;), where TCP support is REQUIRED and UDP support is OPTIONAL</li> <li>Bytestreams are established over standard TCP connections (&rfc0793;) or UDP associations (&rfc0768;), where TCP support is REQUIRED and UDP support is OPTIONAL</li>
<li>Sockets can be direct (peer-to-peer) or mediated (established through a relay)</li> <li>Sockets can be direct (peer-to-peer) or mediated (established through a relay)</li>
<li>Where possible, standard wire protocols are used</li> <li>Where possible, standard wire protocols are used</li>
</ul> </ul>
<p>Specifically, this document makes use of the SOCKS 5 protocol, which is an IETF-approved, IPv6-ready technology for bytestreams defined in &rfc1928;. However, because this proposal uses a subset of the SOCKS5 protocol that is specially adapted for bytestreaming over XMPP, existing SOCKS5 proxies cannot be used to implement this proposal without modifications.</p> <p>Specifically, this protocol makes use of the SOCKS 5 protocol, which is an IETF-approved, IPv6-ready technology for bytestreams defined in &rfc1928;. However, because this protocol uses a subset of the SOCKS5 protocol that is specially adapted for bytestreaming over XMPP, existing SOCKS5 proxies cannot be used to implement this protocol without modifications.</p>
<p>There are two scenarios addressed by this protocol:</p> <p>There are two scenarios addressed by this protocol:</p>
<ol> <ol>
<li>A direct connection in which the StreamHost is the Requester, as described under <link url='#direct'>Direct Connections</link></li> <li>A direct connection in which the StreamHost is the Requester, as described under <link url='#direct'>Direct Connection</link></li>
<li>A mediated connection in which the StreamHost is a Proxy, as described under <link url='#mediated'>Mediated Connections</link></li> <li>A mediated connection in which the StreamHost is a Proxy, as described under <link url='#mediated'>Mediated Connection</link></li>
</ol> </ol>
<p>Early versions of this specification documented only the use of TCP connections. In version 1.6 (approved in November 2004), optional UDP associations were added, as described in the <link url='#udp'>Optional UDP Support</link> section of this document. However, the main body of this document describes the use of TCP, which is the primary method of SOCKS5 Bytestreams ("S5B").</p> <p>Early versions of this specification documented only the use of TCP connections. In version 1.6 (approved in November 2004), optional UDP associations were added, as described in the <link url='#udp'>Optional UDP Support</link> section of this document. However, the main body of this document describes the use of TCP, which is the primary method of SOCKS5 Bytestreams ("S5B").</p>
</section1> </section1>
@ -173,15 +178,15 @@
</di> </di>
<di> <di>
<dt>StreamID</dt> <dt>StreamID</dt>
<dd>A relatively unique Stream ID for this connection; this is generated by the Requester for tracking purposes and MUST be less than 128 characters in length.</dd> <dd>A relatively unique Stream ID for this connection; this is generated by the Requester for tracking purposes.</dd>
</di> </di>
</dl> </dl>
<p>Note: Because either party can attempt to establish a bytestream (this is formalized in &xep0260;), the Requester and the Target roles apply to a particular S5B negotiation, and do not map to the Initiator and Responder roles from &xep0166; in a fixed way. For example, during a Jingle negotiation the Initiator might first take on the role of an S5B Requester but if that first bytestreams negotiation fails then the Jingle Responder might take on the role of an S5B Requester.</p> <p>Note: Because either party can attempt to establish a bytestream (this is formalized in &xep0260;), the Requester and the Target roles apply to a particular S5B negotiation, and do not map to the Initiator and Responder roles from &xep0166; in a fixed way. For example, during a Jingle negotiation the Jingle Initiator might first take on the role of an S5B Requester but if that first bytestreams negotiation fails then the Jingle Responder might take on the role of an S5B Requester.</p>
<p>In the protocol flow diagrams, the line types have the following meaning:</p> <p>In the protocol flow diagrams, the line types have the following meaning:</p>
<ul> <ul>
<li>"----" ... communications over XMPP</li> <li>"----" ... communications over XMPP</li>
<li>"____" ... communications over TCP</li> <li>"____" ... communications over TCP</li>
<li>"\\\\" and "////" ... communications over SOCKS 5</li> <li>"\\\\" and "////" ... communications over SOCKS5</li>
<li>"====" ... communications over the bytestream itself</li> <li>"====" ... communications over the bytestream itself</li>
</ul> </ul>
<p>In the examples, "streamer.example.com" is a Proxy that services bytestreams on port 7625.</p> <p>In the examples, "streamer.example.com" is a Proxy that services bytestreams on port 7625.</p>
@ -233,7 +238,7 @@
</query> </query>
</iq> </iq>
]]></example> ]]></example>
<p>In this case, the bytestreams proxy is hosted at "streamer.example.com".</p> <p>In this case, the "streamer.example.com" is a bytestreams proxy.</p>
<p>For each item in the disco#items result, the Requester needs to query to determine if it is a bytestreams proxy.</p> <p>For each item in the disco#items result, the Requester needs to query to determine if it is a bytestreams proxy.</p>
<example caption='Requester Sends Service Discovery Request to Proxy'><![CDATA[ <example caption='Requester Sends Service Discovery Request to Proxy'><![CDATA[
<iq from='requester@example.com/foo' <iq from='requester@example.com/foo'
@ -257,7 +262,7 @@
</query> </query>
</iq> </iq>
]]></example> ]]></example>
<p>Next the Requester needs to request the full network address to be used for bytestreaming through the Proxy. This is done by sending an IQ-get to the proxy containing a &QUERY; element qualified by the bytestreams namespace. <note>Before version 1.8 of this specification, the &QUERY; element in this use case possessed a 'sid' attribute; however, it is unnecessary for the Requester to specify the StreamID here and it would be harmful for the Proxy to reserve the StreamID at this point because the StreamID might never be used and because the Requester might use the Proxy's services for multiple different streams.</note></p> <p>Next the Requester needs to request the full network address to be used for bytestreaming through the Proxy. This is done by sending an IQ-get to the proxy containing a &QUERY; element qualified by the bytestreams namespace (not the service discovery namespace). <note>Before version 1.8 of this specification, the &QUERY; element in this use case possessed a 'sid' attribute; however, it is unnecessary for the Requester to specify the StreamID here and it would be harmful for the Proxy to reserve the StreamID at this point because the StreamID might never be used (thus forcing the Proxy to establish and maintain state about the bytestream) and because the Requester might use the Proxy's services for multiple different streams.</note></p>
<example caption='Requester Requests Network Address from Proxy'><![CDATA[ <example caption='Requester Requests Network Address from Proxy'><![CDATA[
<iq from='requester@example.com/foo' <iq from='requester@example.com/foo'
id='uj2c15z9' id='uj2c15z9'
@ -268,7 +273,7 @@
]]></example> ]]></example>
<p>The Proxy replies by returning an IQ-result that contains its network address, structured using the &lt;streamhost/&gt; child of the &QUERY; element; the &lt;streamhost/&gt; element MUST possess the following attributes:</p> <p>The Proxy replies by returning an IQ-result that contains its network address, structured using the &lt;streamhost/&gt; child of the &QUERY; element; the &lt;streamhost/&gt; element MUST possess the following attributes:</p>
<ul> <ul>
<li><cite>host</cite> = the hostname or IP address of the StreamHost for SOCKS5 communication over TCP</li> <li><cite>host</cite> = the IP address or DNS domain name of the StreamHost for SOCKS5 communication over TCP</li>
<li><cite>jid</cite> = the JabberID of the StreamHost for communication over XMPP</li> <li><cite>jid</cite> = the JabberID of the StreamHost for communication over XMPP</li>
<li><cite>port</cite> = a port associated with the hostname or IP address for SOCKS5 communication over TCP</li> <li><cite>port</cite> = a port associated with the hostname or IP address for SOCKS5 communication over TCP</li>
</ul> </ul>
@ -291,9 +296,9 @@
id='uj2c15z9' id='uj2c15z9'
to='streamer.example.com' to='streamer.example.com'
type='error'> type='error'>
<query xmlns='http://jabber.org/protocol/bytestreams'>
<error type='auth'> <error type='auth'>
<forbidden xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/> <forbidden
xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/>
</error> </error>
</iq> </iq>
]]></example> ]]></example>
@ -303,16 +308,15 @@
id='uj2c15z9' id='uj2c15z9'
to='streamer.example.com' to='streamer.example.com'
type='error'> type='error'>
<query xmlns='http://jabber.org/protocol/bytestreams'
sid='vxf9n471bn46'/>
<error type='cancel'> <error type='cancel'>
<not-allowed xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/> <not-allowed
xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/>
</error> </error>
</iq> </iq>
]]></example> ]]></example>
</section1> </section1>
<section1 topic='Direct Connections' anchor='direct'> <section1 topic='Direct Connection' anchor='direct'>
<p>In this situation, the StreamHost is the Requester, which means that the Requester knows the network address of the StreamHost and knows when to activate the bytestream.</p> <p>In this situation, the StreamHost is the Requester, which means that the Requester knows the network address of the StreamHost and knows when to activate the bytestream.</p>
<section2 topic='Process' anchor='direct-process'> <section2 topic='Process' anchor='direct-process'>
<p>For direct connections, the process for establishing a bytestream is as follows:</p> <p>For direct connections, the process for establishing a bytestream is as follows:</p>
@ -328,31 +332,31 @@
<section2 topic='Flow' anchor='direct-flow'> <section2 topic='Flow' anchor='direct-flow'>
<p>The data flow is shown in the following diagram.</p> <p>The data flow is shown in the following diagram.</p>
<code><![CDATA[ <code><![CDATA[
Requester Target Requester Target
| | | |
| Send S5B initiation request | | Send S5B initiation request |
| -------------------------------> | | -----------------------------> |
| | | |
| Open TCP socket | | Open TCP socket |
| <_______________________________ | | <_____________________________ |
| | | |
| Request SOCKS 5 connection | | Request SOCKS5 connection |
| <\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ | | <\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ |
| | | |
| Acknowledge SOCKS 5 connection | | Acknowledge SOCKS5 connection |
| ///////////////////////////////> | | /////////////////////////////> |
| | | |
| Send S5B acceptance | | Send S5B acceptance |
| <------------------------------- | | <----------------------------- |
| | | |
| Exchange data over S5B | | Exchange data over S5B |
| <==============================> | | <============================> |
| | | |
]]></code> ]]></code>
</section2> </section2>
<section2 topic='Protocol' anchor='direct-proto'> <section2 topic='Protocol' anchor='direct-proto'>
<section3 topic='Requester Initiates S5B Negotiation' anchor='direct-proto-initiate'> <section3 topic='Requester Initiates S5B Negotiation' anchor='direct-proto-initiate'>
<p>To initiate an S5B negotiation with the Target, the Requester sends the Target network address information about one or more StreamHosts. In the case of a direct connection, the Requester might include information only about itself (as shown in the following example) or about itself and a Proxy. The &QUERY; element MUST possess a 'sid' attribute the specifies the Stream ID for this bytestream and MAY possess a 'mode' attribute whose value is "tcp" (the default) or "udp"; the &QUERY; element also MUST contain one or more &lt;streamhost/&gt; elements, each of which MUST possess the 'host', 'jid', and 'port' attributes.</p> <p>To initiate an S5B negotiation with the Target, the Requester sends network address information about one or more StreamHosts to the Target. In the case of a direct connection, the Requester might include information only about itself (as shown in the following example) or about itself and a Proxy. The &QUERY; element MUST possess a 'sid' attribute the specifies the Stream ID for this bytestream and MAY possess a 'mode' attribute whose value is "tcp" (the default) or "udp" (for which see <link url='#udp'>Optional UDP Support</link>); the &QUERY; element also MUST contain one or more &lt;streamhost/&gt; elements, each of which MUST possess the 'host', 'jid', and 'port' attributes.</p>
<example caption='Requester Initiates Negotiation'><![CDATA[ <example caption='Requester Initiates Negotiation'><![CDATA[
<iq from='requester@example.com/foo' <iq from='requester@example.com/foo'
id='hu3vax16' id='hu3vax16'
@ -367,28 +371,30 @@ Requester Target
</query> </query>
</iq> </iq>
]]></example> ]]></example>
<p>If the Target is unwilling to accept the bytestream, it MUST return a &notacceptable; error to the Requester.</p> <p>If the request is malformed (e.g., the &QUERY; element does not include the 'sid' attribute), the Target MUST return an error of &badrequest;.</p>
<p>Else if the Target is unwilling to accept the bytestream, it MUST return an error of &notacceptable; to the Requester.</p>
<example caption='Target Refuses Bytestream'><![CDATA[ <example caption='Target Refuses Bytestream'><![CDATA[
<iq from='target@example.org/bar' <iq from='target@example.org/bar'
id='hu3vax16' id='hu3vax16'
to='requester@example.com/foo' to='requester@example.com/foo'
type='error'> type='error'>
<error type='auth'> <error type='auth'>
<not-acceptable xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/> <not-acceptable
xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/>
</error> </error>
</iq> </iq>
]]></example> ]]></example>
<p>If the Target is willing to negotiate a bytestream, it proceeds as shown in the following sections.</p> <p>If the Target is willing to negotiate a bytestream, it proceeds as shown in the following sections.</p>
</section3> </section3>
<section3 topic='Target Establishes SOCKS5 Connection with StreamHost/Requester' anchor='direct-proto-establish'> <section3 topic='Target Establishes SOCKS5 Connection with StreamHost/Requester' anchor='direct-proto-establish'>
<p>Next the Target attempts to open a standard TCP socket on the network address of the StreamHost/Requester.</p> <p>Next the Target attempts to open a standard TCP socket on the network address of the StreamHost/Requester (for information about UDP usage, see the <link url='#udp'>Optional UDP Support</link> section of this document).</p>
<p>Note: If the Requester provides more than one StreamHost, the Target SHOULD try to connect to them in the order of the &lt;streamhost/&gt; children within the &QUERY; element. &xep0260; modifies this rule by providing explicit priorities for each streamhost candidate.</p> <p>Note: If the Requester provides more than one StreamHost, the Target SHOULD try to connect to them in the order of the &lt;streamhost/&gt; children within the &QUERY; element. &xep0260; modifies this rule by providing explicit priorities for each streamhost candidate.</p>
<p>If the Target is able to open a TCP socket on a StreamHost/Requester, it MUST use the SOCKS5 protocol to establish a SOCKS5 connection. In accordance with <cite>RFC 1928</cite>, the Target might need to authenticate in order to use the proxy. However, any authentication required is beyond the scope of this document.</p> <p>If the Target is able to open a TCP socket on a StreamHost/Requester, it MUST use the SOCKS5 protocol to establish a SOCKS5 connection. In accordance with <cite>RFC 1928</cite>, the Target might need to authenticate in order to use the proxy. However, any authentication required is beyond the scope of this document.</p>
<p>Once the Target has successfully authenticated with the StreamHost/Requester, it sends a CONNECT request to the appropriate host in order to continue the negotiation. The following rules apply:</p> <p>Once the Target has successfully authenticated with the StreamHost/Requester, it sends a CONNECT request (CMD = X'01') in order to continue the negotiation. The following rules apply:</p>
<ol> <ol>
<li>The hostname MUST be SHA1(SID + Requester JID + Target JID) where the definition of the SHA1 hashing algorithm is as specified by &rfc3174; and the output is hexadecimal-encoded (not binary).</li> <li>The hostname MUST be SHA1(SID + Requester JID + Target JID) where the definition of the SHA1 hashing algorithm is as specified by &rfc3174; and the output is hexadecimal-encoded (not binary).</li>
<li>The port MUST be 0 (zero).</li> <li>The port MUST be 0 (zero).</li>
<li>The JIDs provided MUST be the JIDs used for the IQ exchange, which MAY be full JIDs &FULLJID; or bare JIDs &BAREJID;.</li> <li>The JIDs provided MUST be the JIDs used for the IQ exchange between the Requester and the Target, which MAY be full JIDs &FULLJID; or bare JIDs &BAREJID;.</li>
<li>The appropriate stringprep profiles (as specified in &xmppcore;) MUST be applied to the JIDs before application of the SHA1 hashing algorithm.</li> <li>The appropriate stringprep profiles (as specified in &xmppcore;) MUST be applied to the JIDs before application of the SHA1 hashing algorithm.</li>
</ol> </ol>
<example caption='Target Establishes SOCKS5 Connection with StreamHost'><![CDATA[ <example caption='Target Establishes SOCKS5 Connection with StreamHost'><![CDATA[
@ -400,7 +406,7 @@ DST.PORT = 0
<example caption='StreamHost Acknowledges Connection'><![CDATA[ <example caption='StreamHost Acknowledges Connection'><![CDATA[
STATUS = X'00' STATUS = X'00'
]]></example> ]]></example>
<p>When replying to the Target in accordance with Section 6 of <cite>RFC 1928</cite>, the StreamHost MUST set the BND.ADDR and BND.PORT to the values provided by the client in the connection request.</p> <p>When replying to the Target in accordance with Section 6 of <cite>RFC 1928</cite>, the StreamHost MUST set the BND.ADDR and BND.PORT to the DST.ADDR and DST.PORT values provided by the client in the connection request.</p>
<p>If the Target tries but is unable to connect to any of the StreamHosts and it does not wish to attempt a connection from its side, it MUST return an &notfound; error to the Requester.</p> <p>If the Target tries but is unable to connect to any of the StreamHosts and it does not wish to attempt a connection from its side, it MUST return an &notfound; error to the Requester.</p>
<example caption='Target Is Unable to Connect to Any StreamHost and Wishes to End Negotiation'><![CDATA[ <example caption='Target Is Unable to Connect to Any StreamHost and Wishes to End Negotiation'><![CDATA[
<iq from='target@example.org/bar' <iq from='target@example.org/bar'
@ -408,7 +414,8 @@ STATUS = X'00'
to='requester@example.com/foo' to='requester@example.com/foo'
type='error'> type='error'>
<error type='cancel'> <error type='cancel'>
<item-not-found xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/> <item-not-found
xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/>
</error> </error>
</iq> </iq>
]]></example> ]]></example>
@ -431,7 +438,7 @@ STATUS = X'00'
</section2> </section2>
</section1> </section1>
<section1 topic='Mediated Connections' anchor='mediated'> <section1 topic='Mediated Connection' anchor='mediated'>
<p>In this situation, the StreamHost is not the Requester but a Proxy, which means that the Requester needs to discover the network address of the StreamHost before sending the initiation request to the Target, needs to negotiate a connection with the StreamHost in the same way that the Target does, and needs to ask the StreamHost to activate the bytestream before it can be used.</p> <p>In this situation, the StreamHost is not the Requester but a Proxy, which means that the Requester needs to discover the network address of the StreamHost before sending the initiation request to the Target, needs to negotiate a connection with the StreamHost in the same way that the Target does, and needs to ask the StreamHost to activate the bytestream before it can be used.</p>
<section2 topic='Process' anchor='mediated-process'> <section2 topic='Process' anchor='mediated-process'>
<p>For mediated connections, the process for establishing a bytestream is as follows:</p> <p>For mediated connections, the process for establishing a bytestream is as follows:</p>
@ -454,46 +461,46 @@ STATUS = X'00'
<section2 topic='Flow' anchor='mediated-flow'> <section2 topic='Flow' anchor='mediated-flow'>
<p>The data flow is shown in the following diagram.</p> <p>The data flow is shown in the following diagram.</p>
<code><![CDATA[ <code><![CDATA[
Requester Proxy Target Requester Proxy Target
| | | | | |
| Send S5B initiation request | | Send S5B initiation request |
| ------------------------------------------------------------------> | | --------------------------------------------------------------> |
| | | | | |
| | Open TCP socket | | | Open TCP socket |
| | <_______________________________ | | | <_____________________________ |
| | | | |
| | Request SOCKS 5 connection | | | Request SOCKS 5 connection |
| | <\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ | | | <\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ |
| | | | |
| | Acknowledge SOCKS 5 connection | | | Acknowledge SOCKS 5 connection |
| | ///////////////////////////////> | | | /////////////////////////////> |
| | | | | |
| Send S5B acceptance | | Send S5B acceptance |
| <------------------------------------------------------------------ | | <-------------------------------------------------------------- |
| | | | | |
| Open TCP socket | | | Open TCP socket | |
| _______________________________> | | | _____________________________> | |
| | | | | |
| Request SOCKS 5 connection | | | Request SOCKS 5 connection | |
| ///////////////////////////////> | | | /////////////////////////////> | |
| | | | | |
| Acknowledge SOCKS 5 connection | | | Acknowledge SOCKS 5 connection | |
| <\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ | | | <\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ | |
| | | | | |
| Request activation | | | Request activation | |
| -------------------------------> | | | -----------------------------> | |
| | | | | |
| Acknowledge activation | | | Acknowledge activation | |
| <------------------------------- | | | <----------------------------- | |
| | | | | |
| Exchange data over S5B | | Exchange data over S5B |
| <=================================================================> | | <=============================================================> |
| | | | | |
]]></code> ]]></code>
</section2> </section2>
<section2 topic='Protocol' anchor='mediated-proto'> <section2 topic='Protocol' anchor='mediated-proto'>
<section3 topic='Requester Initiates S5B Negotiation' anchor='mediated-proto-initiate'> <section3 topic='Requester Initiates S5B Negotiation' anchor='mediated-proto-initiate'>
<p>To initiate an S5B negotiation with the Target, the Requester sends the Target network address information about one or more StreamHosts. In the case of a mediated connection, the Requester might include information only about the Proxy (as shown in the following example) or about the Proxy and itself. The &QUERY; element MUST possess a 'sid' attribute the specifies the Stream ID for this bytestream and MAY possess a 'mode' attribute whose value is "tcp" (the default) or "udp"; the &QUERY; element also MUST contain one or more &lt;streamhost/&gt; elements, each of which MUST possess the 'host', 'jid', and 'port' attributes.</p> <p>To initiate an S5B negotiation with the Target, the Requester sends network address information about one or more StreamHosts to the Target. In the case of a mediated connection, the Requester might include information only about the Proxy (as shown in the following example) or about the Proxy and itself. The &QUERY; element MUST possess a 'sid' attribute the specifies the Stream ID for this bytestream and MAY possess a 'mode' attribute whose value is "tcp" (the default) or "udp" (for which see <link url='#udp'>Optional UDP Support</link>); the &QUERY; element also MUST contain one or more &lt;streamhost/&gt; elements, each of which MUST possess the 'host', 'jid', and 'port' attributes.</p>
<example caption='Requester Initiates Negotiation'><![CDATA[ <example caption='Requester Initiates Negotiation'><![CDATA[
<iq from='requester@example.com/foo' <iq from='requester@example.com/foo'
id='npq71g53' id='npq71g53'
@ -513,12 +520,12 @@ Requester Proxy Target
<section3 topic='Target Establishes SOCKS5 Connection with Proxy' anchor='mediated-proto-establish'> <section3 topic='Target Establishes SOCKS5 Connection with Proxy' anchor='mediated-proto-establish'>
<p>Next the Target attempts to open a standard TCP socket on the network address of the Proxy.</p> <p>Next the Target attempts to open a standard TCP socket on the network address of the Proxy.</p>
<p>If the Target is able to open a TCP socket on the Proxy, it uses the SOCKS5 protocol to establish a SOCKS5 connection. In accordance with <cite>RFC 1928</cite>, the Target might need to authenticate in order to use the proxy. However, any authentication required is beyond the scope of this document.</p> <p>If the Target is able to open a TCP socket on the Proxy, it uses the SOCKS5 protocol to establish a SOCKS5 connection. In accordance with <cite>RFC 1928</cite>, the Target might need to authenticate in order to use the proxy. However, any authentication required is beyond the scope of this document.</p>
<p>Once the Target has successfully authenticated with the Proxy, it sends a CONNECT request to the appropriate host in order to continue the negotiation. The following rules apply:</p> <p>Once the Target has successfully authenticated with the Proxy, it sends a CONNECT request (CMD = X'01') in order to continue the negotiation. The following rules apply:</p>
<ol> <ol>
<li>The hostname MUST be SHA1(SID + Requester JID + Target JID) where the definition of the SHA1 hashing algorithm is as specified by &rfc3174; and the output is hexadecimal-encoded (not binary).</li> <li>The hostname MUST be SHA1(SID + Requester JID + Target JID) where the definition of the SHA1 hashing algorithm is as specified by <cite>RFC 3174</cite>; and the output is hexadecimal-encoded (not binary).</li>
<li>The port MUST be 0 (zero).</li> <li>The port MUST be 0 (zero).</li>
<li>The JIDs provided MUST be the JIDs used for the IQ exchange, which MAY be full JIDs &FULLJID; or bare JIDs &BAREJID;.</li> <li>The JIDs provided MUST be the JIDs used for the IQ exchange between the Requester and the Target, which MAY be full JIDs &FULLJID; or bare JIDs &BAREJID;.</li>
<li>The appropriate stringprep profiles (as specified in &xmppcore;) MUST be applied to the JIDs before application of the SHA1 hashing algorithm.</li> <li>The appropriate stringprep profiles (as specified in <cite>XMPP Core</cite>) MUST be applied to the JIDs before application of the SHA1 hashing algorithm.</li>
</ol> </ol>
<example caption='Target Establishes SOCKS5 Connection with StreamHost'><![CDATA[ <example caption='Target Establishes SOCKS5 Connection with StreamHost'><![CDATA[
CMD = X'01' CMD = X'01'
@ -529,7 +536,7 @@ DST.PORT = 0
<example caption='StreamHost Acknowledges Connection'><![CDATA[ <example caption='StreamHost Acknowledges Connection'><![CDATA[
STATUS = X'00' STATUS = X'00'
]]></example> ]]></example>
<p>When replying to the Target in accordance with Section 6 of <cite>RFC 1928</cite>, the Proxy MUST set the BND.ADDR and BND.PORT to the values provided by the client in the connection request.</p> <p>When replying to the Target in accordance with Section 6 of <cite>RFC 1928</cite>, the Proxy MUST set the BND.ADDR and BND.PORT to the DST.ADDR and DST.PORT values provided by the client in the connection request.</p>
</section3> </section3>
<section3 topic='Target Acknowledges Bytestream' anchor='mediated-proto-ack'> <section3 topic='Target Acknowledges Bytestream' anchor='mediated-proto-ack'>
<p>After the Target has established a SOCKS5 connection with the Proxy, it replies to the initiate request with an IQ-result whose &QUERY; element contains a &lt;streamhost-used/&gt; child that specifies which StreamHost was used (in this case, the Proxy).</p> <p>After the Target has established a SOCKS5 connection with the Proxy, it replies to the initiate request with an IQ-result whose &QUERY; element contains a &lt;streamhost-used/&gt; child that specifies which StreamHost was used (in this case, the Proxy).</p>
@ -559,7 +566,7 @@ STATUS = X'00'
]]></example> ]]></example>
</section3> </section3>
<section3 topic='Activation of Bytestream' anchor='mediated-proto-activation'> <section3 topic='Activation of Bytestream' anchor='mediated-proto-activation'>
<p>Next the Requester needs to activate the bytestream with the Proxy. This is done by sending an IQ-set to the Proxy, including an &lt;activate/&gt; element whose XML character data specifies the full JID of the Target.</p> <p>Next the Requester needs to activate the bytestream with the Proxy. This is done by sending an IQ-set to the Proxy, including an &lt;activate/&gt; element whose XML character data specifies the full or bare JID of the Target.</p>
<example caption='Requester Requests Activation of Bytestream'><![CDATA[ <example caption='Requester Requests Activation of Bytestream'><![CDATA[
<iq from='requester@example.com/foo' <iq from='requester@example.com/foo'
id='oqx6t1c9' id='oqx6t1c9'
@ -571,7 +578,7 @@ STATUS = X'00'
</query> </query>
</iq> </iq>
]]></example> ]]></example>
<p>Using this information, with the SID and from address on the packet, the Proxy is able to activate the stream by hashing the SID + Requester JID + Target JID. This provides a reasonable level of trust that the activation request came from the Requester.</p> <p>Using this information, with the SID and from address on the packet, the Proxy is able to activate the stream by hashing the SID + Requester JID + Target JID and comparing the result against the DST.ADDR it has received from the Target and Receiver. Although this provides a reasonable level of trust that the activation request came from the Requester, it does not guard against active or even passive attacks against the bytestreams negotiation (see the <link url='#security'>Security Considerations</link> for information about potential hijacking of the negotiation).</p>
<p>If the Proxy can fulfill the request, it MUST respond to the Requester with an IQ-result.</p> <p>If the Proxy can fulfill the request, it MUST respond to the Requester with an IQ-result.</p>
<example caption='Proxy Informs Requester of Activation'><![CDATA[ <example caption='Proxy Informs Requester of Activation'><![CDATA[
<iq from='streamer.example.com' <iq from='streamer.example.com'
@ -582,37 +589,50 @@ STATUS = X'00'
<p>At this point the parties can begin exchanging data over the bytestream.</p> <p>At this point the parties can begin exchanging data over the bytestream.</p>
<p>If the Proxy cannot fulfill the request, it MUST return an IQ-error to the Requester; the following conditions are defined:</p> <p>If the Proxy cannot fulfill the request, it MUST return an IQ-error to the Requester; the following conditions are defined:</p>
<ul> <ul>
<li>&notfound; error if the 'from' address does not match that of the Requester's full JID</li> <li>&notfound; if the 'from' address does not match that of the Requester's full JID</li>
<li>&notallowed; error if only one party (either Requester or Recipient, but not both) is connected to the Proxy</li> <li>&notallowed; if only one party (either Requester or Recipient, but not both) is connected to the Proxy</li>
<li>&internalserver; error if the proxy cannot activate the bytestream because of some internal malfunction</li> <li>&notauthorized; if the hashes do not match</li>
<li>&internalserver; if the proxy cannot activate the bytestream because of some internal malfunction</li>
</ul> </ul>
</section3> </section3>
</section2> </section2>
</section1> </section1>
<section1 topic='Formal Description' anchor='desc'> <section1 topic='Use with Multi-User Chart' anchor='muc'>
<section2 topic='&lt;query/&gt; Element' anchor='desc-query'> <p>When one occupant of a &xep0045; conference sends an S5B invitation to another occupant, the MUC room obscures the real JID of the Target from the Requester and the real JID of the Requester from the Target. This means that the two parties do not have the same view of the information needed to calculate the DST.ADDR. To overcome this problem, the Requester SHOULD calculate the DST.ADDR based on the SID, its real JID, and the room JID (room@host/nick) of the Target, then include the calculated hash as the value of a 'dstaddr' attribute on the &QUERY; element. The Requester then sends the IQ-set to the Target's room JID because it does not know the Target's real JID.</p>
<p>The &lt;query/&gt; element is the container for all in-band communications. This element MUST be qualified by the "http://jabber.org/protocol/bytestreams" namespace. Depending on the use case, this element contains multiple &lt;streamhost/&gt; elements, a single &lt;streamhost-used/&gt; element, or a single &lt;activate/&gt; element.</p> <p>An example follows.</p>
<p>The "sid" specifies the bytestream session identifier. The value of this attribute is any character data.</p> <example caption='Requester Initiates Negotiation Through MUC Room'><![CDATA[
<p>The "mode" specifies the mode to use, either 'tcp' or 'udp'. If this attribute is missing, the default value of "tcp" MUST be assumed.</p> <iq from='requester@example.com/foo'
<p>The &lt;streamhost/&gt; element conveys the network connection information. At least one instance MUST be present in the initial IQ-set from the Requester to the Target. If multiple instances of this element are present, each one MUST be a separate host/port combination.</p> id='npq71g53'
<p>The &lt;streamhost-used/&gt; element transports the out-of-band token. It MUST be present in the IQ-set from the Target to the Requester, and there MUST be only one instance.</p> to='room@conference.example.net/Tget'
<p>The &lt;activate/&gt; element is used to request activation of a unidirectional or bidirectional bytestream. It MUST be present in the IQ-set sent from the Requester to the StreamHost after the Requester receives an IQ-result from the Target, and there MUST be only one instance.</p> type='set'>
</section2> <query xmlns='http://jabber.org/protocol/bytestreams'
<section2 topic='&lt;streamhost/&gt; Element' anchor='desc-streamhost'> dstaddr='416781edf1ae50bad01cb8509ba35b43952bc345'
<p>The &lt;streamhost/&gt; 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.</p> sid='yia72g3v49j7'>
<p>The "jid" attribute specifies the StreamHost's JID. This attribute MUST be present, and MUST be a valid JID for use with an &lt;iq/&gt;.</p> <streamhost
<p>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").</p> host='24.24.24.1'
<p>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.</p> jid='streamer.example.com'
<p>When communicating the available hosts, the Requester MUST the host and port.</p> port='7625'/>
</section2> </query>
<section2 topic='&lt;streamhost-used/&gt; Element' anchor='desc-streamhost-used'> </iq>
<p>The &lt;streamhost-used/&gt; 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.</p> ]]></example>
<p>The "jid" attribute specifies the JID of the StreamHost. This attribute MUST be present, and MUST be a valid JID for use with an &lt;iq/&gt;.</p> <p>The MUC room will then forward the IQ-set to the Target's real JID with a 'from' address of the Requester's room JID.</p>
</section2> <example caption='MUC Room Forwards Initiation Request'><![CDATA[
<section2 topic='&lt;activate/&gt; Element' anchor='desc-activate'> <iq from='room@conference.example.net/Rter'
<p>The &lt;activate/&gt; element is a flag to trigger a Proxy to complete a connection.</p> id='npq71g53'
</section2> to='target@example.org/bar'
type='set'>
<query xmlns='http://jabber.org/protocol/bytestreams'
dstaddr='416781edf1ae50bad01cb8509ba35b43952bc345'
sid='yia72g3v49j7'>
<streamhost
host='24.24.24.1'
jid='streamer.example.com'
port='7625'/>
</query>
</iq>
]]></example>
<p>Now the parties can proceed as defined for the direct or mediated connection. See the <link url='#security'>Security Considerations</link> for information about potential hijacking of the negotiation.</p>
</section1> </section1>
<section1 topic='Optional UDP Support' anchor='udp'> <section1 topic='Optional UDP Support' anchor='udp'>
@ -620,19 +640,19 @@ STATUS = X'00'
<section2 topic='Discovering UDP Support' anchor='udp-disco'> <section2 topic='Discovering UDP Support' anchor='udp-disco'>
<p>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 <cite>Service Discovery</cite> information requests.</p> <p>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 <cite>Service Discovery</cite> information requests.</p>
<example caption='Requester Sends Service Discovery Request to Target'><![CDATA[ <example caption='Requester Sends Service Discovery Request to Target'><![CDATA[
<iq type='get' <iq from='requester@example.com/foo'
from='requester@example.com/foo' id='pys51v35'
to='target@example.org/bar' to='target@example.org/bar'
id='hello2'> type='get'>
<query xmlns='http://jabber.org/protocol/disco#info'/> <query xmlns='http://jabber.org/protocol/disco#info'/>
</iq> </iq>
]]></example> ]]></example>
<p>If the Target supports UDP associations, it MUST answer to that effect in the service discovery result.</p> <p>If the Target supports UDP associations, it MUST include a feature of 'http://jabber.org/protocol/bytestreams#udp' in the service discovery result.</p>
<example caption='Target Replies to Service Discovery Request'><![CDATA[ <example caption='Target Replies to Service Discovery Request'><![CDATA[
<iq type='result' <iq from='target@example.org/bar'
from='target@example.org/bar' id='pys51v35'
to='requester@example.com/foo' to='requester@example.com/foo'
id='hello2'> type='result'>
<query xmlns='http://jabber.org/protocol/disco#info'> <query xmlns='http://jabber.org/protocol/disco#info'>
<identity <identity
category='proxy' category='proxy'
@ -647,10 +667,10 @@ STATUS = X'00'
<section2 topic='Requesting UDP Mode' anchor='udp-request'> <section2 topic='Requesting UDP Mode' anchor='udp-request'>
<p>UDP associations are requested by setting the 'mode' attribute to a value of "udp" rather than "tcp".</p> <p>UDP associations are requested by setting the 'mode' attribute to a value of "udp" rather than "tcp".</p>
<example caption='Initiation of Interaction (UDP)'><![CDATA[ <example caption='Initiation of Interaction (UDP)'><![CDATA[
<iq type='set' <iq from='requester@example.com/foo'
from='requester@example.com/foo' id='xi2d1973'
to='target@example.org/bar' to='target@example.org/bar'
id='initiate'> type='set'>
<query xmlns='http://jabber.org/protocol/bytestreams' <query xmlns='http://jabber.org/protocol/bytestreams'
mode='udp' mode='udp'
sid='mySID'> sid='mySID'>
@ -670,7 +690,7 @@ STATUS = X'00'
</ul> </ul>
<p>The processes for establishing the UDP association and for initializing the UDP channel are described below.</p> <p>The processes for establishing the UDP association and for initializing the UDP channel are described below.</p>
<section3 topic='Establishing the UDP Association' anchor='udp-process-assoc'> <section3 topic='Establishing the UDP Association' anchor='udp-process-assoc'>
<p>Once the Target has successfully authenticated with the Proxy (as described under <link url='#proto-establish'>Target Establishes SOCKS5 Connection with StreamHost</link>), it MUST send a UDP ASSOCIATE (rather than CONNECT) request to the host identified by the algorithm defined above.</p> <p>Once the Target has successfully authenticated with the Proxy over TCP (as described under <link url='#proto-establish'>Target Establishes SOCKS5 Connection with StreamHost</link>), it MUST send a UDP ASSOCIATE request (CMD = X'03') to the host identified by the algorithm defined above.</p>
<example caption='Target Requests UDP Association with StreamHost'><![CDATA[ <example caption='Target Requests UDP Association with StreamHost'><![CDATA[
CMD = X'03' CMD = X'03'
ATYP = X'03' ATYP = X'03'
@ -695,7 +715,7 @@ DATA = Target or Requester JID
<message <message
from='streamer.example.com' from='streamer.example.com'
to='target@example.org/bar' to='target@example.org/bar'
id='initiate'> id='zy3v29h6'>
<udpsuccess xmlns='http://jabber.org/protocol/bytestreams' <udpsuccess xmlns='http://jabber.org/protocol/bytestreams'
dstaddr='Value of Hash'/> dstaddr='Value of Hash'/>
</message> </message>
@ -719,15 +739,40 @@ DATA = (payload)
</section2> </section2>
</section1> </section1>
<section1 topic='Formal Description' anchor='desc'>
<section2 topic='&lt;query/&gt; Element' anchor='desc-query'>
<p>The &lt;query/&gt; element is the container for all in-band communications. This element MUST be qualified by the "http://jabber.org/protocol/bytestreams" namespace. Depending on the use case, this element contains multiple &lt;streamhost/&gt; elements, a single &lt;streamhost-used/&gt; element, or a single &lt;activate/&gt; element.</p>
<p>The 'sid' attribute specifies the bytestream session identifier. The value of this attribute is any character data.</p>
<p>The 'mode' attribute specifies the mode to use, either "tcp" or "udp". If this attribute is not included, the default value of "tcp" MUST be assumed.</p>
<p>The &lt;streamhost/&gt; element conveys the network connection information. At least one instance MUST be present in the initial IQ-set from the Requester to the Target. If multiple instances of this element are present, each one MUST be a separate host/port combination.</p>
<p>The &lt;streamhost-used/&gt; element informs the Requester about the StreamHost to which the Target has connected. It MUST be present in the IQ-set from the Target to the Requester, and there MUST be only one instance.</p>
<p>The &lt;activate/&gt; element is used to request activation of a unidirectional or bidirectional bytestream. It MUST be present in the IQ-set sent from the Requester to the Proxy after the Requester receives an IQ-result from the Target, and there MUST be only one instance.</p>
</section2>
<section2 topic='&lt;streamhost/&gt; Element' anchor='desc-streamhost'>
<p>The &lt;streamhost/&gt; 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 XML character data or child elements.</p>
<p>The "jid" attribute specifies the StreamHost's JID. This attribute MUST be present, and MUST be a valid JID for communication over XMPP.</p>
<p>The "host" attribute specifies the host to connect to. This attribute MUST be present. The value MUST be either an IPv4 or IPv6 address, or a resolvable DNS domain name.</p>
<p>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.</p>
<p>When communicating the available hosts, the Requester MUST the host and port.</p>
</section2>
<section2 topic='&lt;streamhost-used/&gt; Element' anchor='desc-streamhost-used'>
<p>The &lt;streamhost-used/&gt; element informs the Requester about the StreamHost to which the Target has connected. This element has a single attribute for the JID of the StreamHost to which the Target connected. This element MUST NOT contain any XML character data or child elements.</p>
<p>The "jid" attribute specifies the JID of the StreamHost. This attribute MUST be present, and MUST be a valid JID for communication over XMPP.</p>
</section2>
<section2 topic='&lt;activate/&gt; Element' anchor='desc-activate'>
<p>The &lt;activate/&gt; element is sent from the Requester to the Proxy in order to formally start the bytestream.</p>
</section2>
</section1>
<section1 topic='Implementation Notes' anchor='impl'> <section1 topic='Implementation Notes' anchor='impl'>
<section2 topic='StreamHost Requirements' anchor='impl-streamhost'> <section2 topic='StreamHost Requirements' anchor='impl-streamhost'>
<p>A StreamHost MUST support TCP connections.</p> <p>A StreamHost MUST support TCP connections.</p>
<p>A StreamHost SHOULD:</p> <p>A StreamHost SHOULD:</p>
<ol> <ol>
<li>Allow bi-directional bytestreaming between the Requester and Target.</li> <li>Allow bi-directional bytestreaming between the Requester and Target.</li>
<li>Allow only one Target to connect to a bytestream (i.e., disallow multicasting).</li> <li>In the absence of explicit negotiation of multicasting with the Requester (methods for which are out of scope in this document), allow only one Target to connect to a bytestream.</li>
<li>Track sessions based on a combination of the StreamID and the Requester's full JID, thus allowing an Requester to create more than one simultaneous session.</li> <li>Track sessions based on a combination of the StreamID and the Requester's full or bare JID, thus allowing a Requester to create more than one simultaneous session.</li>
<li>Ignore but not drop any bytes sent before the bytestream is activated.</li> <li>Ignore any bytes sent before the bytestream is activated.</li>
</ol> </ol>
<p>A StreamHost MAY:</p> <p>A StreamHost MAY:</p>
<ol> <ol>
@ -761,7 +806,18 @@ DATA = (payload)
</section1> </section1>
<section1 topic='Security Considerations' anchor='security'> <section1 topic='Security Considerations' anchor='security'>
<p>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.</p> <section2 topic='Confidentiality and Integrity' anchor='security-enc'>
<p>This protocol does not include a method for securing or encrypting the data sent over a SOCKS5 bytetream. 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.</p>
</section2>
<section2 topic='Session Hijacking' anchor='security-hijack'>
<p>In the absence of end-to-end encryption of the negotiation stanzas between the Requester and the Target, a passive attacker (eavesdropper) could authenticate to the bytestream before the Target, thus preventing the Target from connecting and also hijacking the data sent from the Requester.</p>
</section2>
<section2 topic='Denial of Service' anchor='security-dos'>
<p>A SOCKS5 Bytestreams Proxy can be subject to denial of service attacks (e.g., generating a large number of session requests that are never activated). A Proxy SHOULD monitor usage from particular Requesters and blacklist them if their usage is excessive.</p>
</section2>
<section2 topic='Use of SHA-1' anchor='security-sha1'>
<p>The use of the SHA-1 algorithm to hash the SID, Requester's JID, and Target's JID is not security-critical. Therefore, the known weaknesses of SHA-1 are not of significant concern in this protocol.</p>
</section2>
</section1> </section1>
<section1 topic='IANA Considerations' anchor='iana'> <section1 topic='IANA Considerations' anchor='iana'>
@ -814,8 +870,9 @@ DATA = (payload)
<xs:choice> <xs:choice>
<xs:element ref='streamhost' minOccurs='0' maxOccurs='unbounded'/> <xs:element ref='streamhost' minOccurs='0' maxOccurs='unbounded'/>
<xs:element ref='streamhost-used' minOccurs='0'/> <xs:element ref='streamhost-used' minOccurs='0'/>
<xs:element name='activate' type='empty' minOccurs='0'/> <xs:element name='activate' type='xs:string' minOccurs='0'/>
</xs:choice> </xs:choice>
<xs:attribute name='dstaddr' type='xs:string' use='optional'/>
<xs:attribute name='mode' use='optional' default='tcp'> <xs:attribute name='mode' use='optional' default='tcp'>
<xs:simpleType> <xs:simpleType>
<xs:restriction base='xs:NCName'> <xs:restriction base='xs:NCName'>