2

I'm writing a dht server and meet some problem. I send the find_node request to bootstraps, and they return me some compact node info(416bytes) which contains 16 nodes info then i bdecode and store the ip address and port, continue send find_node request to these nodes,but i get no response.

Server code here(receive packet and start a new thread to add nodes to a list)

public void run() {

    try {
        while (true) {
            byte[] buffer_rcv = new byte[1024];
            DatagramPacket recvPacket = new DatagramPacket(buffer_rcv, buffer_rcv.length);
            socket.receive(recvPacket);
            System.out.println("get!!!");

            new Thread(new Runnable() {

                @Override
                public void run() {
                    // TODO Auto-generated method stub
                    try {
                        LinkedList<Node> nodes = BDecode.bdecode_find_node(recvPacket);
                        for (Node n : nodes) {
                            table.add_node(n);
                        }

                        System.out.println("table size" + table.get_all_nodes().size());

                    } catch (IOException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }

                }

            }).start();
            System.out.println("waiting new packet!!!!!!!");
        }
    } catch (IOException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }

}

I download the jbittorrent api from sourceforge and use it to bdecode

public static LinkedList<Node> bdecode_find_node(DatagramPacket recvPacket) throws IOException {

    byte[]nodes_compact_info = (byte[]) ((Map) new BDecoder().decodeByteArray(recvPacket.getData()).get("r")).get("nodes");

    byte[]node_info = new byte[26];
    byte[]node_id = new byte[20];
    byte[]ip_byte = new byte[4];
    byte[]port_byte = new byte[2];
    int port;


    LinkedList<Node> nodes = new LinkedList<>();
    //System.out.println("nodes_compact_info.length"+nodes_compact_info.length);
    for (int i = 0;i<nodes_compact_info.length/26;i++) { //416 = 16 * 26byte_per_node 
        //0-19 id 20 21 22 23 ip 24 25 port

        node_info = Utils.subArray(nodes_compact_info, i*26, 26);           
        node_id=Utils.subArray(node_info, 0, 20);           
        ip_byte = Utils.subArray(node_info, 20, 4); 

        String ip = "";
        for (int j = 0;j<ip_byte.length;j++) {
            ip+=Utils.byteToUnsignedInt(node_info[j]);
            ip+=".";
        }
        ip = ip.substring(0, ip.length()-1);
        //System.out.println(ip);
        port_byte = Utils.subArray(node_info, 24, 2);
        port = Utils.byteArrayToInt(port_byte);

        nodes.add(new Node(node_id, ip, port, new Date()));         
    }
    return nodes;
}

Finally i send find_node request to every node in list

public void get_neighbor() {

    ArrayList<Node> nodes = table.get_all_nodes();
    System.out.println("*********get_neighbor!!!");

    for (Node n : nodes) {
        try {

            byte[] find_node_query = BEncode.find_node(this.id, this.id);
            DatagramPacket sendPacket = new DatagramPacket(find_node_query, find_node_query.length,
                    InetAddress.getByName(n.getIp()), n.getPort());
            for (int i = 0;i<5;i++)
                socket.send(sendPacket);
            System.out.println("packet send to " + n.getIp() + ":" + n.getPort());
        } catch (UnknownHostException e1) {
            // TODO Auto-generated catch block
            System.out.println("UnknownHostException" + n.getIp());
        } catch (IOException e) {
            // TODO Auto-generated catch block
            System.out.println("cant send packet");
        }
    }
}

i have stuck there for some days, and try a lot of ways to find where go wrong, help me please.

node compact info

this is returned from bootstrap and after bdecoding node compact info

capture

send find_node to bootstrap

response from bootstrap

udp packet to node

.pcap file

ahcha.Z
  • 23
  • 4
  • 1
    Can you post a .pcap (wireshark capture) of the bootstrap find_node, the response and the get neighbor attempts? – the8472 May 15 '18 at 16:38
  • hi and thanks, do i need NAT Traversal? i'm in school wlan@the8472 – ahcha.Z May 17 '18 at 09:24
  • I meant the pcap file itself, not screenshots. And if the message to a bootstrap node gets a reply then you probably don't need additional NAT traversal measures to contact other nodes. – the8472 May 17 '18 at 18:41
  • how to send the file to you ? and I found that the protocol of find_node packet i sent to node is UDP but not bt-dht in wireshark, that maybe the problem...altually i implement bencode the packet by hardcoding, like "d1:t2:" + tid + "1:y1:r1:rd2:id20:5:nodes0:5:token5:" , than turn the string to bytes and send – ahcha.Z May 19 '18 at 15:52
  • I just found something. I fix the socket on port 6881, but when i send the packet, the port changes, – ahcha.Z May 19 '18 at 16:31
  • put it up on some file hoster and update your question with a link to it. – the8472 May 19 '18 at 17:24
  • thankyou for your patience, I have uploaded the file, plz check – ahcha.Z May 20 '18 at 01:52

2 Answers2

0

I just found something. I fix the socket on port 6881, but when i send the packet, the port changes

