Skip to content Skip to sidebar Skip to footer

How To Interpret 'nodes' In A DHT Response?

I'm reading through BEP-0005 and I don't really understand how the node IDs translate to (IP, port) pairs. Consider the following code: import bencode import random import socket i

Solution 1:

http://www.bittorrent.org/beps/bep_0005.html#contact-encoding

Contact Encoding

Contact information for peers is encoded as a 6-byte string. Also known as "Compact IP-address/port info" the 4-byte IP address is in network byte order with the 2 byte port in network byte order concatenated onto the end.

Contact information for nodes is encoded as a 26-byte string. Also known as "Compact node info" the 20-byte Node ID in network byte order has the compact IP-address/port info concatenated to the end.


Solution 2:

It looks like the problem was related to endianness of the port number - changing struct.unpack("H", to `struct.unpack(">H", helped. Here's a working sample:

#!/usr/bin/env python

import bencode
import random
import socket
import sys
import ast
import struct

rand = lambda: ''.join([chr(random.randint(0, 255)) for _ in range(20)])
my_id = rand()

def query(ip, port):
    print("Trying %s:%d" % (ip, port))
    get_peers = {"t":'0f', "y":"q", "q":"get_peers",
        "a": {"id":my_id,
              "info_hash": '\xd9\x9d\x14\x8c\xf7\xb5\xee'
                           '\x84</\x806\xd6d\x13\xb3\xe3\x0f\x1b\xe7'}
    }
    get_peers_bencoded = bencode.bencode(get_peers)

    s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    s.sendto(get_peers_bencoded, (ip, port))
    s.settimeout(0.5)
    try:
        r = s.recvfrom(1024)
    except socket.timeout:
        return []
    response = bencode.bdecode(r[0])

    if 'values' in response['r']:
        print(response)
        sys.exit()

    ret = []
    for i in range(0, len(response['r']['nodes']), 26):
        s = response['r']['nodes'][i:i+26]
        ip = socket.inet_ntop(socket.AF_INET, s[-6:][:4])
        port = struct.unpack(">H", s[-2:])[0]
        ret += [(ip, port)]
    print("Got %d nodes." % len(ret))
    return ret

if __name__ == '__main__':
    ips = [(socket.gethostbyname('router.bittorrent.com'), 6881)]
    while True:
        node = ips.pop()
        ip, port = node[0], node[1]
        ips += query(ip, port)

Post a Comment for "How To Interpret 'nodes' In A DHT Response?"