| 81 | | DNS lookup on its host's IP address and then obtains the SRV resource |
| 82 | | record associated with the host's domain name. For example, a host with |
| 83 | | IPv4 address w.x.y.z obtains the PTR record at</p> |
| 84 | | <dl class="docutils"> |
| 85 | | <dt>::</dt> |
| 86 | | <dd>z.y.x.w.in-addr.arpa</dd> |
| 87 | | </dl> |
| 88 | | <p>Assume the returned PTR record contains example.com. The client then |
| 89 | | looks up the SRV record at</p> |
| 90 | | <dl class="docutils"> |
| 91 | | <dt>::</dt> |
| 92 | | <dd>_bittorrent._tcp.example.com</dd> |
| 93 | | </dl> |
| 94 | | <p>The target field in the SRV resource record contains the domain name |
| 95 | | of the cache and the port specifies the location on that cache where |
| 96 | | the BitTorrent implementation listens.</p> |
| 97 | | <p>The SRV resource record type is described in <a class="reference external" href="http://www.faqs.org/rfcs/rfc2782.html">RFC 2782</a> <a class="footnote-reference" href="#rfc-2782" id="id1">[2]</a>. Reverse DNS |
| 98 | | lookups are described in <a class="reference external" href="http://www.faqs.org/rfcs/rfc1034.html">RFC 1034</a> <a class="footnote-reference" href="#rfc-1034" id="id2">[1]</a>.</p> |
| | 92 | DNS lookup on its external IP address and then obtains the BitTorrent |
| | 93 | SRV resource record associated with the host's domain name. For |
| | 94 | example, a host with address 69.107.0.14 obtains the PTR record at</p> |
| | 95 | <pre class="literal-block"> |
| | 96 | 14.0.107.69.in-addr.arpa |
| | 97 | </pre> |
| | 98 | <p>The client's host IP address may not match the host's IP address as |
| | 99 | seen outside the client's private network. We address this in Section |
| | 100 | <a class="reference internal" href="#network-address-translators">Network Address Translators</a>.</p> |
| | 101 | <p>The PTR resource record returned for this example contains domain name</p> |
| | 102 | <pre class="literal-block"> |
| | 103 | adsl-69-107-0-14.dsl.pltn13.pacbell.net |
| | 104 | </pre> |
| | 105 | <p>The client then looks up the SRV records at</p> |
| | 106 | <pre class="literal-block"> |
| | 107 | _bittorrent-tracker._tcp.adsl-69-107-0-14.dsl.pltn13.pacbell.net |
| | 108 | </pre> |
| | 109 | <p>If no SRV record is found, one or more subsequent queries take place as |
| | 110 | described in <a class="reference internal" href="#iterative-queries">Iterative Queries</a>.</p> |
| | 111 | <p>The target field in each returned SRV resource record contains the |
| | 112 | domain name of a tracker and the port on which the tracker runs. This |
| | 113 | tracker is called a <em>cache tracker</em>, but the protocol to talk to this |
| | 114 | tracker is no different from the standard BitTorrent tracker protocol |
| | 115 | described in <a class="footnote-reference" href="#bep-3" id="id1">[1]</a>.</p> |
| | 116 | <p>When the BitTorrent client joins a swarm it announces to one or more |
| | 117 | of the trackers referenced in the .torrent file and announces to the |
| | 118 | cache tracker. The cache tracker returns peers which may be caches or |
| | 119 | other peers that announced the same file to the cache tracker.</p> |
| | 120 | <p>A cache is a BitTorrent peer. A client MAY treat it preferentially.</p> |
| | 121 | <p>Reverse DNS lookups are described in <a class="reference external" href="http://www.faqs.org/rfcs/rfc1034.html">RFC 1034</a> <a class="footnote-reference" href="#rfc-1034" id="id2">[4]</a>. |
| | 122 | The SRV resource record type is described in <a class="reference external" href="http://www.faqs.org/rfcs/rfc2782.html">RFC 2782</a> <a class="footnote-reference" href="#rfc-2782" id="id3">[5]</a>.</p> |
| | 123 | </div> |
| | 124 | <div class="section" id="iterative-queries"> |
| | 125 | <h1>Iterative Queries</h1> |
| | 126 | <p>The domain name returned from the reverse DNS lookup is specific to |
| | 127 | the querying host. In the naive implementation in DNS, there would be |
| | 128 | one SRV resource record for every querying host. The most obvious |
| | 129 | solution is to use a wildcard of the form:</p> |
| | 130 | <pre class="literal-block"> |
| | 131 | *.pacbell.net |
| | 132 | </pre> |
| | 133 | <p>However, if wildcards are implemented according to the algorithm in |
| | 134 | section 4.3.2 in <a class="footnote-reference" href="#rfc-1034" id="id4">[4]</a> then all subdomains of pacbell.net that |
| | 135 | do not have an exact label match will match the wildcard. Thus,</p> |
| | 136 | <pre class="literal-block"> |
| | 137 | _jabber._tcp.pacbell.net |
| | 138 | </pre> |
| | 139 | <p>and</p> |
| | 140 | <pre class="literal-block"> |
| | 141 | _bittorrent-tracker._tcp.pacbell.net |
| | 142 | </pre> |
| | 143 | <p>both match *.pacbell.net and all SRV resource records with owner |
| | 144 | *.pacbell.net would be returned with the name set to the name in the |
| | 145 | query. Thus it would be impossible to disambiguate Jabber from |
| | 146 | BitTorrent SRV records without further information. This behavior is |
| | 147 | implemented with BIND 9.4.1.</p> |
| | 148 | <p>The natural solution would be to specify domain names of the type</p> |
| | 149 | <pre class="literal-block"> |
| | 150 | _bittorrent-tracker._tcp.*.pacbell.net |
| | 151 | </pre> |
| | 152 | <p>However, section 4.3.3 in <a class="footnote-reference" href="#rfc-1034" id="id5">[4]</a> specifies that wildcards only |
| | 153 | appear as the first label in a domain name. This restriction was |
| | 154 | lifted in <a class="footnote-reference" href="#rfc-4592" id="id6">[6]</a>, but not with semantics applicable to our use |
| | 155 | case. An asterisk not at the beginning of a domain name is not |
| | 156 | treated like a wildcard. Only a lookup for the exact domain name</p> |
| | 157 | <pre class="literal-block"> |
| | 158 | _bittorrent-tracker._tcp.*.pacbell.net |
| | 159 | </pre> |
| | 160 | <p>matches.</p> |
| | 161 | <p>We propose an alternative that avoids wildcards and has the advantage |
| | 162 | that it allows suborganizations to override the SRV records provided |
| | 163 | by parent organizations: the peer starts by querying using its |
| | 164 | fully-qualified domain name returned from the reverse DNS lookup, and |
| | 165 | if this fails then it queries again after removing the most specific |
| | 166 | (leftmost) label in the domain name. For example, if no SRV records |
| | 167 | are returned when querying for</p> |
| | 168 | <pre class="literal-block"> |
| | 169 | _bittorrent-tracker._tcp.adsl-69-107-0-14.dsl.pltn13.pacbell.net |
| | 170 | </pre> |
| | 171 | <p>then the client queries for</p> |
| | 172 | <pre class="literal-block"> |
| | 173 | _bittorrent-tracker.dsl.pltn13.pacbell.net |
| | 174 | </pre> |
| | 175 | <p>and then</p> |
| | 176 | <pre class="literal-block"> |
| | 177 | _bittorrent-tracker.pltn13.pacbell.net |
| | 178 | </pre> |
| | 179 | <p>The search removes one domain at a time terminating when one or more |
| | 180 | resource records are found or before querying the root domain or |
| | 181 | top-level domains that are not ccTLDs, e.g., .com, .org, .net. We |
| | 182 | avoid querying the root or global top-level domains given the low |
| | 183 | likelihood that caches would be defined globally, and thus clients |
| | 184 | would unnecessarily burden the root domain name servers with queries |
| | 185 | generating negative results. We considered stopping before querying |
| | 186 | country-level domains, but a country providing public infrastructure |
| | 187 | might choose to provide caches.</p> |
| 104 | | an IP address allocated from one of the three private IP address |
| 105 | | ranges defined by IANA, i.e., 10.*.*.*, 172.*.*.*, or 192.*.*.*. When |
| 106 | | communicating with hosts outside the private network, the NAT |
| 107 | | translates the private IP to an IP address that is globally routable. |
| 108 | | This globally routable address is the host's <em>public IP address</em>.</p> |
| 109 | | <p>When finding a cache, the BitTorrent client must use its host's public |
| 110 | | IP address. A BitTorrent client can obtain its host's public IP by |
| 111 | | either querying the tracker and looking at the value to the returned |
| 112 | | <em>external ip</em> key <a class="footnote-reference" href="#bep-24" id="id3">[4]</a> or from other peers using the <em>yourip</em> |
| 113 | | extension defined for the <em>Extension Protocol</em> proposed in <a class="footnote-reference" href="#bep-10" id="id4">[3]</a>.</p> |
| | 193 | an IP address allocated from one of the private IP address ranges |
| | 194 | defined by IANA, e.g., ranges with prefixes 10/8, 172.16/12, and |
| | 195 | 192.168/16. When communicating with hosts outside the private |
| | 196 | network, the NAT translates the private IP to a globally-routable IP |
| | 197 | address. This globally-routable address is the host's <em>external IP |
| | 198 | address</em>.</p> |
| | 199 | <p>When finding a cache, the BitTorrent client must use its host's |
| | 200 | external IP address. A BitTorrent client can obtain its host's |
| | 201 | external IP either from the <em>external ip</em> key returned from a tracker |
| | 202 | implementing BEP 24 <a class="footnote-reference" href="#bep-24" id="id7">[3]</a> or from peers using the <em>yourip</em> |
| | 203 | extension defined for the <em>Extension Protocol</em> proposed in <a class="footnote-reference" href="#bep-10" id="id8">[2]</a>.</p> |
| | 204 | </div> |
| | 205 | <div class="section" id="example"> |
| | 206 | <h1>Example</h1> |
| | 207 | <p>In our example, we used AT&T's PacBell network. AT&T could implement |
| | 208 | cache discovery by adding the following lines to the zone file for |
| | 209 | pacbell.net,</p> |
| | 210 | <pre class="literal-block"> |
| | 211 | ; name ttl cls rr pri weight port target |
| | 212 | _bittorrent-tracker._tcp.pacbell.net. 600 IN SRV 5 0 6969 tracker |
| | 213 | </pre> |
| | 214 | <p>Now when a client performs cache discovery, it performs three DNS |
| | 215 | queries removing labels before reaching the domain name pacbell.net, |
| | 216 | at which point the SRV record would be returned and the client would |
| | 217 | then query tracker.pacbell.net to obtain caches.</p> |
| | 218 | <p>In Python, the cache tracker's port and domain can be obtained using |
| | 219 | PyDNS using the following code:</p> |
| | 220 | <pre class="literal-block"> |
| | 221 | import DNS |
| | 222 | |
| | 223 | tlds = ["com", "net", "org"] # add more TLDs here. |
| | 224 | |
| | 225 | name = DNS.revlookup( "69.107.0.14" ) |
| | 226 | names = name.split('.') |
| | 227 | while names and names[0] not in tlds: |
| | 228 | name = "_bittorrent._tcp." + ".".join(names) |
| | 229 | req = DNS.Request( name=name, qtype="SRV", protocol="udp") |
| | 230 | response = req.req() |
| | 231 | if response.answers: |
| | 232 | break |
| | 233 | del names[0] |
| | 234 | |
| | 235 | print "response=", response.show() |
| | 236 | </pre> |
| | 237 | <p>which might generate output like</p> |
| | 238 | <pre class="literal-block"> |
| | 239 | response= ; <<>> PDG.py 1.0 <<>> _bittorrent._tcp.pacbell.net SRV |
| | 240 | ;; options: recurs |
| | 241 | ;; got answer: |
| | 242 | ;; ->>HEADER<<- opcode 0, status NOERROR, id 0 |
| | 243 | ;; flags: qr aa rd ra; Ques: 1, Ans: 1, Auth: 2, Addit: 3 |
| | 244 | ;; QUESTIONS: |
| | 245 | ;; _bittorrent._tcp.pacbell.net, type = SRV, class = IN |
| | 246 | |
| | 247 | ;; ANSWERS: |
| | 248 | _bittorrent._tcp.pacbell.net 600 SRV (5, 0, 6969, 'cache.pacbell.net') |
| | 249 | |
| | 250 | ;; AUTHORITY RECORDS: |
| | 251 | pacbell.net 86400 NS ns1.pbi.net |
| | 252 | pacbell.net 86400 NS ns2.pbi.net |
| | 253 | |
| | 254 | ;; ADDITIONAL RECORDS: |
| | 255 | cache.pacbell.net 86400 A 69.107.0.1 |
| | 256 | ns1.pacbell.net 86400 A 206.13.28.11 |
| | 257 | ns2.pacbell.net 86400 A 206.13.29.11 |
| | 258 | |
| | 259 | ;; Total query time: 0 msec |
| | 260 | ;; To SERVER: localhost |
| | 261 | ;; WHEN: Mon May 19 16:00:12 2008 |
| | 262 | </pre> |
| | 263 | <p>The answer above is fictional since AT&T does not at this time |
| | 264 | implement SRV records for BitTorrent trackers.</p> |
| | 265 | <p>In Microsoft Windows, the port and domain name of the server can be |
| | 266 | obtained using WinDNS (Dnsapi.lib) using DnsQuery(). In Unix, the |
| | 267 | relevant call is res_query() from libresolv.</p> |