Yes, this is one issue. You should bind a single UDP socket and then keep reusing that socket. As per BEP 45 it should also be bound to a specific address.

.pcap file

Packet #2, the response from the bootstrap node contains 16 contacts. The first contact is id: 0f9c86a1085677f9f1edb519bfc16b626f19fb11, IPv4/Port: 92.255.216.47:29501

Packet #18 tries to contact 47.216.255.92:29501

So you are swapping bytes when decoding the IP address. Contacts are encoded in network byte order, i.e. big endian.

You don't need to use string processing for that, InetAddress.getByAddress has an overload that takes byte arrays

the8472
  • 40,999
  • 5
  • 70
  • 122
  • Thank you so much! i have modified the code. now i get some announce_peer requests, do you know some API take the infohash as parameter and return the magedata?I want to build an index map the keyword about file to the magnet link – ahcha.Z May 28 '18 at 02:35
0

I see some issues by looking at these four packets from the .pcap file

110 48.444854   10.3.157.234    82.221.103.244  BT-DHT  134 
...
113 48.844328   82.221.103.244  10.3.157.234    BT-DHT  528 reply=16 nodes 
114 48.911670   10.3.157.234    47.152.12.43    BT-DHT  134 
115 48.912589   10.3.157.234    181.39.146.92   BT-DHT  134 

This is the find_node request sent to the bootstrap node: router.utorrent.com [82.221.103.244]

Frame 110: 134 bytes on wire (1072 bits), 134 bytes captured (1072 bits)
Ethernet II, Src: IntelCor_1d:89:36 (5c:e0:c5:1d:89:36), Dst: Hangzhou_bf:8e:b0 (d4:61:fe:bf:8e:b0)
Internet Protocol Version 4, Src: 10.3.157.234, Dst: 82.221.103.244
User Datagram Protocol, Src Port: 6883, Dst Port: 6881
BitTorrent DHT Protocol
    Transaction ID: 7473
        Key: t
        Value: 7473
    Message type: Request
        Key: y
        Value: q
    Request type: find_node
        Key: q
        Value: find_node
    Request arguments: Dictionary...
        Key: a
        Value: Dictionary...
            id: ef417ba2c490541a8981d7905036c814364750a6
                Key: id
                Value: ef417ba2c490541a8981d7905036c814364750a6
            target: ef417ba2c490541a8981d7905036c814364750a6
                Key: target
                Value: ef417ba2c490541a8981d7905036c814364750a6

The node sent both id and target set to the value: ef417ba2c490541a8981d7905036c814364750a6 so this should be its node_id.
This has an minor issue, as the keys in a bencoded dictionary must be sorted, but most implementations will accept the request anyway.
d1:t2:ts1:y1:q1:q9:find_node1:ad2:id20:.A....T.....P6..6GP.6:target20:.A....T.....P6..6GP.ee
should be:
d1:ad2:id20:.A....T.....P6..6GP.6:target20:.A....T.....P6..6GP.e1:q9:find_node1:t2:ts1:y1:qe


This is the response from the bootstrap node:

Frame 113: 528 bytes on wire (4224 bits), 528 bytes captured (4224 bits)
Ethernet II, Src: Hangzhou_bf:8e:b0 (d4:61:fe:bf:8e:b0), Dst: IntelCor_1d:89:36 (5c:e0:c5:1d:89:36)
Internet Protocol Version 4, Src: 82.221.103.244, Dst: 10.3.157.234
User Datagram Protocol, Src Port: 6881, Dst Port: 6883
BitTorrent DHT Protocol
    ip: def983017ed6
        Key: ip
        Value: def983017ed6
    Response values: Dictionary...
        Key: r
        Value: Dictionary...
            id: ebff36697351ff4aec29cdbaabf2fbe3467cc267
                Key: id
                Value: ebff36697351ff4aec29cdbaabf2fbe3467cc267
            nodes: 16
                Key: nodes
                Value: 16 nodes
                Node 1 (id: 2f980c2befa8ae85856bfabd44fb76137c50e39e, IP/Port: 184.148.185.216:43611)
                Node 2 (id: b527925cd9b0f4610904dd2d75aa8c5aa6c900e3, IP/Port: 201.92.140.89:63505)
                Node 3 (id: 454d423032343241433131303030325858587a63, IP/Port: 119.136.154.198:23493)
                Node 4 (id: 4dbe732bad993048936a71ae2c7be49dc9ab24f9, IP/Port: 27.209.68.82:16001)
                Node 5 (id: 39a36bc7f75c494b90395113ab2fd5833c6d684c, IP/Port: 171.239.30.38:1035)
                Node 6 (id: a5ac55cdfdf231bf35e4e68e3b89b5430f0eedd7, IP/Port: 109.154.41.107:58580)
                Node 7 (id: 8f05d55f2129e53c4a1f87b13199b598c479b0aa, IP/Port: 189.78.63.188:27070)
                Node 8 (id: d1bd0a25de085c18d8c45c60f681f7074b9e0458, IP/Port: 95.81.104.30:27196)
                Node 9 (id: 30f0086f8618d7aa5a53b8ac0e3d5b080351fb9a, IP/Port: 70.118.138.155:26085)
                Node 10 (id: dd4797facea363d908b629ce93183c241f08f478, IP/Port: 189.83.128.160:45381)
                Node 11 (id: 0801a40c0e72581bc76e00262350243fc38d21af, IP/Port: 218.210.40.82:31021)
                Node 12 (id: cacf92f943a69abcc24891919d80953b3e70526d, IP/Port: 120.148.25.109:59348)
                Node 13 (id: 3f3834ab54f4215248f0f47d0d0265317d320b48, IP/Port: 189.62.200.109:49307)
                Node 14 (id: fd81b802855925bee2b2ed89134788babe2328bb, IP/Port: 189.152.39.89:43529)
                Node 15 (id: cef348726b9c1278675db1b1da4b605016aab4f8, IP/Port: 189.163.183.249:49937)
                Node 16 (id: 96f24f9a50ee407836fd124932f69e7d49dcad32, IP/Port: 178.77.35.128:34304)
    Transaction ID: 7473
        Key: t
        Value: 7473
    Message type: Response
        Key: y
        Value: r

A list with 16 nodes.


This is the find_node request sent to the first node in the list:
Node 1 (id: 2f980c2befa8ae85856bfabd44fb76137c50e39e, IP/Port: 184.148.185.216:43611)

Frame 114: 134 bytes on wire (1072 bits), 134 bytes captured (1072 bits)
Ethernet II, Src: IntelCor_1d:89:36 (5c:e0:c5:1d:89:36), Dst: Hangzhou_bf:8e:b0 (d4:61:fe:bf:8e:b0)
Internet Protocol Version 4, Src: 10.3.157.234, Dst: 47.152.12.43
User Datagram Protocol, Src Port: 6883, Dst Port: 43611
BitTorrent DHT Protocol
    Transaction ID: 6476
        Key: t
        Value: 6476
    Message type: Request
        Key: y
        Value: q
    Request type: find_node
        Key: q
        Value: find_node
    Request arguments: Dictionary...
        Key: a
        Value: Dictionary...
            id: 2f980c2befa8ae85856bfabd44fb7614364750a6
                Key: id
                Value: 2f980c2befa8ae85856bfabd44fb7614364750a6
            target: ef417ba2c490541a8981d7905036c814364750a6
                Key: target
                Value: ef417ba2c490541a8981d7905036c814364750a6

Here are more issues: The port and target is correct,
but id is wrong. It's queried nodes id =2f980c2befa8ae85856bfabd44fb7614364750a6
instead of querying nodes id =ef417ba2c490541a8981d7905036c814364750a6 as it should be.
Nodes will likely not respond to 'id thieves'.
IP is also wrong, instead of 184.148.185.216 it's 47.152.12.43 = 0x2f980c2b which is the four first bytes in queried nodes id. Sending to wrong IP is of course a fatal issue.
The bencoded keys are unsorted.


This is the find_node request sent to the second node in the list:
Node 2 (id: b527925cd9b0f4610904dd2d75aa8c5aa6c900e3, IP/Port: 201.92.140.89:63505)

Frame 115: 134 bytes on wire (1072 bits), 134 bytes captured (1072 bits)
Ethernet II, Src: IntelCor_1d:89:36 (5c:e0:c5:1d:89:36), Dst: Hangzhou_bf:8e:b0 (d4:61:fe:bf:8e:b0)
Internet Protocol Version 4, Src: 10.3.157.234, Dst: 181.39.146.92
User Datagram Protocol, Src Port: 6883, Dst Port: 63505
BitTorrent DHT Protocol
    Transaction ID: 6f69
        Key: t
        Value: 6f69
    Message type: Request
        Key: y
        Value: q
    Request type: find_node
        Key: q
        Value: find_node
    Request arguments: Dictionary...
        Key: a
        Value: Dictionary...
            id: b527925cd9b0f4610904dd2d75aa8c14364750a6
                Key: id
                Value: b527925cd9b0f4610904dd2d75aa8c14364750a6
            target: ef417ba2c490541a8981d7905036c814364750a6
                Key: target
                Value: ef417ba2c490541a8981d7905036c814364750a6

Has the same issues as the first node. All the following requests has the same issues.

Encombe
  • 2,003
  • 1
  • 17
  • 26
  • Cool man!Thank you for helping me find some mistakes in my code.I just got some announce_peer requests, do you know some API take the infohash as parameter and return the magedata?I want to build an index map the keyword about file to the magnet link – ahcha.Z May 28 '18 at 02:33
  • There is no easy way to get the metadata from the infohash, other than using a almost fullly functional bittorrent client or using a online service, See: https://stackoverflow.com/questions/48873300/how-to-create-torrent-file-from-magnet-link-using-java/48873710#48873710 – Encombe May 28 '18 at 05:01