├── .ocp-indent ├── .gitignore ├── lib_test ├── dune └── find_ih.ml ├── dht ├── dune ├── Makefile ├── LICENCE ├── dht.h ├── CHANGES ├── README ├── dht-example.c └── dht.c ├── descr ├── lib ├── dune ├── dht.ml ├── dht.mli └── dht_stubs.c ├── dune-project ├── CHANGES ├── Makefile ├── dht.opam ├── README.md └── LICENCE /.ocp-indent: -------------------------------------------------------------------------------- 1 | match_clause=4 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | _build 2 | *.install 3 | .merlin 4 | -------------------------------------------------------------------------------- /lib_test/dune: -------------------------------------------------------------------------------- 1 | (executable 2 | (name find_ih) 3 | (libraries dht)) 4 | -------------------------------------------------------------------------------- /dht/dune: -------------------------------------------------------------------------------- 1 | (foreign_library 2 | (archive_name dht) 3 | (language c) 4 | (names dht)) 5 | -------------------------------------------------------------------------------- /descr: -------------------------------------------------------------------------------- 1 | OCaml bindings for Juliusz Chroboczek's dht C library 2 | found at 3 | -------------------------------------------------------------------------------- /lib/dune: -------------------------------------------------------------------------------- 1 | (library 2 | (public_name dht) 3 | (libraries unix) 4 | (foreign_archives ../dht/dht) 5 | (foreign_stubs 6 | (language c) 7 | (include_dirs ../dht) 8 | (names dht_stubs))) 9 | -------------------------------------------------------------------------------- /dht/Makefile: -------------------------------------------------------------------------------- 1 | CFLAGS = -g -Wall 2 | LDLIBS = -lcrypt 3 | 4 | dht-example: dht-example.o dht.o 5 | 6 | all: dht-example 7 | 8 | clean: 9 | -rm -f dht-example dht-example.o dht-example.id dht.o *~ core 10 | -------------------------------------------------------------------------------- /dune-project: -------------------------------------------------------------------------------- 1 | (lang dune 2.5) 2 | 3 | (name dht) 4 | 5 | (generate_opam_files true) 6 | 7 | (license MIT) 8 | (authors Nicolas Ojeda Bar ) 9 | (maintainers Nicolas Ojeda Bar ) 10 | (source (github nojb/ocaml-dht)) 11 | 12 | (package (name dht)) 13 | -------------------------------------------------------------------------------- /CHANGES: -------------------------------------------------------------------------------- 1 | 0.2.0 (6 Dec 2015, Paris) 2 | ------------------------- 3 | 4 | * Remove pure OCaml implementation and switch to 5 | bindings for Juliusz Chroboczek's dht C library 6 | found at . 7 | * Remove OASIS, switch to Makefile/ocamlfind 8 | * Rewrite lib_test/find_ih 9 | 10 | 0.1.0 11 | ----- 12 | 13 | * Initial release 14 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | .PHONY: update_upstream 2 | update_upstream: 3 | rm -rf dht 4 | git clone https://github.com/jech/dht dht 5 | rm -rf dht/.git 6 | 7 | .PHONY: gh-pages 8 | gh-pages: doc 9 | git clone `git config --get remote.origin.url` .gh-pages --reference . 10 | git -C .gh-pages checkout --orphan gh-pages 11 | git -C .gh-pages reset 12 | git -C .gh-pages clean -dxf 13 | cp $(DOC_DIR)* .gh-pages/ 14 | git -C .gh-pages add . 15 | git -C .gh-pages commit -m "Update Pages" 16 | git -C .gh-pages push origin gh-pages -f 17 | rm -rf .gh-pages 18 | -------------------------------------------------------------------------------- /dht.opam: -------------------------------------------------------------------------------- 1 | # This file is generated by dune, edit dune-project instead 2 | opam-version: "2.0" 3 | maintainer: ["Nicolas" "Ojeda" "Bar" ""] 4 | authors: ["Nicolas" "Ojeda" "Bar" ""] 5 | license: "MIT" 6 | homepage: "https://github.com/nojb/ocaml-dht" 7 | bug-reports: "https://github.com/nojb/ocaml-dht/issues" 8 | depends: [ 9 | "dune" {>= "2.5"} 10 | ] 11 | build: [ 12 | ["dune" "subst"] {pinned} 13 | [ 14 | "dune" 15 | "build" 16 | "-p" 17 | name 18 | "-j" 19 | jobs 20 | "@install" 21 | "@runtest" {with-test} 22 | "@doc" {with-doc} 23 | ] 24 | ] 25 | dev-repo: "git+https://github.com/nojb/ocaml-dht.git" 26 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ocaml-dht 2 | 3 | OCaml bindings for [jech/dht](https://github.com/jech/dht), a tiny and efficient 4 | C library used to access the BitTorrent DHT. This project used to contain a 5 | pure OCaml implementation of the DHT extracted from MLdonkey, but it was too 6 | unstable for heavy-duty use so it has been replaced by these bindings. The pure 7 | OCaml implementation might return if I can fix it. 8 | 9 | ## Installation 10 | 11 | ```bash 12 | make 13 | make install 14 | ``` 15 | 16 | More docs to come once this is more stable. 17 | 18 | ### Documentation 19 | 20 | See [online](https://nojb.github.io/ocaml-dht). 21 | 22 | ### Usage 23 | 24 | See 25 | [find_ih.ml](https://github.com/nojb/ocaml-dht/blob/master/lib_test/find_ih.ml) 26 | for a very simple example of how to use the library. 27 | 28 | ### LICENSE 29 | 30 | MIT. 31 | 32 | ## Contact 33 | 34 | Nicolas Ojeda Bar at n.oje.bar@gmail.com. 35 | -------------------------------------------------------------------------------- /dht/LICENCE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2009, 2010 by Juliusz Chroboczek 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in 11 | all copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. 20 | -------------------------------------------------------------------------------- /LICENCE: -------------------------------------------------------------------------------- 1 | (* The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Nicolas Ojeda Bar 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *) 21 | -------------------------------------------------------------------------------- /dht/dht.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2009-2011 by Juliusz Chroboczek 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in 12 | all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | THE SOFTWARE. 21 | */ 22 | 23 | #ifdef __cplusplus 24 | extern "C" { 25 | #endif 26 | 27 | typedef void 28 | dht_callback(void *closure, int event, 29 | const unsigned char *info_hash, 30 | const void *data, size_t data_len); 31 | 32 | #define DHT_EVENT_NONE 0 33 | #define DHT_EVENT_VALUES 1 34 | #define DHT_EVENT_VALUES6 2 35 | #define DHT_EVENT_SEARCH_DONE 3 36 | #define DHT_EVENT_SEARCH_DONE6 4 37 | 38 | extern FILE *dht_debug; 39 | 40 | int dht_init(int s, int s6, const unsigned char *id, const unsigned char *v); 41 | int dht_insert_node(const unsigned char *id, struct sockaddr *sa, int salen); 42 | int dht_ping_node(const struct sockaddr *sa, int salen); 43 | int dht_periodic(const void *buf, size_t buflen, 44 | const struct sockaddr *from, int fromlen, 45 | time_t *tosleep, dht_callback *callback, void *closure); 46 | int dht_search(const unsigned char *id, int port, int af, 47 | dht_callback *callback, void *closure); 48 | int dht_nodes(int af, 49 | int *good_return, int *dubious_return, int *cached_return, 50 | int *incoming_return); 51 | void dht_dump_tables(FILE *f); 52 | int dht_get_nodes(struct sockaddr_in *sin, int *num, 53 | struct sockaddr_in6 *sin6, int *num6); 54 | int dht_uninit(void); 55 | 56 | /* This must be provided by the user. */ 57 | int dht_blacklisted(const struct sockaddr *sa, int salen); 58 | void dht_hash(void *hash_return, int hash_size, 59 | const void *v1, int len1, 60 | const void *v2, int len2, 61 | const void *v3, int len3); 62 | int dht_random_bytes(void *buf, size_t size); 63 | 64 | #ifdef __cplusplus 65 | } 66 | #endif 67 | -------------------------------------------------------------------------------- /lib/dht.ml: -------------------------------------------------------------------------------- 1 | (* The MIT License (MIT) 2 | 3 | Copyright (c) 2015-2017 Nicolas Ojeda Bar 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *) 21 | 22 | type event = 23 | | EVENT_VALUES of Unix.sockaddr list 24 | | EVENT_SEARCH_DONE 25 | 26 | type nodes = 27 | { 28 | good: int; 29 | dubious: int; 30 | cached: int; 31 | incoming: int; 32 | } 33 | 34 | type callback = 35 | event -> string -> unit 36 | 37 | external dht_init: Unix.file_descr option -> Unix.file_descr option -> string -> unit = "caml_dht_init" 38 | external dht_insert_node: string -> Unix.sockaddr -> unit = "caml_dht_insert_node" 39 | external ping_node: Unix.sockaddr -> unit = "caml_dht_ping_node" 40 | external periodic: (bytes * int * Unix.sockaddr) option -> callback -> float = "caml_dht_periodic" 41 | external dht_search: string -> int -> Unix.socket_domain -> callback -> unit = "caml_dht_search" 42 | external nodes: Unix.socket_domain -> nodes = "caml_dht_nodes" 43 | external get_nodes: ipv4:int -> ipv6:int -> Unix.sockaddr list = "caml_dht_get_nodes" 44 | 45 | let init ?ipv4 ?ipv6 id = 46 | if String.length id <> 20 then invalid_arg "init"; 47 | dht_init ipv4 ipv6 id 48 | 49 | let insert_node id sa = 50 | if String.length id <> 20 then invalid_arg "insert_node"; 51 | dht_insert_node id sa 52 | 53 | let search id ?(port = 0) ?(af = Unix.PF_INET) cb = 54 | if String.length id <> 20 then invalid_arg "search"; 55 | dht_search id port af cb 56 | 57 | let dht_hash s = 58 | Digest.string s 59 | 60 | let dht_random_bytes bytes = 61 | for i = 0 to Bigarray.Array1.dim bytes - 1 do 62 | Bigarray.Array1.set bytes i (char_of_int (Random.int 0xFF)) 63 | done 64 | 65 | let () = 66 | Random.self_init () 67 | 68 | let () = 69 | (* Callback.register "dht_blacklisted" dht_blacklisted; *) 70 | Callback.register "dht_hash" dht_hash; 71 | Callback.register "dht_random_bytes" dht_random_bytes 72 | -------------------------------------------------------------------------------- /dht/CHANGES: -------------------------------------------------------------------------------- 1 | 18 May 2015: dht-0.24 2 | 3 | * Fixed off-by-one error that dropped find_nodes responses with exactly 4 | 16 nodes. While forbidden by BEP-5, this is apparently what the good 5 | folks at BitTorrent are doing. Thanks to Tomas Brod. 6 | 7 | 15 May 2015: dht-0.23 8 | 9 | * Changed the limit on the number of nodes in replies to 16. Thanks to 10 | Tomas Brod. 11 | * Fixed a memory leak when initialisation fails. Thanks to 3null. 12 | * Fixed a Y2038 issue. Thanks to Gwiz65. 13 | 14 | 3 May 2014: dht-0.22 15 | 16 | * INCOMPATIBLE CHANGE: the callback now takes const arguments. 17 | * Consult the local storage when performing a search, which should 18 | make bootstrapping of tiny DHTs easier. Note that we're still not 19 | performing local stores, since that would require knowing our IP 20 | address. 21 | * Don't attempt to flush the debug stream if debugging is disabled. 22 | This appears to work around a bug in Transmission. 23 | 24 | 25 July 2011: dht-0.21 25 | 26 | * Blacklisting support. 27 | 28 | 7 July 2011: dht-0.20 29 | 30 | * Fix compilation on systems that have memmem but don't define HAVE_MEMMEM. 31 | 32 | 30 April 2011: dht-0.19 33 | 34 | * Fix incorrect parsing of announces. Thanks to cjdelisle. 35 | * Relax rate limiting slightly. 36 | 37 | 20 January 2011: dht-0.18 38 | 39 | * Fix a bug that could cause parse_message to enter an infinite loop 40 | on overflow. Thanks to Jordan Lee. 41 | 42 | 9 January 2011: dht-0.17: 43 | 44 | * Fix a bug that prevented calling dht_init after dht_uninit. 45 | * Remove the "dofree" parameter to dht_uninit. 46 | 47 | 23 December 2010: dht-0.16: 48 | 49 | * Change the interface to allow sharing of the UDP socket e.g. with uTP. 50 | 51 | 1 July 2010: dht-0.15 52 | 53 | * Port to Windows, for the needs of Transmission. 54 | 55 | 25 March 2010: dht-0.14 56 | 57 | * Fixed ordering of entries in parameter dictionaries. 58 | 59 | 15 December 2009: dht-0.13 60 | 61 | * Implemented protection against incorrect addresses in the DHT. 62 | * Tweaked neighborhood maintenance to wake up less often. 63 | 64 | 11 December 2009: dht-0.12 65 | * Fixed slightly incorrect formatting of DHT messages. 66 | * Fixed incorrect debugging message. 67 | 68 | 22 November 2009: dht-0.11 69 | 70 | * Implemented IPv6 support (BEP-32). 71 | * Fixed a bug which could cause us to never mark a search as finished. 72 | * Fixed a bug that could cause us to send incomplete lists in response to 73 | find_nodes. 74 | * Limit the number of hashes that we're willing to track. 75 | * Made bucket maintenance slightly more aggressive. 76 | * Produce on-the-wire error messages to give a hint to the other side. 77 | * Added a bunch of options to dht-example to make it useful as 78 | a bootstrap node. 79 | * Send version "JC\0\0" when using dht-example. 80 | 81 | 18 October 2009: dht-0.10 82 | 83 | * Send nodes even when sending values. This is a violation of the 84 | protocol, but I have been assured that it doesn't break any deployed 85 | implementation. This is also what both libtorrent and uTorrent do. 86 | * Give up immediately on a search peer when no token was provided. This 87 | is a very reasonable extension to the protocol, and certainly doesn't 88 | break anything. 89 | * Parse heterogeneous values lists correctly. This is mandated by BEP 32. 90 | 91 | 20 September 2009: dht-0.9 92 | 93 | * Fixed incorrect computation of number of nodes. 94 | * Made the initial bucket split eagerly (speeds up bootstrapping). 95 | * Fixed initial filling of search buckets (speeds up searches). 96 | 97 | 28 July 2009: dht-0.8 98 | 99 | * Fixed a crash when expiring the first search on the list. 100 | * Fixed freeing of the search list when uniniting with dofree = 1. 101 | 102 | 24 June 2009: dht-0.7 103 | 104 | * Removed the fixed limit on the number of concurrent searches, we now 105 | use a linked list. 106 | * Fixed build on FreeBSD (thanks to Humihara and Charles Kerr). 107 | 108 | 22 May 2009: dht-0.6 109 | 110 | * Fixed a buffer overflow (when reading) in parse_message. 111 | * Fixed slightly inacurrate metric computation when searching. 112 | * Removed a slightly inaccurate shortcut when responding to find_nodes. 113 | * Relaxed the rate-limiting parameters to 4 requests per second. 114 | 115 | 19 May 2009: dht-0.5 116 | 117 | * Made reading of /dev/urandom a function provided by the user. 118 | * Implemented the ``v'' extension that identifies node implementations. 119 | 120 | 18 May 2009: dht-0.4 121 | 122 | * Fixed the handling of tokens in announce_peer messages. 123 | * Implemented backtracking during search when nodes turn out to be dead. 124 | 125 | 17 May 2009: dht-0.3 126 | 127 | * Fixed a number of incorrectly formatted messages. 128 | * Changed reply to find_peers to spread the load more uniformly. 129 | * Fixed a bug that could cause premature splitting. 130 | * Implemented rate limiting. 131 | * Changed some time constants to be less chatty. 132 | * When determining if a bucket is fresh enough, we now only take replies 133 | into account. 134 | * dht_get_nodes now returns nodes starting with our own bucket. 135 | * Tweaked the memory allocation strategy for stored peers. 136 | 137 | 17 May 2009: dht-0.2 138 | 139 | * Fixed a crash in dht_uninit. 140 | * Added support for saving the list of known-good nodes. 141 | * Changed the interface of dht_nodes to provide the number of nodes that 142 | recently sent incoming requests. 143 | 144 | 13 May 2009: dht-0.1 145 | 146 | * Initial public release. 147 | -------------------------------------------------------------------------------- /lib_test/find_ih.ml: -------------------------------------------------------------------------------- 1 | (* The MIT License (MIT) 2 | 3 | Copyright (c) 2015-2017 Nicolas Ojeda Bar 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *) 21 | 22 | open Printf 23 | 24 | let color n oc s = 25 | if Unix.isatty (Unix.descr_of_out_channel oc) then 26 | fprintf oc "\x1b[%d;1m%s\x1b[0m" n s 27 | else 28 | output_string oc s 29 | 30 | let red = color 31 31 | 32 | let green = color 32 33 | 34 | let yellow = color 33 35 | 36 | let magenta = color 35 37 | 38 | let cyan = color 36 39 | 40 | let logf c s fmt = 41 | eprintf ("[%a] " ^^ fmt ^^ "\n%!") c s 42 | 43 | let errorf fmt = 44 | logf red "ERROR" fmt 45 | 46 | let warnf fmt = 47 | logf yellow "WARNING" fmt 48 | 49 | let infof fmt = 50 | logf green "INFO" fmt 51 | 52 | let hex_of_string s = 53 | let h = Buffer.create (2 * String.length s) in 54 | for i = 0 to String.length s - 1 do 55 | bprintf h "%02x" (int_of_char s.[i]); 56 | done; 57 | Buffer.contents h 58 | 59 | let short_hex_of_string s = 60 | String.sub (hex_of_string s) 0 6 61 | 62 | let string_of_hex h = 63 | if String.length h mod 2 <> 0 then invalid_arg "string_of_hex"; 64 | let s = Bytes.create (String.length h / 2) in 65 | let c = Bytes.create 2 in 66 | for i = 0 to String.length h / 2 - 1 do 67 | Bytes.set c 0 h.[2*i]; 68 | Bytes.set c 1 h.[2*i+1]; 69 | Bytes.set s i (Scanf.sscanf (Bytes.unsafe_to_string c) "%x" char_of_int) 70 | done; 71 | Bytes.unsafe_to_string s 72 | 73 | let string_of_sockaddr = function 74 | | Unix.ADDR_UNIX s -> 75 | s 76 | | Unix.ADDR_INET (ip, port) -> 77 | sprintf "%s:%d" (Unix.string_of_inet_addr ip) port 78 | 79 | let port = 80 | ref 4567 81 | 82 | let fresh_id () = 83 | let s = Bytes.create 20 in 84 | for i = 0 to 19 do 85 | Bytes.set s i (char_of_int (Random.int 256)) 86 | done; 87 | Bytes.unsafe_to_string s 88 | 89 | let bootstrap_nodes = 90 | [ 91 | "dht.transmissionbt.com", 6881; 92 | "router.utorrent.com", 6881; 93 | ] 94 | 95 | let resolve (name, port) = 96 | try 97 | match Unix.getaddrinfo name (string_of_int port) [] with 98 | | [] -> 99 | raise Exit 100 | | {Unix.ai_addr; _} :: _ -> 101 | ai_addr 102 | with _ -> 103 | ksprintf failwith "Server %s could not be contacted" name 104 | 105 | let id, start_nodes = 106 | if Sys.file_exists "dht.dat" then begin 107 | let ic = open_in_bin "dht.dat" in 108 | let id, nodes = Marshal.from_channel ic in 109 | close_in ic; 110 | infof "Restored %d good nodes" (List.length nodes); 111 | id, nodes 112 | end else 113 | fresh_id (), List.map resolve bootstrap_nodes 114 | 115 | let () = 116 | infof "id %a" magenta (hex_of_string id) 117 | 118 | let timer () = 119 | let t0 = Unix.gettimeofday () in 120 | fun () -> Unix.gettimeofday () -. t0 121 | 122 | let buf = 123 | Bytes.create 4096 124 | 125 | let fd = 126 | let fd = Unix.socket Unix.PF_INET Unix.SOCK_DGRAM 0 in 127 | Unix.bind fd (Unix.ADDR_INET (Unix.inet_addr_any, !port)); 128 | Dht.init ~ipv4:fd ?ipv6:None id; 129 | fd 130 | 131 | let wait_read sleep = 132 | let rd, _, ed = Unix.select [fd] [] [fd] sleep in 133 | if ed <> [] then failwith "Read error"; 134 | if rd <> [] then begin 135 | let len, sa = Unix.recvfrom fd buf 0 (Bytes.length buf - 1) [] in 136 | Bytes.set buf len '\000'; 137 | Some (buf, len, sa) 138 | end else 139 | None 140 | 141 | let search_all l = 142 | let n = ref (List.length l) in 143 | let t = timer () in 144 | let cb ev ih = 145 | match ev with 146 | | Dht.EVENT_VALUES addrs -> 147 | let aux sa = 148 | logf magenta (sprintf "%.2f" (t ())) "%s: %s" 149 | (short_hex_of_string ih) (string_of_sockaddr sa) 150 | in 151 | List.iter aux addrs 152 | | Dht.EVENT_SEARCH_DONE -> 153 | decr n 154 | in 155 | let logf fmt = logf red "SEARCH" fmt in 156 | List.iter (fun ih -> 157 | Dht.search ih ~port:!port cb; 158 | logf "START %s" (hex_of_string ih) 159 | ) l; 160 | let sleep = ref 0.0 in 161 | while !n > 0 do 162 | logf "Waiting... (%.2fs, n=%d)" !sleep !n; 163 | sleep := Dht.periodic (wait_read !sleep) cb 164 | done 165 | 166 | let ping sa = 167 | infof "Pinging %s..." (string_of_sockaddr sa); 168 | Dht.ping_node sa 169 | 170 | let bootstrap () = 171 | let logf fmt = logf yellow "BOOTSTRAP" fmt in 172 | List.iter ping start_nodes; 173 | let rec loop sleep = 174 | let {Dht.good; dubious; _} = Dht.nodes Unix.PF_INET in 175 | let check = good >= 2 && good + dubious >= 10 in 176 | if not check then begin 177 | logf "Waiting... (%.2fs, good=%d, dubious=%d)" sleep good dubious; 178 | loop (Dht.periodic (wait_read sleep) (fun _ _ -> ())) 179 | end else 180 | logf "OK" 181 | in 182 | loop 0.0 183 | 184 | let save () = 185 | let nodes = Dht.get_nodes ~ipv4:1024 ~ipv6:1024 in 186 | let oc = open_out_bin "dht.dat" in 187 | Marshal.to_channel oc (id, nodes) []; 188 | close_out oc; 189 | infof "Saved %d good nodes" (List.length nodes) 190 | 191 | let spec = 192 | [ 193 | "-p", Arg.Set_int port, " Port to use to communicate"; 194 | ] 195 | 196 | let usage_msg = 197 | sprintf "%s [-v] INFOHASH INFOHASH ..." Sys.executable_name 198 | 199 | let tosearch = ref [] 200 | 201 | let () = 202 | try 203 | Arg.parse (Arg.align spec) (fun s -> tosearch := s :: !tosearch) usage_msg; 204 | bootstrap (); 205 | search_all (List.map string_of_hex (List.sort_uniq compare !tosearch)); 206 | save () 207 | with e -> 208 | errorf "Fatal: %s" (Printexc.to_string e); 209 | exit 2 210 | -------------------------------------------------------------------------------- /lib/dht.mli: -------------------------------------------------------------------------------- 1 | (* The MIT License (MIT) 2 | 3 | Copyright (c) 2015-2017 Nicolas Ojeda Bar 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *) 21 | 22 | (** This interface implement bindings to Juliusz Chroboczek's 23 | {{:https://github.com/jech/dht}dht library.} That library implements the 24 | variant of the Kademlia Distributed Hash Table (DHT) used in the Bittorrent 25 | network ({i mainline} variant). 26 | 27 | The following documentation is lightly adapted from the one coming with that 28 | library. *) 29 | 30 | type event = 31 | | EVENT_VALUES of Unix.sockaddr list 32 | | EVENT_SEARCH_DONE 33 | 34 | type nodes = 35 | { 36 | good: int; 37 | dubious: int; 38 | cached: int; 39 | incoming: int; 40 | } 41 | 42 | type callback = 43 | event -> string -> unit 44 | 45 | val init: ?ipv4:Unix.file_descr -> ?ipv6:Unix.file_descr -> string -> unit 46 | (** This must be called before using the library. You pass it a bound IPv4 47 | datagram socket, a bound IPv6 datagram socket, and your node [id], a 48 | 20-octet array that should be globally unique. 49 | 50 | If you're on a multi-homed host, you should bind the sockets to one of your 51 | addresses. 52 | 53 | Node ids must be well distributed, so you cannot just use your Bittorrent 54 | id; you should either generate a truly random value (using plenty of 55 | entropy), or at least take the SHA-1 of something. However, it is a good 56 | idea to keep the id stable, so you may want to store it in stable storage 57 | at client shutdown. *) 58 | 59 | val insert_node: string -> Unix.sockaddr -> unit 60 | (** This is a softer bootstrapping method, which doesn't actually send a query 61 | -- it only stores the node in the routing table for later use. It is a good 62 | idea to use that when e.g. restoring your routing table from disk. 63 | 64 | Note that [insert_node] requires that you supply a node id. If the id turns 65 | out to be wrong, the DHT will eventually recover; still, inserting massive 66 | amounts of incorrect information into your routing table is certainly not a 67 | good idea. 68 | 69 | An additionaly difficulty with [insert_node] is that, for various reasons, a 70 | Kademlia routing table cannot absorb nodes faster than a certain rate. 71 | Dumping a large number of nodes into a table using [insert_node] will 72 | probably cause most of these nodes to be discarded straight away. (The 73 | tolerable rate is difficult to estimate; it is probably on the order of one 74 | node every few seconds per node already in the table divided by 8, for some 75 | suitable value of 8.) *) 76 | 77 | val ping_node: Unix.sockaddr -> unit 78 | (** This is the main bootstrapping primitive. You pass it an address at which 79 | you believe that a DHT node may be living, and a query will be sent. If a node 80 | replies, and if there is space in the routing table, it will be inserted. *) 81 | 82 | val periodic: (bytes * int * Unix.sockaddr) option -> callback -> float 83 | (** This function should be called by your main loop periodically, and also 84 | whenever data is available on the socket. The time after which [periodic] 85 | should be called if no data is available is returned. (You do not need to 86 | be particularly accurate; actually, it is a good idea to be late by a random 87 | value.) 88 | 89 | The parameters optionally carry a received message [(pkt, len, sa)] where 90 | the packet is [Bytes.sub pkt 0 len] and [sa] is the origin address, as 91 | obtained from [Unix.recvfrom] for examples. 92 | 93 | [periodic] also takes a callback, which will be called whenever something 94 | interesting happens (see below). *) 95 | 96 | val search: string -> ?port:int -> ?af:Unix.socket_domain -> callback -> unit 97 | (** This schedules a search for information about the info-hash specified in 98 | [id]. If [port] is given, it specifies the TCP port on which the current 99 | peer is listening; in that case, when the search is complete it will be 100 | announced to the network. 101 | 102 | In either case, data is passed to the callback function as soon as it is 103 | available, possibly in multiple pieces. The callback function will 104 | additionally be called when the search is complete. 105 | 106 | Up to [1024] searches can be in progress at a given time; any more, and 107 | [search] will raise [Failure "dht_search"]. If you specify a new search for 108 | the same info hash as a search still in progress, the previous search is 109 | combined with the new one -- you will only receive a completion indication 110 | once. *) 111 | 112 | val get_nodes: ipv4:int -> ipv6:int -> Unix.sockaddr list 113 | (** This retrieves the list of known good nodes, starting with the nodes in our 114 | own bucket. It is a good idea to save the list of known good nodes at 115 | shutdown, and ping them at startup. *) 116 | 117 | val nodes: Unix.socket_domain -> nodes 118 | (** This returns the number of known good, dubious and cached nodes in our 119 | routing table. This can be used to decide whether it's reasonable to start a 120 | search; a search is likely to be successful as long as we have a few good nodes; 121 | however, in order to avoid overloading your bootstrap nodes, you may want to 122 | wait until good is at least 4 and good + doubtful is at least 30 or so. 123 | 124 | It also includes the number of nodes that recently sent us an unsolicited 125 | request; this can be used to determine if the UDP port used for the DHT is 126 | firewalled. 127 | 128 | If you want to display a single figure to the user, you should display [good 129 | + doubtful], which is the total number of nodes in your routing table. Some 130 | clients try to estimate the total number of nodes, but this doesn't make 131 | much sense -- since the result is exponential in the number of nodes in the 132 | routing table, small variations in the latter cause huge jumps in the 133 | former. *) 134 | -------------------------------------------------------------------------------- /dht/README: -------------------------------------------------------------------------------- 1 | The files dht.c and dht.h implement the variant of the Kademlia Distributed 2 | Hash Table (DHT) used in the Bittorrent network (``mainline'' variant). 3 | 4 | The file dht-example.c is a stand-alone program that participates in the 5 | DHT. Another example is a patch against Transmission, which you might or 6 | might not be able to find somewhere. 7 | 8 | The code is designed to work well in both event-driven and threaded code. 9 | The caller, which is either an event-loop or a dedicated thread, must 10 | periodically call the function dht_periodic. In addition, it must call 11 | dht_periodic whenever any data has arrived from the network. 12 | 13 | All functions return -1 in case of failure, in which case errno is set, or 14 | a positive value in case of success. 15 | 16 | Initialisation 17 | ************** 18 | 19 | * dht_init 20 | 21 | This must be called before using the library. You pass it a bound IPv4 22 | datagram socket, a bound IPv6 datagram socket, and your node id, a 20-octet 23 | array that should be globally unique. 24 | 25 | If you're on a multi-homed host, you should bind the sockets to one of your 26 | addresses. 27 | 28 | Node ids must be well distributed, so you cannot just use your Bittorrent 29 | id; you should either generate a truly random value (using plenty of 30 | entropy), or at least take the SHA-1 of something. However, it is a good 31 | idea to keep the id stable, so you may want to store it in stable storage 32 | at client shutdown. 33 | 34 | 35 | * dht_uninit 36 | 37 | This may be called at the end of the session. 38 | 39 | Bootstrapping 40 | ************* 41 | 42 | The DHT needs to be taught a small number of contacts to begin functioning. 43 | You can hard-wire a small number of stable nodes in your application, but 44 | this obviously fails to scale. You may save the list of known good nodes 45 | at shutdown, and restore it at restart. You may also grab nodes from 46 | torrent files (the nodes field), and you may exchange contacts with other 47 | Bittorrent peers using the PORT extension. 48 | 49 | * dht_ping 50 | 51 | This is the main bootstrapping primitive. You pass it an address at which 52 | you believe that a DHT node may be living, and a query will be sent. If 53 | a node replies, and if there is space in the routing table, it will be 54 | inserted. 55 | 56 | * dht_insert_node 57 | 58 | This is a softer bootstrapping method, which doesn't actually send 59 | a query -- it only stores the node in the routing table for later use. It 60 | is a good idea to use that when e.g. restoring your routing table from 61 | disk. 62 | 63 | Note that dht_insert_node requires that you supply a node id. If the id 64 | turns out to be wrong, the DHT will eventually recover; still, inserting 65 | massive amounts of incorrect information into your routing table is 66 | certainly not a good idea. 67 | 68 | An additionaly difficulty with dht_insert_node is that, for various 69 | reasons, a Kademlia routing table cannot absorb nodes faster than a certain 70 | rate. Dumping a large number of nodes into a table using dht_insert_node 71 | will probably cause most of these nodes to be discarded straight away. 72 | (The tolerable rate is difficult to estimate; it is probably on the order 73 | of one node every few seconds per node already in the table divided by 8, 74 | for some suitable value of 8.) 75 | 76 | Doing some work 77 | *************** 78 | 79 | * dht_periodic 80 | 81 | This function should be called by your main loop periodically, and also 82 | whenever data is available on the socket. The time after which 83 | dht_periodic should be called if no data is available is returned in the 84 | parameter tosleep. (You do not need to be particularly accurate; actually, 85 | it is a good idea to be late by a random value.) 86 | 87 | The parameters buf, buflen, from and fromlen optionally carry a received 88 | message. If buflen is 0, then no message was received. 89 | 90 | Dht_periodic also takes a callback, which will be called whenever something 91 | interesting happens (see below). 92 | 93 | * dht_search 94 | 95 | This schedules a search for information about the info-hash specified in 96 | id. If port is not 0, it specifies the TCP port on which the current peer 97 | is listening; in that case, when the search is complete it will be announced 98 | to the network. The port is in host order, beware if you got it from 99 | a struct sockaddr_in. 100 | 101 | In either case, data is passed to the callback function as soon as it is 102 | available, possibly in multiple pieces. The callback function will 103 | additionally be called when the search is complete. 104 | 105 | Up to DHT_MAX_SEARCHES (1024) searches can be in progress at a given time; 106 | any more, and dht_search will return -1. If you specify a new search for 107 | the same info hash as a search still in progress, the previous search is 108 | combined with the new one -- you will only receive a completion indication 109 | once. 110 | 111 | Information queries 112 | ******************* 113 | 114 | * dht_nodes 115 | 116 | This returns the number of known good, dubious and cached nodes in our 117 | routing table. This can be used to decide whether it's reasonable to start 118 | a search; a search is likely to be successful as long as we have a few good 119 | nodes; however, in order to avoid overloading your bootstrap nodes, you may 120 | want to wait until good is at least 4 and good + doubtful is at least 30 or 121 | so. 122 | 123 | It also includes the number of nodes that recently sent us an unsolicited 124 | request; this can be used to determine if the UDP port used for the DHT is 125 | firewalled. 126 | 127 | If you want to display a single figure to the user, you should display 128 | good + doubtful, which is the total number of nodes in your routing table. 129 | Some clients try to estimate the total number of nodes, but this doesn't 130 | make much sense -- since the result is exponential in the number of nodes 131 | in the routing table, small variations in the latter cause huge jumps in 132 | the former. 133 | 134 | * dht_get_nodes 135 | 136 | This retrieves the list of known good nodes, starting with the nodes in our 137 | own bucket. It is a good idea to save the list of known good nodes at 138 | shutdown, and ping them at startup. 139 | 140 | * dht_dump_tables 141 | * dht_debug 142 | 143 | These are debugging aids. 144 | 145 | Functions provided by you 146 | ************************* 147 | 148 | * The callback function 149 | 150 | The callback function is called with 5 arguments. Closure is simply the 151 | value that you passed to dht_periodic. Event is one of DHT_EVENT_VALUES or 152 | DHT_EVENT_VALUES6, which indicates that we have new values, or 153 | DHT_EVENT_SEARCH_DONE or DHT_EVENT_SEARCH_DONE6, which indicates that 154 | a search has completed. In either case, info_hash is set to the info-hash 155 | of the search. 156 | 157 | In the case of DHT_EVENT_VALUES, data is a list of nodes in ``compact'' 158 | format -- 6 or 18 bytes per node. Its length in bytes is in data_len. 159 | 160 | * dht_blacklisted 161 | 162 | This is a function that takes an IP address and returns true if this 163 | address should be silently ignored. Do not use this feature unless you 164 | really must -- Kademlia supposes transitive reachability. 165 | 166 | * dht_hash 167 | 168 | This should compute a reasonably strong cryptographic hash of the passed 169 | values. It should map cleanly to your favourite crypto toolkit's MD5 or 170 | SHA-1 function. 171 | 172 | * dht_random_bytes 173 | 174 | This should fill the supplied buffer with true random bytes. 175 | 176 | Final notes 177 | *********** 178 | 179 | * NAT 180 | 181 | Nothing works well across NATs, but Kademlia is somewhat less impacted than 182 | many other protocols. The implementation takes care to distinguish between 183 | unidirectional and bidirectional reachability, and NATed nodes will 184 | eventually fall out from other nodes' routing tables. 185 | 186 | While there is no periodic pinging in this implementation, maintaining 187 | a full routing table requires slightly more than one packet exchange per 188 | minute, even in a completely idle network; this should be sufficient to 189 | make most full cone NATs happy. 190 | 191 | * Missing functionality 192 | 193 | Some of the code has had very little testing. If it breaks, you get to 194 | keep both pieces. 195 | 196 | 197 | Juliusz Chroboczek 198 | 199 | -------------------------------------------------------------------------------- /lib/dht_stubs.c: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2015-2017 Nicolas Ojeda Bar 2 | 3 | This file is part of ocaml-libutp. 4 | 5 | This library is free software; you can redistribute it and/or modify it under 6 | the terms of the GNU Lesser General Public License as published by the Free 7 | Software Foundation; either version 2.1 of the License, or (at your option) 8 | any later version. 9 | 10 | This library is distributed in the hope that it will be useful, but WITHOUT 11 | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 12 | FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more 13 | details. 14 | 15 | You should have received a copy of the GNU Lesser General Public License 16 | along with this library; if not, write to the Free Software Foundation, Inc., 17 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ 18 | 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | 34 | #include "dht.h" 35 | 36 | CAMLprim void caml_dht_callback (void *closure, int event, const unsigned char *info_hash, const void *data, size_t data_len) 37 | { 38 | CAMLparam0 (); 39 | CAMLlocal5 (ev, ih, lst, cons, addr); 40 | union sock_addr_union from; 41 | const unsigned char *p = data; 42 | 43 | lst = Val_emptylist; 44 | 45 | switch (event) { 46 | case DHT_EVENT_VALUES: 47 | ev = caml_alloc (1, 0); 48 | for (int i = data_len - 6; i >= 0; i -= 6) { 49 | from.s_gen.sa_family = AF_INET; 50 | memcpy (&from.s_inet.sin_addr, p + i, 4); 51 | from.s_inet.sin_port = *(unsigned short *) (p + i + 4); 52 | addr = alloc_sockaddr (&from, sizeof (from.s_inet), 0); 53 | cons = caml_alloc (2, 0); 54 | Store_field (cons, 0, addr); 55 | Store_field (cons, 1, lst); 56 | lst = cons; 57 | } 58 | Store_field (ev, 0, lst); 59 | break; 60 | case DHT_EVENT_VALUES6: 61 | ev = caml_alloc (1, 0); 62 | for (int i = data_len - 18; i >= 0; i -= 18) { 63 | from.s_gen.sa_family = AF_INET6; 64 | memcpy (&from.s_inet6.sin6_addr, data + i, 16); 65 | from.s_inet6.sin6_port = *(unsigned short *) (data + i + 16); 66 | addr = alloc_sockaddr (&from, sizeof (from.s_inet6), 0); 67 | cons = caml_alloc (2, 0); 68 | Store_field (cons, 0, addr); 69 | Store_field (cons, 1, lst); 70 | lst = cons; 71 | } 72 | Store_field (ev, 0, lst); 73 | break; 74 | case DHT_EVENT_SEARCH_DONE: 75 | case DHT_EVENT_SEARCH_DONE6: 76 | ev = Val_int (0); 77 | break; 78 | default: 79 | CAMLreturn0; 80 | } 81 | 82 | ih = caml_alloc_string (20); 83 | memcpy (String_val(ih), info_hash, 20); 84 | 85 | caml_callback2 (*(value *)closure, ev, ih); 86 | 87 | CAMLreturn0; 88 | } 89 | 90 | CAMLprim value caml_dht_init (value ipv4, value ipv6, value id) 91 | { 92 | CAMLparam3 (ipv4, ipv6, id); 93 | int res, s, s6; 94 | 95 | if (ipv4 == Val_int (0)) { 96 | s = -1; 97 | } else { 98 | s = Int_val (Field (ipv4, 0)); 99 | } 100 | 101 | if (ipv6 == Val_int (0)) { 102 | s6 = -1; 103 | } else { 104 | s6 = Int_val (Field (ipv6, 0)); 105 | } 106 | 107 | res = dht_init (s, s6, (unsigned char *) String_val (id), NULL); 108 | 109 | /* dht_debug = stderr; */ 110 | 111 | if (res < 0) { 112 | caml_failwith ("dht_init"); 113 | } 114 | 115 | CAMLreturn (Val_unit); 116 | } 117 | 118 | CAMLprim value caml_dht_insert_node (value id, value addr) 119 | { 120 | CAMLparam2 (id, addr); 121 | union sock_addr_union sa; 122 | socklen_param_type salen; 123 | 124 | get_sockaddr (addr, &sa, &salen); 125 | dht_insert_node ((unsigned char *) String_val (id), &sa.s_gen, salen); 126 | 127 | CAMLreturn (Val_unit); 128 | } 129 | 130 | CAMLprim value caml_dht_ping_node (value addr) 131 | { 132 | CAMLparam1 (addr); 133 | union sock_addr_union sa; 134 | socklen_param_type salen; 135 | int res; 136 | 137 | get_sockaddr (addr, &sa, &salen); 138 | res = dht_ping_node (&sa.s_gen, salen); 139 | 140 | if (res < 0) { 141 | caml_failwith ("dht_ping_node"); 142 | } 143 | 144 | CAMLreturn (Val_unit); 145 | } 146 | 147 | CAMLprim value caml_dht_periodic (value pkt_opt, value closure) 148 | { 149 | CAMLparam2 (pkt_opt, closure); 150 | CAMLlocal4 (pkt, buf, buflen, addr); 151 | time_t tosleep; 152 | union sock_addr_union from; 153 | socklen_param_type fromlen; 154 | int res; 155 | value *root = malloc (sizeof (closure)); 156 | *root = closure; 157 | caml_register_generational_global_root (root); 158 | 159 | if (pkt_opt == Val_int(0)) { 160 | res = dht_periodic (NULL, 0, NULL, 0, &tosleep, &caml_dht_callback, root); 161 | } else { 162 | pkt = Field (pkt_opt, 0); 163 | buf = Field (pkt, 0); 164 | buflen = Field (pkt, 1); 165 | addr = Field (pkt, 2); 166 | get_sockaddr (addr, &from, &fromlen); 167 | res = dht_periodic (String_val(buf), Int_val(buflen), &from.s_gen, fromlen, &tosleep, &caml_dht_callback, root); 168 | } 169 | 170 | caml_remove_generational_global_root (root); 171 | free (root); 172 | 173 | if (res < 0) { 174 | caml_failwith ("dht_periodic"); 175 | } 176 | 177 | CAMLreturn (caml_copy_double ((double) tosleep)); 178 | } 179 | 180 | CAMLprim value caml_dht_search (value id, value port, value dom, value closure) 181 | { 182 | CAMLparam4 (id, port, dom, closure); 183 | int res, af; 184 | value *root; 185 | 186 | switch (Int_val(dom)) { 187 | case 0: 188 | af = AF_UNIX; 189 | break; 190 | case 1: 191 | af = AF_INET; 192 | break; 193 | case 2: 194 | af = AF_INET6; 195 | break; 196 | default: 197 | caml_invalid_argument("dht_search"); 198 | break; 199 | } 200 | 201 | root = malloc (sizeof (value)); 202 | *root = closure; 203 | caml_register_generational_global_root (root); 204 | res = dht_search ((unsigned char *) String_val (id), Int_val (port), af, &caml_dht_callback, root); 205 | caml_remove_generational_global_root (root); 206 | free (root); 207 | 208 | if (res < 0) { 209 | caml_failwith ("dht_search"); 210 | } 211 | 212 | CAMLreturn (Val_unit); 213 | } 214 | 215 | CAMLprim value caml_dht_get_nodes (value num, value num6) 216 | { 217 | CAMLparam2 (num, num6); 218 | CAMLlocal3 (lst, sa, cons); 219 | int n = Int_val (num); 220 | int n6 = Int_val (num6); 221 | struct sockaddr_in in[n]; 222 | struct sockaddr_in6 in6[n6]; 223 | union sock_addr_union adr; 224 | union sock_addr_union adr6; 225 | int res; 226 | 227 | lst = Val_emptylist; 228 | 229 | res = dht_get_nodes (in, &n, in6, &n6); 230 | 231 | if (res < 0) caml_failwith ("dht_get_nodes"); 232 | 233 | for (int i = 0; i < n; i ++) { 234 | memcpy (&adr.s_inet, &in[i], sizeof (struct sockaddr_in)); 235 | sa = alloc_sockaddr (&adr, sizeof (struct sockaddr_in), 0); 236 | cons = caml_alloc_tuple (2); 237 | Store_field (cons, 0, sa); 238 | Store_field (cons, 1, lst); 239 | lst = cons; 240 | } 241 | 242 | for (int i = 0; i < n6; i ++) { 243 | memcpy (&adr.s_inet6, &in6[i], sizeof (struct sockaddr_in6)); 244 | sa = alloc_sockaddr (&adr6, sizeof (struct sockaddr_in6), 0); 245 | cons = caml_alloc_tuple (2); 246 | Store_field (cons, 0, sa); 247 | Store_field (cons, 1, lst); 248 | lst = cons; 249 | } 250 | 251 | CAMLreturn (lst); 252 | } 253 | 254 | CAMLprim value caml_dht_nodes (value sdom) 255 | { 256 | CAMLparam1 (sdom); 257 | CAMLlocal1 (nodes); 258 | int af, good, dubious, cached, incoming; 259 | 260 | switch (Int_val (sdom)) { 261 | case 0: 262 | af = AF_UNIX; 263 | break; 264 | case 1: 265 | af = AF_INET; 266 | break; 267 | case 2: 268 | af = AF_INET6; 269 | break; 270 | default: 271 | caml_invalid_argument ("caml_dht_nodes"); 272 | } 273 | 274 | dht_nodes (af, &good, &dubious, &cached, &incoming); 275 | 276 | nodes = caml_alloc (4, 0); 277 | Store_field (nodes, 0, Val_int(good)); 278 | Store_field (nodes, 1, Val_int(dubious)); 279 | Store_field (nodes, 2, Val_int(cached)); 280 | Store_field (nodes, 3, Val_int(incoming)); 281 | 282 | CAMLreturn (nodes); 283 | } 284 | 285 | /* Functions called by the DHT. */ 286 | int dht_blacklisted (const struct sockaddr *sa, int salen) 287 | { 288 | return 0; 289 | } 290 | 291 | void dht_hash(void *hash_return, int hash_size, const void *v1, int len1, const void *v2, int len2, const void *v3, int len3) 292 | { 293 | CAMLparam0 (); 294 | CAMLlocal2 (w, r); 295 | 296 | w = caml_alloc_string (len1 + len2 + len3); 297 | 298 | memcpy (String_val (w), v1, len1); 299 | memcpy (String_val (w) + len1, v2, len2); 300 | memcpy (String_val (w) + len1 + len2, v3, len3); 301 | 302 | r = caml_callback (*caml_named_value ("dht_hash"), w); 303 | 304 | if (hash_size > 16) 305 | memset ((char *) hash_return + 16, 0, hash_size - 16); 306 | 307 | memcpy (hash_return, String_val (r), hash_size > 16 ? 16 : hash_size); 308 | 309 | CAMLreturn0; 310 | } 311 | 312 | int dht_random_bytes (void *buf, size_t size) 313 | { 314 | CAMLparam0 (); 315 | CAMLlocal1 (ba); 316 | ba = caml_ba_alloc_dims (CAML_BA_UINT8 | CAML_BA_C_LAYOUT, 1, buf, size); 317 | caml_callback (*caml_named_value ("dht_random_bytes"), ba); 318 | CAMLreturn (Val_int(size)); 319 | } 320 | -------------------------------------------------------------------------------- /dht/dht-example.c: -------------------------------------------------------------------------------- 1 | /* This example code was written by Juliusz Chroboczek. 2 | You are free to cut'n'paste from it to your heart's content. */ 3 | 4 | /* For crypt */ 5 | #define _GNU_SOURCE 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | 20 | #include "dht.h" 21 | 22 | #define MAX_BOOTSTRAP_NODES 20 23 | static struct sockaddr_storage bootstrap_nodes[MAX_BOOTSTRAP_NODES]; 24 | static int num_bootstrap_nodes = 0; 25 | 26 | static volatile sig_atomic_t dumping = 0, searching = 0, exiting = 0; 27 | 28 | static void 29 | sigdump(int signo) 30 | { 31 | dumping = 1; 32 | } 33 | 34 | static void 35 | sigtest(int signo) 36 | { 37 | searching = 1; 38 | } 39 | 40 | static void 41 | sigexit(int signo) 42 | { 43 | exiting = 1; 44 | } 45 | 46 | static void 47 | init_signals(void) 48 | { 49 | struct sigaction sa; 50 | sigset_t ss; 51 | 52 | sigemptyset(&ss); 53 | sa.sa_handler = sigdump; 54 | sa.sa_mask = ss; 55 | sa.sa_flags = 0; 56 | sigaction(SIGUSR1, &sa, NULL); 57 | 58 | sigemptyset(&ss); 59 | sa.sa_handler = sigtest; 60 | sa.sa_mask = ss; 61 | sa.sa_flags = 0; 62 | sigaction(SIGUSR2, &sa, NULL); 63 | 64 | sigemptyset(&ss); 65 | sa.sa_handler = sigexit; 66 | sa.sa_mask = ss; 67 | sa.sa_flags = 0; 68 | sigaction(SIGINT, &sa, NULL); 69 | } 70 | 71 | const unsigned char hash[20] = { 72 | 0x54, 0x57, 0x87, 0x89, 0xdf, 0xc4, 0x23, 0xee, 0xf6, 0x03, 73 | 0x1f, 0x81, 0x94, 0xa9, 0x3a, 0x16, 0x98, 0x8b, 0x72, 0x7b 74 | }; 75 | 76 | /* The call-back function is called by the DHT whenever something 77 | interesting happens. Right now, it only happens when we get a new value or 78 | when a search completes, but this may be extended in future versions. */ 79 | static void 80 | callback(void *closure, 81 | int event, 82 | const unsigned char *info_hash, 83 | const void *data, size_t data_len) 84 | { 85 | if(event == DHT_EVENT_SEARCH_DONE) 86 | printf("Search done.\n"); 87 | else if(event == DHT_EVENT_VALUES) 88 | printf("Received %d values.\n", (int)(data_len / 6)); 89 | } 90 | 91 | static unsigned char buf[4096]; 92 | 93 | int 94 | main(int argc, char **argv) 95 | { 96 | int i, rc, fd; 97 | int s = -1, s6 = -1, port; 98 | int have_id = 0; 99 | unsigned char myid[20]; 100 | time_t tosleep = 0; 101 | char *id_file = "dht-example.id"; 102 | int opt; 103 | int quiet = 0, ipv4 = 1, ipv6 = 1; 104 | struct sockaddr_in sin; 105 | struct sockaddr_in6 sin6; 106 | struct sockaddr_storage from; 107 | socklen_t fromlen; 108 | 109 | memset(&sin, 0, sizeof(sin)); 110 | sin.sin_family = AF_INET; 111 | 112 | memset(&sin6, 0, sizeof(sin6)); 113 | sin6.sin6_family = AF_INET6; 114 | 115 | 116 | 117 | while(1) { 118 | opt = getopt(argc, argv, "q46b:i:"); 119 | if(opt < 0) 120 | break; 121 | 122 | switch(opt) { 123 | case 'q': quiet = 1; break; 124 | case '4': ipv6 = 0; break; 125 | case '6': ipv4 = 0; break; 126 | case 'b': { 127 | char buf[16]; 128 | int rc; 129 | rc = inet_pton(AF_INET, optarg, buf); 130 | if(rc == 1) { 131 | memcpy(&sin.sin_addr, buf, 4); 132 | break; 133 | } 134 | rc = inet_pton(AF_INET6, optarg, buf); 135 | if(rc == 1) { 136 | memcpy(&sin6.sin6_addr, buf, 16); 137 | break; 138 | } 139 | goto usage; 140 | } 141 | break; 142 | case 'i': 143 | id_file = optarg; 144 | break; 145 | default: 146 | goto usage; 147 | } 148 | } 149 | 150 | /* Ids need to be distributed evenly, so you cannot just use your 151 | bittorrent id. Either generate it randomly, or take the SHA-1 of 152 | something. */ 153 | fd = open(id_file, O_RDONLY); 154 | if(fd >= 0) { 155 | rc = read(fd, myid, 20); 156 | if(rc == 20) 157 | have_id = 1; 158 | close(fd); 159 | } 160 | 161 | fd = open("/dev/urandom", O_RDONLY); 162 | if(fd < 0) { 163 | perror("open(random)"); 164 | exit(1); 165 | } 166 | 167 | if(!have_id) { 168 | int ofd; 169 | 170 | rc = read(fd, myid, 20); 171 | if(rc < 0) { 172 | perror("read(random)"); 173 | exit(1); 174 | } 175 | have_id = 1; 176 | close(fd); 177 | 178 | ofd = open(id_file, O_WRONLY | O_CREAT | O_TRUNC, 0666); 179 | if(ofd >= 0) { 180 | rc = write(ofd, myid, 20); 181 | if(rc < 20) 182 | unlink(id_file); 183 | close(ofd); 184 | } 185 | } 186 | 187 | { 188 | unsigned seed; 189 | read(fd, &seed, sizeof(seed)); 190 | srandom(seed); 191 | } 192 | 193 | close(fd); 194 | 195 | if(argc < 2) 196 | goto usage; 197 | 198 | i = optind; 199 | 200 | if(argc < i + 1) 201 | goto usage; 202 | 203 | port = atoi(argv[i++]); 204 | if(port <= 0 || port >= 0x10000) 205 | goto usage; 206 | 207 | while(i < argc) { 208 | struct addrinfo hints, *info, *infop; 209 | memset(&hints, 0, sizeof(hints)); 210 | hints.ai_socktype = SOCK_DGRAM; 211 | if(!ipv6) 212 | hints.ai_family = AF_INET; 213 | else if(!ipv4) 214 | hints.ai_family = AF_INET6; 215 | else 216 | hints.ai_family = 0; 217 | rc = getaddrinfo(argv[i], argv[i + 1], &hints, &info); 218 | if(rc != 0) { 219 | fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rc)); 220 | exit(1); 221 | } 222 | 223 | i++; 224 | if(i >= argc) 225 | goto usage; 226 | 227 | infop = info; 228 | while(infop) { 229 | memcpy(&bootstrap_nodes[num_bootstrap_nodes], 230 | infop->ai_addr, infop->ai_addrlen); 231 | infop = infop->ai_next; 232 | num_bootstrap_nodes++; 233 | } 234 | freeaddrinfo(info); 235 | 236 | i++; 237 | } 238 | 239 | /* If you set dht_debug to a stream, every action taken by the DHT will 240 | be logged. */ 241 | if(!quiet) 242 | dht_debug = stdout; 243 | 244 | /* We need an IPv4 and an IPv6 socket, bound to a stable port. Rumour 245 | has it that uTorrent works better when it is the same as your 246 | Bittorrent port. */ 247 | if(ipv4) { 248 | s = socket(PF_INET, SOCK_DGRAM, 0); 249 | if(s < 0) { 250 | perror("socket(IPv4)"); 251 | } 252 | } 253 | 254 | if(ipv6) { 255 | s6 = socket(PF_INET6, SOCK_DGRAM, 0); 256 | if(s6 < 0) { 257 | perror("socket(IPv6)"); 258 | } 259 | } 260 | 261 | if(s < 0 && s6 < 0) { 262 | fprintf(stderr, "Eek!"); 263 | exit(1); 264 | } 265 | 266 | 267 | if(s >= 0) { 268 | sin.sin_port = htons(port); 269 | rc = bind(s, (struct sockaddr*)&sin, sizeof(sin)); 270 | if(rc < 0) { 271 | perror("bind(IPv4)"); 272 | exit(1); 273 | } 274 | } 275 | 276 | if(s6 >= 0) { 277 | int rc; 278 | int val = 1; 279 | 280 | rc = setsockopt(s6, IPPROTO_IPV6, IPV6_V6ONLY, 281 | (char *)&val, sizeof(val)); 282 | if(rc < 0) { 283 | perror("setsockopt(IPV6_V6ONLY)"); 284 | exit(1); 285 | } 286 | 287 | /* BEP-32 mandates that we should bind this socket to one of our 288 | global IPv6 addresses. In this simple example, this only 289 | happens if the user used the -b flag. */ 290 | 291 | sin6.sin6_port = htons(port); 292 | rc = bind(s6, (struct sockaddr*)&sin6, sizeof(sin6)); 293 | if(rc < 0) { 294 | perror("bind(IPv6)"); 295 | exit(1); 296 | } 297 | } 298 | 299 | /* Init the dht. This sets the socket into non-blocking mode. */ 300 | rc = dht_init(s, s6, myid, (unsigned char*)"JC\0\0"); 301 | if(rc < 0) { 302 | perror("dht_init"); 303 | exit(1); 304 | } 305 | 306 | init_signals(); 307 | 308 | /* For bootstrapping, we need an initial list of nodes. This could be 309 | hard-wired, but can also be obtained from the nodes key of a torrent 310 | file, or from the PORT bittorrent message. 311 | 312 | Dht_ping_node is the brutal way of bootstrapping -- it actually 313 | sends a message to the peer. If you're going to bootstrap from 314 | a massive number of nodes (for example because you're restoring from 315 | a dump) and you already know their ids, it's better to use 316 | dht_insert_node. If the ids are incorrect, the DHT will recover. */ 317 | for(i = 0; i < num_bootstrap_nodes; i++) { 318 | dht_ping_node((struct sockaddr*)&bootstrap_nodes[i], 319 | sizeof(bootstrap_nodes[i])); 320 | usleep(random() % 100000); 321 | } 322 | 323 | while(1) { 324 | struct timeval tv; 325 | fd_set readfds; 326 | tv.tv_sec = tosleep; 327 | tv.tv_usec = random() % 1000000; 328 | 329 | FD_ZERO(&readfds); 330 | if(s >= 0) 331 | FD_SET(s, &readfds); 332 | if(s6 >= 0) 333 | FD_SET(s6, &readfds); 334 | rc = select(s > s6 ? s + 1 : s6 + 1, &readfds, NULL, NULL, &tv); 335 | if(rc < 0) { 336 | if(errno != EINTR) { 337 | perror("select"); 338 | sleep(1); 339 | } 340 | } 341 | 342 | if(exiting) 343 | break; 344 | 345 | if(rc > 0) { 346 | fromlen = sizeof(from); 347 | if(s >= 0 && FD_ISSET(s, &readfds)) 348 | rc = recvfrom(s, buf, sizeof(buf) - 1, 0, 349 | (struct sockaddr*)&from, &fromlen); 350 | else if(s6 >= 0 && FD_ISSET(s6, &readfds)) 351 | rc = recvfrom(s6, buf, sizeof(buf) - 1, 0, 352 | (struct sockaddr*)&from, &fromlen); 353 | else 354 | abort(); 355 | } 356 | 357 | if(rc > 0) { 358 | buf[rc] = '\0'; 359 | rc = dht_periodic(buf, rc, (struct sockaddr*)&from, fromlen, 360 | &tosleep, callback, NULL); 361 | } else { 362 | rc = dht_periodic(NULL, 0, NULL, 0, &tosleep, callback, NULL); 363 | } 364 | if(rc < 0) { 365 | if(errno == EINTR) { 366 | continue; 367 | } else { 368 | perror("dht_periodic"); 369 | if(rc == EINVAL || rc == EFAULT) 370 | abort(); 371 | tosleep = 1; 372 | } 373 | } 374 | 375 | /* This is how you trigger a search for a torrent hash. If port 376 | (the second argument) is non-zero, it also performs an announce. 377 | Since peers expire announced data after 30 minutes, it's a good 378 | idea to reannounce every 28 minutes or so. */ 379 | if(searching) { 380 | if(s >= 0) 381 | dht_search(hash, 0, AF_INET, callback, NULL); 382 | if(s6 >= 0) 383 | dht_search(hash, 0, AF_INET6, callback, NULL); 384 | searching = 0; 385 | } 386 | 387 | /* For debugging, or idle curiosity. */ 388 | if(dumping) { 389 | dht_dump_tables(stdout); 390 | dumping = 0; 391 | } 392 | } 393 | 394 | { 395 | struct sockaddr_in sin[500]; 396 | struct sockaddr_in6 sin6[500]; 397 | int num = 500, num6 = 500; 398 | int i; 399 | i = dht_get_nodes(sin, &num, sin6, &num6); 400 | printf("Found %d (%d + %d) good nodes.\n", i, num, num6); 401 | } 402 | 403 | dht_uninit(); 404 | return 0; 405 | 406 | usage: 407 | printf("Usage: dht-example [-q] [-4] [-6] [-i filename] [-b address]...\n" 408 | " port [address port]...\n"); 409 | exit(1); 410 | } 411 | 412 | /* Functions called by the DHT. */ 413 | 414 | int 415 | dht_blacklisted(const struct sockaddr *sa, int salen) 416 | { 417 | return 0; 418 | } 419 | 420 | /* We need to provide a reasonably strong cryptographic hashing function. 421 | Here's how we'd do it if we had RSA's MD5 code. */ 422 | #if 0 423 | void 424 | dht_hash(void *hash_return, int hash_size, 425 | const void *v1, int len1, 426 | const void *v2, int len2, 427 | const void *v3, int len3) 428 | { 429 | static MD5_CTX ctx; 430 | MD5Init(&ctx); 431 | MD5Update(&ctx, v1, len1); 432 | MD5Update(&ctx, v2, len2); 433 | MD5Update(&ctx, v3, len3); 434 | MD5Final(&ctx); 435 | if(hash_size > 16) 436 | memset((char*)hash_return + 16, 0, hash_size - 16); 437 | memcpy(hash_return, ctx.digest, hash_size > 16 ? 16 : hash_size); 438 | } 439 | #else 440 | /* But for this example, we might as well use something weaker. */ 441 | void 442 | dht_hash(void *hash_return, int hash_size, 443 | const void *v1, int len1, 444 | const void *v2, int len2, 445 | const void *v3, int len3) 446 | { 447 | const char *c1 = v1, *c2 = v2, *c3 = v3; 448 | char key[9]; /* crypt is limited to 8 characters */ 449 | int i; 450 | 451 | memset(key, 0, 9); 452 | #define CRYPT_HAPPY(c) ((c % 0x60) + 0x20) 453 | 454 | for(i = 0; i < 2 && i < len1; i++) 455 | key[i] = CRYPT_HAPPY(c1[i]); 456 | for(i = 0; i < 4 && i < len1; i++) 457 | key[2 + i] = CRYPT_HAPPY(c2[i]); 458 | for(i = 0; i < 2 && i < len1; i++) 459 | key[6 + i] = CRYPT_HAPPY(c3[i]); 460 | strncpy(hash_return, crypt(key, "jc"), hash_size); 461 | } 462 | #endif 463 | 464 | int 465 | dht_random_bytes(void *buf, size_t size) 466 | { 467 | int fd, rc, save; 468 | 469 | fd = open("/dev/urandom", O_RDONLY); 470 | if(fd < 0) 471 | return -1; 472 | 473 | rc = read(fd, buf, size); 474 | 475 | save = errno; 476 | close(fd); 477 | errno = save; 478 | 479 | return rc; 480 | } 481 | -------------------------------------------------------------------------------- /dht/dht.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2009-2011 by Juliusz Chroboczek 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in 12 | all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | THE SOFTWARE. 21 | */ 22 | 23 | /* Please, please, please. 24 | 25 | You are welcome to integrate this code in your favourite Bittorrent 26 | client. Please remember, however, that it is meant to be usable by 27 | others, including myself. This means no C++, no relicensing, and no 28 | gratuitious changes to the coding style. And please send back any 29 | improvements to the author. */ 30 | 31 | /* For memmem. */ 32 | #define _GNU_SOURCE 33 | 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | 40 | #if !defined(_WIN32) || defined(__MINGW32__) 41 | #include 42 | #endif 43 | 44 | #ifndef _WIN32 45 | #include 46 | #include 47 | 48 | #include 49 | #include 50 | #include 51 | #include 52 | #else 53 | #ifndef _WIN32_WINNT 54 | #define _WIN32_WINNT 0x0501 /* Windows XP */ 55 | #endif 56 | #ifndef WINVER 57 | #define WINVER _WIN32_WINNT 58 | #endif 59 | #include 60 | #include 61 | #endif 62 | 63 | #include "dht.h" 64 | 65 | #ifndef HAVE_MEMMEM 66 | #ifdef __GLIBC__ 67 | #define HAVE_MEMMEM 68 | #endif 69 | #endif 70 | 71 | #ifndef MSG_CONFIRM 72 | #define MSG_CONFIRM 0 73 | #endif 74 | 75 | #if !defined(_WIN32) || defined(__MINGW32__) 76 | #define dht_gettimeofday(_ts, _tz) gettimeofday((_ts), (_tz)) 77 | #else 78 | extern int dht_gettimeofday(struct timeval *tv, struct timezone *tz); 79 | #endif 80 | 81 | #ifdef _WIN32 82 | 83 | #undef EAFNOSUPPORT 84 | #define EAFNOSUPPORT WSAEAFNOSUPPORT 85 | 86 | static int 87 | set_nonblocking(int fd, int nonblocking) 88 | { 89 | int rc; 90 | 91 | unsigned long mode = !!nonblocking; 92 | rc = ioctlsocket(fd, FIONBIO, &mode); 93 | if(rc != 0) 94 | errno = WSAGetLastError(); 95 | return (rc == 0 ? 0 : -1); 96 | } 97 | 98 | static int 99 | random(void) 100 | { 101 | return rand(); 102 | } 103 | 104 | /* Windows Vista and later already provide the implementation. */ 105 | #if _WIN32_WINNT < 0x0600 106 | extern const char *inet_ntop(int, const void *, char *, socklen_t); 107 | #endif 108 | 109 | #ifdef _MSC_VER 110 | /* There is no snprintf in MSVCRT. */ 111 | #define snprintf _snprintf 112 | #endif 113 | 114 | #else 115 | 116 | static int 117 | set_nonblocking(int fd, int nonblocking) 118 | { 119 | int rc; 120 | rc = fcntl(fd, F_GETFL, 0); 121 | if(rc < 0) 122 | return -1; 123 | 124 | rc = fcntl(fd, F_SETFL, nonblocking?(rc | O_NONBLOCK):(rc & ~O_NONBLOCK)); 125 | if(rc < 0) 126 | return -1; 127 | 128 | return 0; 129 | } 130 | 131 | #endif 132 | 133 | /* We set sin_family to 0 to mark unused slots. */ 134 | #if AF_INET == 0 || AF_INET6 == 0 135 | #error You lose 136 | #endif 137 | 138 | #if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L 139 | /* nothing */ 140 | #elif defined(__GNUC__) 141 | #define inline __inline 142 | #if (__GNUC__ >= 3) 143 | #define restrict __restrict 144 | #else 145 | #define restrict /**/ 146 | #endif 147 | #else 148 | #define inline /**/ 149 | #define restrict /**/ 150 | #endif 151 | 152 | #define MAX(x, y) ((x) >= (y) ? (x) : (y)) 153 | #define MIN(x, y) ((x) <= (y) ? (x) : (y)) 154 | 155 | struct node { 156 | unsigned char id[20]; 157 | struct sockaddr_storage ss; 158 | int sslen; 159 | time_t time; /* time of last message received */ 160 | time_t reply_time; /* time of last correct reply received */ 161 | time_t pinged_time; /* time of last request */ 162 | int pinged; /* how many requests we sent since last reply */ 163 | struct node *next; 164 | }; 165 | 166 | struct bucket { 167 | int af; 168 | unsigned char first[20]; 169 | int count; /* number of nodes */ 170 | time_t time; /* time of last reply in this bucket */ 171 | struct node *nodes; 172 | struct sockaddr_storage cached; /* the address of a likely candidate */ 173 | int cachedlen; 174 | struct bucket *next; 175 | }; 176 | 177 | struct search_node { 178 | unsigned char id[20]; 179 | struct sockaddr_storage ss; 180 | int sslen; 181 | time_t request_time; /* the time of the last unanswered request */ 182 | time_t reply_time; /* the time of the last reply */ 183 | int pinged; 184 | unsigned char token[40]; 185 | int token_len; 186 | int replied; /* whether we have received a reply */ 187 | int acked; /* whether they acked our announcement */ 188 | }; 189 | 190 | /* When performing a search, we search for up to SEARCH_NODES closest nodes 191 | to the destination, and use the additional ones to backtrack if any of 192 | the target 8 turn out to be dead. */ 193 | #define SEARCH_NODES 14 194 | 195 | struct search { 196 | unsigned short tid; 197 | int af; 198 | time_t step_time; /* the time of the last search_step */ 199 | unsigned char id[20]; 200 | unsigned short port; /* 0 for pure searches */ 201 | int done; 202 | struct search_node nodes[SEARCH_NODES]; 203 | int numnodes; 204 | struct search *next; 205 | }; 206 | 207 | struct peer { 208 | time_t time; 209 | unsigned char ip[16]; 210 | unsigned short len; 211 | unsigned short port; 212 | }; 213 | 214 | /* The maximum number of peers we store for a given hash. */ 215 | #ifndef DHT_MAX_PEERS 216 | #define DHT_MAX_PEERS 2048 217 | #endif 218 | 219 | /* The maximum number of hashes we're willing to track. */ 220 | #ifndef DHT_MAX_HASHES 221 | #define DHT_MAX_HASHES 16384 222 | #endif 223 | 224 | /* The maximum number of searches we keep data about. */ 225 | #ifndef DHT_MAX_SEARCHES 226 | #define DHT_MAX_SEARCHES 1024 227 | #endif 228 | 229 | /* The time after which we consider a search to be expirable. */ 230 | #ifndef DHT_SEARCH_EXPIRE_TIME 231 | #define DHT_SEARCH_EXPIRE_TIME (62 * 60) 232 | #endif 233 | 234 | struct storage { 235 | unsigned char id[20]; 236 | int numpeers, maxpeers; 237 | struct peer *peers; 238 | struct storage *next; 239 | }; 240 | 241 | static struct storage * find_storage(const unsigned char *id); 242 | static void flush_search_node(struct search_node *n, struct search *sr); 243 | 244 | static int send_ping(const struct sockaddr *sa, int salen, 245 | const unsigned char *tid, int tid_len); 246 | static int send_pong(const struct sockaddr *sa, int salen, 247 | const unsigned char *tid, int tid_len); 248 | static int send_find_node(const struct sockaddr *sa, int salen, 249 | const unsigned char *tid, int tid_len, 250 | const unsigned char *target, int want, int confirm); 251 | static int send_nodes_peers(const struct sockaddr *sa, int salen, 252 | const unsigned char *tid, int tid_len, 253 | const unsigned char *nodes, int nodes_len, 254 | const unsigned char *nodes6, int nodes6_len, 255 | int af, struct storage *st, 256 | const unsigned char *token, int token_len); 257 | static int send_closest_nodes(const struct sockaddr *sa, int salen, 258 | const unsigned char *tid, int tid_len, 259 | const unsigned char *id, int want, 260 | int af, struct storage *st, 261 | const unsigned char *token, int token_len); 262 | static int send_get_peers(const struct sockaddr *sa, int salen, 263 | unsigned char *tid, int tid_len, 264 | unsigned char *infohash, int want, int confirm); 265 | static int send_announce_peer(const struct sockaddr *sa, int salen, 266 | unsigned char *tid, int tid_len, 267 | unsigned char *infohas, unsigned short port, 268 | unsigned char *token, int token_len, int confirm); 269 | static int send_peer_announced(const struct sockaddr *sa, int salen, 270 | unsigned char *tid, int tid_len); 271 | static int send_error(const struct sockaddr *sa, int salen, 272 | unsigned char *tid, int tid_len, 273 | int code, const char *message); 274 | 275 | #define ERROR 0 276 | #define REPLY 1 277 | #define PING 2 278 | #define FIND_NODE 3 279 | #define GET_PEERS 4 280 | #define ANNOUNCE_PEER 5 281 | 282 | #define WANT4 1 283 | #define WANT6 2 284 | 285 | static int parse_message(const unsigned char *buf, int buflen, 286 | unsigned char *tid_return, int *tid_len, 287 | unsigned char *id_return, 288 | unsigned char *info_hash_return, 289 | unsigned char *target_return, 290 | unsigned short *port_return, 291 | unsigned char *token_return, int *token_len, 292 | unsigned char *nodes_return, int *nodes_len, 293 | unsigned char *nodes6_return, int *nodes6_len, 294 | unsigned char *values_return, int *values_len, 295 | unsigned char *values6_return, int *values6_len, 296 | int *want_return); 297 | 298 | static const unsigned char zeroes[20] = {0}; 299 | static const unsigned char ones[20] = { 300 | 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 301 | 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 302 | 0xFF, 0xFF, 0xFF, 0xFF 303 | }; 304 | static const unsigned char v4prefix[16] = { 305 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFF, 0xFF, 0, 0, 0, 0 306 | }; 307 | 308 | static int dht_socket = -1; 309 | static int dht_socket6 = -1; 310 | 311 | static time_t search_time; 312 | static time_t confirm_nodes_time; 313 | static time_t rotate_secrets_time; 314 | 315 | static unsigned char myid[20]; 316 | static int have_v = 0; 317 | static unsigned char my_v[9]; 318 | static unsigned char secret[8]; 319 | static unsigned char oldsecret[8]; 320 | 321 | static struct bucket *buckets = NULL; 322 | static struct bucket *buckets6 = NULL; 323 | static struct storage *storage; 324 | static int numstorage; 325 | 326 | static struct search *searches = NULL; 327 | static int numsearches; 328 | static unsigned short search_id; 329 | 330 | /* The maximum number of nodes that we snub. There is probably little 331 | reason to increase this value. */ 332 | #ifndef DHT_MAX_BLACKLISTED 333 | #define DHT_MAX_BLACKLISTED 10 334 | #endif 335 | static struct sockaddr_storage blacklist[DHT_MAX_BLACKLISTED]; 336 | int next_blacklisted; 337 | 338 | static struct timeval now; 339 | static time_t mybucket_grow_time, mybucket6_grow_time; 340 | static time_t expire_stuff_time; 341 | 342 | #define MAX_TOKEN_BUCKET_TOKENS 400 343 | static time_t token_bucket_time; 344 | static int token_bucket_tokens; 345 | 346 | FILE *dht_debug = NULL; 347 | 348 | #ifdef __GNUC__ 349 | __attribute__ ((format (printf, 1, 2))) 350 | #endif 351 | static void 352 | debugf(const char *format, ...) 353 | { 354 | va_list args; 355 | va_start(args, format); 356 | if(dht_debug) 357 | vfprintf(dht_debug, format, args); 358 | va_end(args); 359 | if(dht_debug) 360 | fflush(dht_debug); 361 | } 362 | 363 | static void 364 | debug_printable(const unsigned char *buf, int buflen) 365 | { 366 | int i; 367 | if(dht_debug) { 368 | for(i = 0; i < buflen; i++) 369 | putc(buf[i] >= 32 && buf[i] <= 126 ? buf[i] : '.', dht_debug); 370 | } 371 | } 372 | 373 | static void 374 | print_hex(FILE *f, const unsigned char *buf, int buflen) 375 | { 376 | int i; 377 | for(i = 0; i < buflen; i++) 378 | fprintf(f, "%02x", buf[i]); 379 | } 380 | 381 | static int 382 | is_martian(const struct sockaddr *sa) 383 | { 384 | switch(sa->sa_family) { 385 | case AF_INET: { 386 | struct sockaddr_in *sin = (struct sockaddr_in*)sa; 387 | const unsigned char *address = (const unsigned char*)&sin->sin_addr; 388 | return sin->sin_port == 0 || 389 | (address[0] == 0) || 390 | (address[0] == 127) || 391 | ((address[0] & 0xE0) == 0xE0); 392 | } 393 | case AF_INET6: { 394 | struct sockaddr_in6 *sin6 = (struct sockaddr_in6*)sa; 395 | const unsigned char *address = (const unsigned char*)&sin6->sin6_addr; 396 | return sin6->sin6_port == 0 || 397 | (address[0] == 0xFF) || 398 | (address[0] == 0xFE && (address[1] & 0xC0) == 0x80) || 399 | (memcmp(address, zeroes, 15) == 0 && 400 | (address[15] == 0 || address[15] == 1)) || 401 | (memcmp(address, v4prefix, 12) == 0); 402 | } 403 | 404 | default: 405 | return 0; 406 | } 407 | } 408 | 409 | /* Forget about the ``XOR-metric''. An id is just a path from the 410 | root of the tree, so bits are numbered from the start. */ 411 | 412 | static int 413 | id_cmp(const unsigned char *restrict id1, const unsigned char *restrict id2) 414 | { 415 | /* Memcmp is guaranteed to perform an unsigned comparison. */ 416 | return memcmp(id1, id2, 20); 417 | } 418 | 419 | /* Find the lowest 1 bit in an id. */ 420 | static int 421 | lowbit(const unsigned char *id) 422 | { 423 | int i, j; 424 | for(i = 19; i >= 0; i--) 425 | if(id[i] != 0) 426 | break; 427 | 428 | if(i < 0) 429 | return -1; 430 | 431 | for(j = 7; j >= 0; j--) 432 | if((id[i] & (0x80 >> j)) != 0) 433 | break; 434 | 435 | return 8 * i + j; 436 | } 437 | 438 | /* Find how many bits two ids have in common. */ 439 | static int 440 | common_bits(const unsigned char *id1, const unsigned char *id2) 441 | { 442 | int i, j; 443 | unsigned char xor; 444 | for(i = 0; i < 20; i++) { 445 | if(id1[i] != id2[i]) 446 | break; 447 | } 448 | 449 | if(i == 20) 450 | return 160; 451 | 452 | xor = id1[i] ^ id2[i]; 453 | 454 | j = 0; 455 | while((xor & 0x80) == 0) { 456 | xor <<= 1; 457 | j++; 458 | } 459 | 460 | return 8 * i + j; 461 | } 462 | 463 | /* Determine whether id1 or id2 is closer to ref */ 464 | static int 465 | xorcmp(const unsigned char *id1, const unsigned char *id2, 466 | const unsigned char *ref) 467 | { 468 | int i; 469 | for(i = 0; i < 20; i++) { 470 | unsigned char xor1, xor2; 471 | if(id1[i] == id2[i]) 472 | continue; 473 | xor1 = id1[i] ^ ref[i]; 474 | xor2 = id2[i] ^ ref[i]; 475 | if(xor1 < xor2) 476 | return -1; 477 | else 478 | return 1; 479 | } 480 | return 0; 481 | } 482 | 483 | /* We keep buckets in a sorted linked list. A bucket b ranges from 484 | b->first inclusive up to b->next->first exclusive. */ 485 | static int 486 | in_bucket(const unsigned char *id, struct bucket *b) 487 | { 488 | return id_cmp(b->first, id) <= 0 && 489 | (b->next == NULL || id_cmp(id, b->next->first) < 0); 490 | } 491 | 492 | static struct bucket * 493 | find_bucket(unsigned const char *id, int af) 494 | { 495 | struct bucket *b = af == AF_INET ? buckets : buckets6; 496 | 497 | if(b == NULL) 498 | return NULL; 499 | 500 | while(1) { 501 | if(b->next == NULL) 502 | return b; 503 | if(id_cmp(id, b->next->first) < 0) 504 | return b; 505 | b = b->next; 506 | } 507 | } 508 | 509 | static struct bucket * 510 | previous_bucket(struct bucket *b) 511 | { 512 | struct bucket *p = b->af == AF_INET ? buckets : buckets6; 513 | 514 | if(b == p) 515 | return NULL; 516 | 517 | while(1) { 518 | if(p->next == NULL) 519 | return NULL; 520 | if(p->next == b) 521 | return p; 522 | p = p->next; 523 | } 524 | } 525 | 526 | /* Every bucket contains an unordered list of nodes. */ 527 | static struct node * 528 | find_node(const unsigned char *id, int af) 529 | { 530 | struct bucket *b = find_bucket(id, af); 531 | struct node *n; 532 | 533 | if(b == NULL) 534 | return NULL; 535 | 536 | n = b->nodes; 537 | while(n) { 538 | if(id_cmp(n->id, id) == 0) 539 | return n; 540 | n = n->next; 541 | } 542 | return NULL; 543 | } 544 | 545 | /* Return a random node in a bucket. */ 546 | static struct node * 547 | random_node(struct bucket *b) 548 | { 549 | struct node *n; 550 | int nn; 551 | 552 | if(b->count == 0) 553 | return NULL; 554 | 555 | nn = random() % b->count; 556 | n = b->nodes; 557 | while(nn > 0 && n) { 558 | n = n->next; 559 | nn--; 560 | } 561 | return n; 562 | } 563 | 564 | /* Return the middle id of a bucket. */ 565 | static int 566 | bucket_middle(struct bucket *b, unsigned char *id_return) 567 | { 568 | int bit1 = lowbit(b->first); 569 | int bit2 = b->next ? lowbit(b->next->first) : -1; 570 | int bit = MAX(bit1, bit2) + 1; 571 | 572 | if(bit >= 160) 573 | return -1; 574 | 575 | memcpy(id_return, b->first, 20); 576 | id_return[bit / 8] |= (0x80 >> (bit % 8)); 577 | return 1; 578 | } 579 | 580 | /* Return a random id within a bucket. */ 581 | static int 582 | bucket_random(struct bucket *b, unsigned char *id_return) 583 | { 584 | int bit1 = lowbit(b->first); 585 | int bit2 = b->next ? lowbit(b->next->first) : -1; 586 | int bit = MAX(bit1, bit2) + 1; 587 | int i; 588 | 589 | if(bit >= 160) { 590 | memcpy(id_return, b->first, 20); 591 | return 1; 592 | } 593 | 594 | memcpy(id_return, b->first, bit / 8); 595 | id_return[bit / 8] = b->first[bit / 8] & (0xFF00 >> (bit % 8)); 596 | id_return[bit / 8] |= random() & 0xFF >> (bit % 8); 597 | for(i = bit / 8 + 1; i < 20; i++) 598 | id_return[i] = random() & 0xFF; 599 | return 1; 600 | } 601 | 602 | /* Insert a new node into a bucket. */ 603 | static struct node * 604 | insert_node(struct node *node) 605 | { 606 | struct bucket *b = find_bucket(node->id, node->ss.ss_family); 607 | 608 | if(b == NULL) 609 | return NULL; 610 | 611 | node->next = b->nodes; 612 | b->nodes = node; 613 | b->count++; 614 | return node; 615 | } 616 | 617 | /* This is our definition of a known-good node. */ 618 | static int 619 | node_good(struct node *node) 620 | { 621 | return 622 | node->pinged <= 2 && 623 | node->reply_time >= now.tv_sec - 7200 && 624 | node->time >= now.tv_sec - 900; 625 | } 626 | 627 | /* Our transaction-ids are 4-bytes long, with the first two bytes identi- 628 | fying the kind of request, and the remaining two a sequence number in 629 | host order. */ 630 | 631 | static void 632 | make_tid(unsigned char *tid_return, const char *prefix, unsigned short seqno) 633 | { 634 | tid_return[0] = prefix[0] & 0xFF; 635 | tid_return[1] = prefix[1] & 0xFF; 636 | memcpy(tid_return + 2, &seqno, 2); 637 | } 638 | 639 | static int 640 | tid_match(const unsigned char *tid, const char *prefix, 641 | unsigned short *seqno_return) 642 | { 643 | if(tid[0] == (prefix[0] & 0xFF) && tid[1] == (prefix[1] & 0xFF)) { 644 | if(seqno_return) 645 | memcpy(seqno_return, tid + 2, 2); 646 | return 1; 647 | } else 648 | return 0; 649 | } 650 | 651 | /* Every bucket caches the address of a likely node. Ping it. */ 652 | static int 653 | send_cached_ping(struct bucket *b) 654 | { 655 | unsigned char tid[4]; 656 | int rc; 657 | /* We set family to 0 when there's no cached node. */ 658 | if(b->cached.ss_family == 0) 659 | return 0; 660 | 661 | debugf("Sending ping to cached node.\n"); 662 | make_tid(tid, "pn", 0); 663 | rc = send_ping((struct sockaddr*)&b->cached, b->cachedlen, tid, 4); 664 | b->cached.ss_family = 0; 665 | b->cachedlen = 0; 666 | return rc; 667 | } 668 | 669 | /* Called whenever we send a request to a node, increases the ping count 670 | and, if that reaches 3, sends a ping to a new candidate. */ 671 | static void 672 | pinged(struct node *n, struct bucket *b) 673 | { 674 | n->pinged++; 675 | n->pinged_time = now.tv_sec; 676 | if(n->pinged >= 3) 677 | send_cached_ping(b ? b : find_bucket(n->id, n->ss.ss_family)); 678 | } 679 | 680 | /* The internal blacklist is an LRU cache of nodes that have sent 681 | incorrect messages. */ 682 | static void 683 | blacklist_node(const unsigned char *id, const struct sockaddr *sa, int salen) 684 | { 685 | int i; 686 | 687 | debugf("Blacklisting broken node.\n"); 688 | 689 | if(id) { 690 | struct node *n; 691 | struct search *sr; 692 | /* Make the node easy to discard. */ 693 | n = find_node(id, sa->sa_family); 694 | if(n) { 695 | n->pinged = 3; 696 | pinged(n, NULL); 697 | } 698 | /* Discard it from any searches in progress. */ 699 | sr = searches; 700 | while(sr) { 701 | for(i = 0; i < sr->numnodes; i++) 702 | if(id_cmp(sr->nodes[i].id, id) == 0) 703 | flush_search_node(&sr->nodes[i], sr); 704 | sr = sr->next; 705 | } 706 | } 707 | /* And make sure we don't hear from it again. */ 708 | memcpy(&blacklist[next_blacklisted], sa, salen); 709 | next_blacklisted = (next_blacklisted + 1) % DHT_MAX_BLACKLISTED; 710 | } 711 | 712 | static int 713 | node_blacklisted(const struct sockaddr *sa, int salen) 714 | { 715 | int i; 716 | 717 | if((unsigned)salen > sizeof(struct sockaddr_storage)) 718 | abort(); 719 | 720 | if(dht_blacklisted(sa, salen)) 721 | return 1; 722 | 723 | for(i = 0; i < DHT_MAX_BLACKLISTED; i++) { 724 | if(memcmp(&blacklist[i], sa, salen) == 0) 725 | return 1; 726 | } 727 | 728 | return 0; 729 | } 730 | 731 | /* Split a bucket into two equal parts. */ 732 | static struct bucket * 733 | split_bucket(struct bucket *b) 734 | { 735 | struct bucket *new; 736 | struct node *nodes; 737 | int rc; 738 | unsigned char new_id[20]; 739 | 740 | rc = bucket_middle(b, new_id); 741 | if(rc < 0) 742 | return NULL; 743 | 744 | new = calloc(1, sizeof(struct bucket)); 745 | if(new == NULL) 746 | return NULL; 747 | 748 | new->af = b->af; 749 | 750 | send_cached_ping(b); 751 | 752 | memcpy(new->first, new_id, 20); 753 | new->time = b->time; 754 | 755 | nodes = b->nodes; 756 | b->nodes = NULL; 757 | b->count = 0; 758 | new->next = b->next; 759 | b->next = new; 760 | while(nodes) { 761 | struct node *n; 762 | n = nodes; 763 | nodes = nodes->next; 764 | insert_node(n); 765 | } 766 | return b; 767 | } 768 | 769 | /* We just learnt about a node, not necessarily a new one. Confirm is 1 if 770 | the node sent a message, 2 if it sent us a reply. */ 771 | static struct node * 772 | new_node(const unsigned char *id, const struct sockaddr *sa, int salen, 773 | int confirm) 774 | { 775 | struct bucket *b = find_bucket(id, sa->sa_family); 776 | struct node *n; 777 | int mybucket, split; 778 | 779 | if(b == NULL) 780 | return NULL; 781 | 782 | if(id_cmp(id, myid) == 0) 783 | return NULL; 784 | 785 | if(is_martian(sa) || node_blacklisted(sa, salen)) 786 | return NULL; 787 | 788 | mybucket = in_bucket(myid, b); 789 | 790 | if(confirm == 2) 791 | b->time = now.tv_sec; 792 | 793 | n = b->nodes; 794 | while(n) { 795 | if(id_cmp(n->id, id) == 0) { 796 | if(confirm || n->time < now.tv_sec - 15 * 60) { 797 | /* Known node. Update stuff. */ 798 | memcpy((struct sockaddr*)&n->ss, sa, salen); 799 | if(confirm) 800 | n->time = now.tv_sec; 801 | if(confirm >= 2) { 802 | n->reply_time = now.tv_sec; 803 | n->pinged = 0; 804 | n->pinged_time = 0; 805 | } 806 | } 807 | return n; 808 | } 809 | n = n->next; 810 | } 811 | 812 | /* New node. */ 813 | 814 | if(mybucket) { 815 | if(sa->sa_family == AF_INET) 816 | mybucket_grow_time = now.tv_sec; 817 | else 818 | mybucket6_grow_time = now.tv_sec; 819 | } 820 | 821 | /* First, try to get rid of a known-bad node. */ 822 | n = b->nodes; 823 | while(n) { 824 | if(n->pinged >= 3 && n->pinged_time < now.tv_sec - 15) { 825 | memcpy(n->id, id, 20); 826 | memcpy((struct sockaddr*)&n->ss, sa, salen); 827 | n->time = confirm ? now.tv_sec : 0; 828 | n->reply_time = confirm >= 2 ? now.tv_sec : 0; 829 | n->pinged_time = 0; 830 | n->pinged = 0; 831 | return n; 832 | } 833 | n = n->next; 834 | } 835 | 836 | if(b->count >= 8) { 837 | /* Bucket full. Ping a dubious node */ 838 | int dubious = 0; 839 | n = b->nodes; 840 | while(n) { 841 | /* Pick the first dubious node that we haven't pinged in the 842 | last 15 seconds. This gives nodes the time to reply, but 843 | tends to concentrate on the same nodes, so that we get rid 844 | of bad nodes fast. */ 845 | if(!node_good(n)) { 846 | dubious = 1; 847 | if(n->pinged_time < now.tv_sec - 15) { 848 | unsigned char tid[4]; 849 | debugf("Sending ping to dubious node.\n"); 850 | make_tid(tid, "pn", 0); 851 | send_ping((struct sockaddr*)&n->ss, n->sslen, 852 | tid, 4); 853 | n->pinged++; 854 | n->pinged_time = now.tv_sec; 855 | break; 856 | } 857 | } 858 | n = n->next; 859 | } 860 | 861 | split = 0; 862 | if(mybucket) { 863 | if(!dubious) 864 | split = 1; 865 | /* If there's only one bucket, split eagerly. This is 866 | incorrect unless there's more than 8 nodes in the DHT. */ 867 | else if(b->af == AF_INET && buckets->next == NULL) 868 | split = 1; 869 | else if(b->af == AF_INET6 && buckets6->next == NULL) 870 | split = 1; 871 | } 872 | 873 | if(split) { 874 | debugf("Splitting.\n"); 875 | b = split_bucket(b); 876 | return new_node(id, sa, salen, confirm); 877 | } 878 | 879 | /* No space for this node. Cache it away for later. */ 880 | if(confirm || b->cached.ss_family == 0) { 881 | memcpy(&b->cached, sa, salen); 882 | b->cachedlen = salen; 883 | } 884 | 885 | return NULL; 886 | } 887 | 888 | /* Create a new node. */ 889 | n = calloc(1, sizeof(struct node)); 890 | if(n == NULL) 891 | return NULL; 892 | memcpy(n->id, id, 20); 893 | memcpy(&n->ss, sa, salen); 894 | n->sslen = salen; 895 | n->time = confirm ? now.tv_sec : 0; 896 | n->reply_time = confirm >= 2 ? now.tv_sec : 0; 897 | n->next = b->nodes; 898 | b->nodes = n; 899 | b->count++; 900 | return n; 901 | } 902 | 903 | /* Called periodically to purge known-bad nodes. Note that we're very 904 | conservative here: broken nodes in the table don't do much harm, we'll 905 | recover as soon as we find better ones. */ 906 | static int 907 | expire_buckets(struct bucket *b) 908 | { 909 | while(b) { 910 | struct node *n, *p; 911 | int changed = 0; 912 | 913 | while(b->nodes && b->nodes->pinged >= 4) { 914 | n = b->nodes; 915 | b->nodes = n->next; 916 | b->count--; 917 | changed = 1; 918 | free(n); 919 | } 920 | 921 | p = b->nodes; 922 | while(p) { 923 | while(p->next && p->next->pinged >= 4) { 924 | n = p->next; 925 | p->next = n->next; 926 | b->count--; 927 | changed = 1; 928 | free(n); 929 | } 930 | p = p->next; 931 | } 932 | 933 | if(changed) 934 | send_cached_ping(b); 935 | 936 | b = b->next; 937 | } 938 | expire_stuff_time = now.tv_sec + 120 + random() % 240; 939 | return 1; 940 | } 941 | 942 | /* While a search is in progress, we don't necessarily keep the nodes being 943 | walked in the main bucket table. A search in progress is identified by 944 | a unique transaction id, a short (and hence small enough to fit in the 945 | transaction id of the protocol packets). */ 946 | 947 | static struct search * 948 | find_search(unsigned short tid, int af) 949 | { 950 | struct search *sr = searches; 951 | while(sr) { 952 | if(sr->tid == tid && sr->af == af) 953 | return sr; 954 | sr = sr->next; 955 | } 956 | return NULL; 957 | } 958 | 959 | /* A search contains a list of nodes, sorted by decreasing distance to the 960 | target. We just got a new candidate, insert it at the right spot or 961 | discard it. */ 962 | 963 | static int 964 | insert_search_node(unsigned char *id, 965 | const struct sockaddr *sa, int salen, 966 | struct search *sr, int replied, 967 | unsigned char *token, int token_len) 968 | { 969 | struct search_node *n; 970 | int i, j; 971 | 972 | if(sa->sa_family != sr->af) { 973 | debugf("Attempted to insert node in the wrong family.\n"); 974 | return 0; 975 | } 976 | 977 | for(i = 0; i < sr->numnodes; i++) { 978 | if(id_cmp(id, sr->nodes[i].id) == 0) { 979 | n = &sr->nodes[i]; 980 | goto found; 981 | } 982 | if(xorcmp(id, sr->nodes[i].id, sr->id) < 0) 983 | break; 984 | } 985 | 986 | if(i == SEARCH_NODES) 987 | return 0; 988 | 989 | if(sr->numnodes < SEARCH_NODES) 990 | sr->numnodes++; 991 | 992 | for(j = sr->numnodes - 1; j > i; j--) { 993 | sr->nodes[j] = sr->nodes[j - 1]; 994 | } 995 | 996 | n = &sr->nodes[i]; 997 | 998 | memset(n, 0, sizeof(struct search_node)); 999 | memcpy(n->id, id, 20); 1000 | 1001 | found: 1002 | memcpy(&n->ss, sa, salen); 1003 | n->sslen = salen; 1004 | 1005 | if(replied) { 1006 | n->replied = 1; 1007 | n->reply_time = now.tv_sec; 1008 | n->request_time = 0; 1009 | n->pinged = 0; 1010 | } 1011 | if(token) { 1012 | if(token_len >= 40) { 1013 | debugf("Eek! Overlong token.\n"); 1014 | } else { 1015 | memcpy(n->token, token, token_len); 1016 | n->token_len = token_len; 1017 | } 1018 | } 1019 | 1020 | return 1; 1021 | } 1022 | 1023 | static void 1024 | flush_search_node(struct search_node *n, struct search *sr) 1025 | { 1026 | int i = n - sr->nodes, j; 1027 | for(j = i; j < sr->numnodes - 1; j++) 1028 | sr->nodes[j] = sr->nodes[j + 1]; 1029 | sr->numnodes--; 1030 | } 1031 | 1032 | static void 1033 | expire_searches(void) 1034 | { 1035 | struct search *sr = searches, *previous = NULL; 1036 | 1037 | while(sr) { 1038 | struct search *next = sr->next; 1039 | if(sr->step_time < now.tv_sec - DHT_SEARCH_EXPIRE_TIME) { 1040 | if(previous) 1041 | previous->next = next; 1042 | else 1043 | searches = next; 1044 | free(sr); 1045 | numsearches--; 1046 | } else { 1047 | previous = sr; 1048 | } 1049 | sr = next; 1050 | } 1051 | } 1052 | 1053 | /* This must always return 0 or 1, never -1, not even on failure (see below). */ 1054 | static int 1055 | search_send_get_peers(struct search *sr, struct search_node *n) 1056 | { 1057 | struct node *node; 1058 | unsigned char tid[4]; 1059 | 1060 | if(n == NULL) { 1061 | int i; 1062 | for(i = 0; i < sr->numnodes; i++) { 1063 | if(sr->nodes[i].pinged < 3 && !sr->nodes[i].replied && 1064 | sr->nodes[i].request_time < now.tv_sec - 15) 1065 | n = &sr->nodes[i]; 1066 | } 1067 | } 1068 | 1069 | if(!n || n->pinged >= 3 || n->replied || 1070 | n->request_time >= now.tv_sec - 15) 1071 | return 0; 1072 | 1073 | debugf("Sending get_peers.\n"); 1074 | make_tid(tid, "gp", sr->tid); 1075 | send_get_peers((struct sockaddr*)&n->ss, n->sslen, tid, 4, sr->id, -1, 1076 | n->reply_time >= now.tv_sec - 15); 1077 | n->pinged++; 1078 | n->request_time = now.tv_sec; 1079 | /* If the node happens to be in our main routing table, mark it 1080 | as pinged. */ 1081 | node = find_node(n->id, n->ss.ss_family); 1082 | if(node) pinged(node, NULL); 1083 | return 1; 1084 | } 1085 | 1086 | /* When a search is in progress, we periodically call search_step to send 1087 | further requests. */ 1088 | static void 1089 | search_step(struct search *sr, dht_callback *callback, void *closure) 1090 | { 1091 | int i, j; 1092 | int all_done = 1; 1093 | 1094 | /* Check if the first 8 live nodes have replied. */ 1095 | j = 0; 1096 | for(i = 0; i < sr->numnodes && j < 8; i++) { 1097 | struct search_node *n = &sr->nodes[i]; 1098 | if(n->pinged >= 3) 1099 | continue; 1100 | if(!n->replied) { 1101 | all_done = 0; 1102 | break; 1103 | } 1104 | j++; 1105 | } 1106 | 1107 | if(all_done) { 1108 | if(sr->port == 0) { 1109 | goto done; 1110 | } else { 1111 | int all_acked = 1; 1112 | j = 0; 1113 | for(i = 0; i < sr->numnodes && j < 8; i++) { 1114 | struct search_node *n = &sr->nodes[i]; 1115 | struct node *node; 1116 | unsigned char tid[4]; 1117 | if(n->pinged >= 3) 1118 | continue; 1119 | /* A proposed extension to the protocol consists in 1120 | omitting the token when storage tables are full. While 1121 | I don't think this makes a lot of sense -- just sending 1122 | a positive reply is just as good --, let's deal with it. */ 1123 | if(n->token_len == 0) 1124 | n->acked = 1; 1125 | if(!n->acked) { 1126 | all_acked = 0; 1127 | debugf("Sending announce_peer.\n"); 1128 | make_tid(tid, "ap", sr->tid); 1129 | send_announce_peer((struct sockaddr*)&n->ss, 1130 | sizeof(struct sockaddr_storage), 1131 | tid, 4, sr->id, sr->port, 1132 | n->token, n->token_len, 1133 | n->reply_time >= now.tv_sec - 15); 1134 | n->pinged++; 1135 | n->request_time = now.tv_sec; 1136 | node = find_node(n->id, n->ss.ss_family); 1137 | if(node) pinged(node, NULL); 1138 | } 1139 | j++; 1140 | } 1141 | if(all_acked) 1142 | goto done; 1143 | } 1144 | sr->step_time = now.tv_sec; 1145 | return; 1146 | } 1147 | 1148 | if(sr->step_time + 15 >= now.tv_sec) 1149 | return; 1150 | 1151 | j = 0; 1152 | for(i = 0; i < sr->numnodes; i++) { 1153 | j += search_send_get_peers(sr, &sr->nodes[i]); 1154 | if(j >= 3) 1155 | break; 1156 | } 1157 | sr->step_time = now.tv_sec; 1158 | return; 1159 | 1160 | done: 1161 | sr->done = 1; 1162 | if(callback) 1163 | (*callback)(closure, 1164 | sr->af == AF_INET ? 1165 | DHT_EVENT_SEARCH_DONE : DHT_EVENT_SEARCH_DONE6, 1166 | sr->id, NULL, 0); 1167 | sr->step_time = now.tv_sec; 1168 | } 1169 | 1170 | static struct search * 1171 | new_search(void) 1172 | { 1173 | struct search *sr, *oldest = NULL; 1174 | 1175 | /* Find the oldest done search */ 1176 | sr = searches; 1177 | while(sr) { 1178 | if(sr->done && 1179 | (oldest == NULL || oldest->step_time > sr->step_time)) 1180 | oldest = sr; 1181 | sr = sr->next; 1182 | } 1183 | 1184 | /* The oldest slot is expired. */ 1185 | if(oldest && oldest->step_time < now.tv_sec - DHT_SEARCH_EXPIRE_TIME) 1186 | return oldest; 1187 | 1188 | /* Allocate a new slot. */ 1189 | if(numsearches < DHT_MAX_SEARCHES) { 1190 | sr = calloc(1, sizeof(struct search)); 1191 | if(sr != NULL) { 1192 | sr->next = searches; 1193 | searches = sr; 1194 | numsearches++; 1195 | return sr; 1196 | } 1197 | } 1198 | 1199 | /* Oh, well, never mind. Reuse the oldest slot. */ 1200 | return oldest; 1201 | } 1202 | 1203 | /* Insert the contents of a bucket into a search structure. */ 1204 | static void 1205 | insert_search_bucket(struct bucket *b, struct search *sr) 1206 | { 1207 | struct node *n; 1208 | n = b->nodes; 1209 | while(n) { 1210 | insert_search_node(n->id, (struct sockaddr*)&n->ss, n->sslen, 1211 | sr, 0, NULL, 0); 1212 | n = n->next; 1213 | } 1214 | } 1215 | 1216 | /* Start a search. If port is non-zero, perform an announce when the 1217 | search is complete. */ 1218 | int 1219 | dht_search(const unsigned char *id, int port, int af, 1220 | dht_callback *callback, void *closure) 1221 | { 1222 | struct search *sr; 1223 | struct storage *st; 1224 | struct bucket *b = find_bucket(id, af); 1225 | 1226 | if(b == NULL) { 1227 | errno = EAFNOSUPPORT; 1228 | return -1; 1229 | } 1230 | 1231 | /* Try to answer this search locally. In a fully grown DHT this 1232 | is very unlikely, but people are running modified versions of 1233 | this code in private DHTs with very few nodes. What's wrong 1234 | with flooding? */ 1235 | if(callback) { 1236 | st = find_storage(id); 1237 | if(st) { 1238 | unsigned short swapped; 1239 | unsigned char buf[18]; 1240 | int i; 1241 | 1242 | debugf("Found local data (%d peers).\n", st->numpeers); 1243 | 1244 | for(i = 0; i < st->numpeers; i++) { 1245 | swapped = htons(st->peers[i].port); 1246 | if(st->peers[i].len == 4) { 1247 | memcpy(buf, st->peers[i].ip, 4); 1248 | memcpy(buf + 4, &swapped, 2); 1249 | (*callback)(closure, DHT_EVENT_VALUES, id, 1250 | (void*)buf, 6); 1251 | } else if(st->peers[i].len == 16) { 1252 | memcpy(buf, st->peers[i].ip, 16); 1253 | memcpy(buf + 16, &swapped, 2); 1254 | (*callback)(closure, DHT_EVENT_VALUES6, id, 1255 | (void*)buf, 18); 1256 | } 1257 | } 1258 | } 1259 | } 1260 | 1261 | sr = searches; 1262 | while(sr) { 1263 | if(sr->af == af && id_cmp(sr->id, id) == 0) 1264 | break; 1265 | sr = sr->next; 1266 | } 1267 | 1268 | if(sr) { 1269 | /* We're reusing data from an old search. Reusing the same tid 1270 | means that we can merge replies for both searches. */ 1271 | int i; 1272 | sr->done = 0; 1273 | again: 1274 | for(i = 0; i < sr->numnodes; i++) { 1275 | struct search_node *n; 1276 | n = &sr->nodes[i]; 1277 | /* Discard any doubtful nodes. */ 1278 | if(n->pinged >= 3 || n->reply_time < now.tv_sec - 7200) { 1279 | flush_search_node(n, sr); 1280 | goto again; 1281 | } 1282 | n->pinged = 0; 1283 | n->token_len = 0; 1284 | n->replied = 0; 1285 | n->acked = 0; 1286 | } 1287 | } else { 1288 | sr = new_search(); 1289 | if(sr == NULL) { 1290 | errno = ENOSPC; 1291 | return -1; 1292 | } 1293 | sr->af = af; 1294 | sr->tid = search_id++; 1295 | sr->step_time = 0; 1296 | memcpy(sr->id, id, 20); 1297 | sr->done = 0; 1298 | sr->numnodes = 0; 1299 | } 1300 | 1301 | sr->port = port; 1302 | 1303 | insert_search_bucket(b, sr); 1304 | 1305 | if(sr->numnodes < SEARCH_NODES) { 1306 | struct bucket *p = previous_bucket(b); 1307 | if(b->next) 1308 | insert_search_bucket(b->next, sr); 1309 | if(p) 1310 | insert_search_bucket(p, sr); 1311 | } 1312 | if(sr->numnodes < SEARCH_NODES) 1313 | insert_search_bucket(find_bucket(myid, af), sr); 1314 | 1315 | search_step(sr, callback, closure); 1316 | search_time = now.tv_sec; 1317 | return 1; 1318 | } 1319 | 1320 | /* A struct storage stores all the stored peer addresses for a given info 1321 | hash. */ 1322 | 1323 | static struct storage * 1324 | find_storage(const unsigned char *id) 1325 | { 1326 | struct storage *st = storage; 1327 | 1328 | while(st) { 1329 | if(id_cmp(id, st->id) == 0) 1330 | break; 1331 | st = st->next; 1332 | } 1333 | return st; 1334 | } 1335 | 1336 | static int 1337 | storage_store(const unsigned char *id, 1338 | const struct sockaddr *sa, unsigned short port) 1339 | { 1340 | int i, len; 1341 | struct storage *st; 1342 | unsigned char *ip; 1343 | 1344 | if(sa->sa_family == AF_INET) { 1345 | struct sockaddr_in *sin = (struct sockaddr_in*)sa; 1346 | ip = (unsigned char*)&sin->sin_addr; 1347 | len = 4; 1348 | } else if(sa->sa_family == AF_INET6) { 1349 | struct sockaddr_in6 *sin6 = (struct sockaddr_in6*)sa; 1350 | ip = (unsigned char*)&sin6->sin6_addr; 1351 | len = 16; 1352 | } else { 1353 | return -1; 1354 | } 1355 | 1356 | st = find_storage(id); 1357 | 1358 | if(st == NULL) { 1359 | if(numstorage >= DHT_MAX_HASHES) 1360 | return -1; 1361 | st = calloc(1, sizeof(struct storage)); 1362 | if(st == NULL) return -1; 1363 | memcpy(st->id, id, 20); 1364 | st->next = storage; 1365 | storage = st; 1366 | numstorage++; 1367 | } 1368 | 1369 | for(i = 0; i < st->numpeers; i++) { 1370 | if(st->peers[i].port == port && st->peers[i].len == len && 1371 | memcmp(st->peers[i].ip, ip, len) == 0) 1372 | break; 1373 | } 1374 | 1375 | if(i < st->numpeers) { 1376 | /* Already there, only need to refresh */ 1377 | st->peers[i].time = now.tv_sec; 1378 | return 0; 1379 | } else { 1380 | struct peer *p; 1381 | if(i >= st->maxpeers) { 1382 | /* Need to expand the array. */ 1383 | struct peer *new_peers; 1384 | int n; 1385 | if(st->maxpeers >= DHT_MAX_PEERS) 1386 | return 0; 1387 | n = st->maxpeers == 0 ? 2 : 2 * st->maxpeers; 1388 | n = MIN(n, DHT_MAX_PEERS); 1389 | new_peers = realloc(st->peers, n * sizeof(struct peer)); 1390 | if(new_peers == NULL) 1391 | return -1; 1392 | st->peers = new_peers; 1393 | st->maxpeers = n; 1394 | } 1395 | p = &st->peers[st->numpeers++]; 1396 | p->time = now.tv_sec; 1397 | p->len = len; 1398 | memcpy(p->ip, ip, len); 1399 | p->port = port; 1400 | return 1; 1401 | } 1402 | } 1403 | 1404 | static int 1405 | expire_storage(void) 1406 | { 1407 | struct storage *st = storage, *previous = NULL; 1408 | while(st) { 1409 | int i = 0; 1410 | while(i < st->numpeers) { 1411 | if(st->peers[i].time < now.tv_sec - 32 * 60) { 1412 | if(i != st->numpeers - 1) 1413 | st->peers[i] = st->peers[st->numpeers - 1]; 1414 | st->numpeers--; 1415 | } else { 1416 | i++; 1417 | } 1418 | } 1419 | 1420 | if(st->numpeers == 0) { 1421 | free(st->peers); 1422 | if(previous) 1423 | previous->next = st->next; 1424 | else 1425 | storage = st->next; 1426 | free(st); 1427 | if(previous) 1428 | st = previous->next; 1429 | else 1430 | st = storage; 1431 | numstorage--; 1432 | if(numstorage < 0) { 1433 | debugf("Eek... numstorage became negative.\n"); 1434 | numstorage = 0; 1435 | } 1436 | } else { 1437 | previous = st; 1438 | st = st->next; 1439 | } 1440 | } 1441 | return 1; 1442 | } 1443 | 1444 | static int 1445 | rotate_secrets(void) 1446 | { 1447 | int rc; 1448 | 1449 | rotate_secrets_time = now.tv_sec + 900 + random() % 1800; 1450 | 1451 | memcpy(oldsecret, secret, sizeof(secret)); 1452 | rc = dht_random_bytes(secret, sizeof(secret)); 1453 | 1454 | if(rc < 0) 1455 | return -1; 1456 | 1457 | return 1; 1458 | } 1459 | 1460 | #ifndef TOKEN_SIZE 1461 | #define TOKEN_SIZE 8 1462 | #endif 1463 | 1464 | static void 1465 | make_token(const struct sockaddr *sa, int old, unsigned char *token_return) 1466 | { 1467 | void *ip; 1468 | int iplen; 1469 | unsigned short port; 1470 | 1471 | if(sa->sa_family == AF_INET) { 1472 | struct sockaddr_in *sin = (struct sockaddr_in*)sa; 1473 | ip = &sin->sin_addr; 1474 | iplen = 4; 1475 | port = htons(sin->sin_port); 1476 | } else if(sa->sa_family == AF_INET6) { 1477 | struct sockaddr_in6 *sin6 = (struct sockaddr_in6*)sa; 1478 | ip = &sin6->sin6_addr; 1479 | iplen = 16; 1480 | port = htons(sin6->sin6_port); 1481 | } else { 1482 | abort(); 1483 | } 1484 | 1485 | dht_hash(token_return, TOKEN_SIZE, 1486 | old ? oldsecret : secret, sizeof(secret), 1487 | ip, iplen, (unsigned char*)&port, 2); 1488 | } 1489 | static int 1490 | token_match(const unsigned char *token, int token_len, 1491 | const struct sockaddr *sa) 1492 | { 1493 | unsigned char t[TOKEN_SIZE]; 1494 | if(token_len != TOKEN_SIZE) 1495 | return 0; 1496 | make_token(sa, 0, t); 1497 | if(memcmp(t, token, TOKEN_SIZE) == 0) 1498 | return 1; 1499 | make_token(sa, 1, t); 1500 | if(memcmp(t, token, TOKEN_SIZE) == 0) 1501 | return 1; 1502 | return 0; 1503 | } 1504 | 1505 | int 1506 | dht_nodes(int af, int *good_return, int *dubious_return, int *cached_return, 1507 | int *incoming_return) 1508 | { 1509 | int good = 0, dubious = 0, cached = 0, incoming = 0; 1510 | struct bucket *b = af == AF_INET ? buckets : buckets6; 1511 | 1512 | while(b) { 1513 | struct node *n = b->nodes; 1514 | while(n) { 1515 | if(node_good(n)) { 1516 | good++; 1517 | if(n->time > n->reply_time) 1518 | incoming++; 1519 | } else { 1520 | dubious++; 1521 | } 1522 | n = n->next; 1523 | } 1524 | if(b->cached.ss_family > 0) 1525 | cached++; 1526 | b = b->next; 1527 | } 1528 | if(good_return) 1529 | *good_return = good; 1530 | if(dubious_return) 1531 | *dubious_return = dubious; 1532 | if(cached_return) 1533 | *cached_return = cached; 1534 | if(incoming_return) 1535 | *incoming_return = incoming; 1536 | return good + dubious; 1537 | } 1538 | 1539 | static void 1540 | dump_bucket(FILE *f, struct bucket *b) 1541 | { 1542 | struct node *n = b->nodes; 1543 | fprintf(f, "Bucket "); 1544 | print_hex(f, b->first, 20); 1545 | fprintf(f, " count %d age %d%s%s:\n", 1546 | b->count, (int)(now.tv_sec - b->time), 1547 | in_bucket(myid, b) ? " (mine)" : "", 1548 | b->cached.ss_family ? " (cached)" : ""); 1549 | while(n) { 1550 | char buf[512]; 1551 | unsigned short port; 1552 | fprintf(f, " Node "); 1553 | print_hex(f, n->id, 20); 1554 | if(n->ss.ss_family == AF_INET) { 1555 | struct sockaddr_in *sin = (struct sockaddr_in*)&n->ss; 1556 | inet_ntop(AF_INET, &sin->sin_addr, buf, 512); 1557 | port = ntohs(sin->sin_port); 1558 | } else if(n->ss.ss_family == AF_INET6) { 1559 | struct sockaddr_in6 *sin6 = (struct sockaddr_in6*)&n->ss; 1560 | inet_ntop(AF_INET6, &sin6->sin6_addr, buf, 512); 1561 | port = ntohs(sin6->sin6_port); 1562 | } else { 1563 | snprintf(buf, 512, "unknown(%d)", n->ss.ss_family); 1564 | port = 0; 1565 | } 1566 | 1567 | if(n->ss.ss_family == AF_INET6) 1568 | fprintf(f, " [%s]:%d ", buf, port); 1569 | else 1570 | fprintf(f, " %s:%d ", buf, port); 1571 | if(n->time != n->reply_time) 1572 | fprintf(f, "age %ld, %ld", 1573 | (long)(now.tv_sec - n->time), 1574 | (long)(now.tv_sec - n->reply_time)); 1575 | else 1576 | fprintf(f, "age %ld", (long)(now.tv_sec - n->time)); 1577 | if(n->pinged) 1578 | fprintf(f, " (%d)", n->pinged); 1579 | if(node_good(n)) 1580 | fprintf(f, " (good)"); 1581 | fprintf(f, "\n"); 1582 | n = n->next; 1583 | } 1584 | 1585 | } 1586 | 1587 | void 1588 | dht_dump_tables(FILE *f) 1589 | { 1590 | int i; 1591 | struct bucket *b; 1592 | struct storage *st = storage; 1593 | struct search *sr = searches; 1594 | 1595 | fprintf(f, "My id "); 1596 | print_hex(f, myid, 20); 1597 | fprintf(f, "\n"); 1598 | 1599 | b = buckets; 1600 | while(b) { 1601 | dump_bucket(f, b); 1602 | b = b->next; 1603 | } 1604 | 1605 | fprintf(f, "\n"); 1606 | 1607 | b = buckets6; 1608 | while(b) { 1609 | dump_bucket(f, b); 1610 | b = b->next; 1611 | } 1612 | 1613 | while(sr) { 1614 | fprintf(f, "\nSearch%s id ", sr->af == AF_INET6 ? " (IPv6)" : ""); 1615 | print_hex(f, sr->id, 20); 1616 | fprintf(f, " age %d%s\n", (int)(now.tv_sec - sr->step_time), 1617 | sr->done ? " (done)" : ""); 1618 | for(i = 0; i < sr->numnodes; i++) { 1619 | struct search_node *n = &sr->nodes[i]; 1620 | fprintf(f, "Node %d id ", i); 1621 | print_hex(f, n->id, 20); 1622 | fprintf(f, " bits %d age ", common_bits(sr->id, n->id)); 1623 | if(n->request_time) 1624 | fprintf(f, "%d, ", (int)(now.tv_sec - n->request_time)); 1625 | fprintf(f, "%d", (int)(now.tv_sec - n->reply_time)); 1626 | if(n->pinged) 1627 | fprintf(f, " (%d)", n->pinged); 1628 | fprintf(f, "%s%s.\n", 1629 | find_node(n->id, AF_INET) ? " (known)" : "", 1630 | n->replied ? " (replied)" : ""); 1631 | } 1632 | sr = sr->next; 1633 | } 1634 | 1635 | while(st) { 1636 | fprintf(f, "\nStorage "); 1637 | print_hex(f, st->id, 20); 1638 | fprintf(f, " %d/%d nodes:", st->numpeers, st->maxpeers); 1639 | for(i = 0; i < st->numpeers; i++) { 1640 | char buf[100]; 1641 | if(st->peers[i].len == 4) { 1642 | inet_ntop(AF_INET, st->peers[i].ip, buf, 100); 1643 | } else if(st->peers[i].len == 16) { 1644 | buf[0] = '['; 1645 | inet_ntop(AF_INET6, st->peers[i].ip, buf + 1, 98); 1646 | strcat(buf, "]"); 1647 | } else { 1648 | strcpy(buf, "???"); 1649 | } 1650 | fprintf(f, " %s:%u (%ld)", 1651 | buf, st->peers[i].port, 1652 | (long)(now.tv_sec - st->peers[i].time)); 1653 | } 1654 | st = st->next; 1655 | } 1656 | 1657 | fprintf(f, "\n\n"); 1658 | fflush(f); 1659 | } 1660 | 1661 | int 1662 | dht_init(int s, int s6, const unsigned char *id, const unsigned char *v) 1663 | { 1664 | int rc; 1665 | 1666 | if(dht_socket >= 0 || dht_socket6 >= 0 || buckets || buckets6) { 1667 | errno = EBUSY; 1668 | return -1; 1669 | } 1670 | 1671 | searches = NULL; 1672 | numsearches = 0; 1673 | 1674 | storage = NULL; 1675 | numstorage = 0; 1676 | 1677 | if(s >= 0) { 1678 | buckets = calloc(sizeof(struct bucket), 1); 1679 | if(buckets == NULL) 1680 | return -1; 1681 | buckets->af = AF_INET; 1682 | 1683 | rc = set_nonblocking(s, 1); 1684 | if(rc < 0) 1685 | goto fail; 1686 | } 1687 | 1688 | if(s6 >= 0) { 1689 | buckets6 = calloc(sizeof(struct bucket), 1); 1690 | if(buckets6 == NULL) 1691 | return -1; 1692 | buckets6->af = AF_INET6; 1693 | 1694 | rc = set_nonblocking(s6, 1); 1695 | if(rc < 0) 1696 | goto fail; 1697 | } 1698 | 1699 | memcpy(myid, id, 20); 1700 | if(v) { 1701 | memcpy(my_v, "1:v4:", 5); 1702 | memcpy(my_v + 5, v, 4); 1703 | have_v = 1; 1704 | } else { 1705 | have_v = 0; 1706 | } 1707 | 1708 | dht_gettimeofday(&now, NULL); 1709 | 1710 | mybucket_grow_time = now.tv_sec; 1711 | mybucket6_grow_time = now.tv_sec; 1712 | confirm_nodes_time = now.tv_sec + random() % 3; 1713 | 1714 | search_id = random() & 0xFFFF; 1715 | search_time = 0; 1716 | 1717 | next_blacklisted = 0; 1718 | 1719 | token_bucket_time = now.tv_sec; 1720 | token_bucket_tokens = MAX_TOKEN_BUCKET_TOKENS; 1721 | 1722 | memset(secret, 0, sizeof(secret)); 1723 | rc = rotate_secrets(); 1724 | if(rc < 0) 1725 | goto fail; 1726 | 1727 | dht_socket = s; 1728 | dht_socket6 = s6; 1729 | 1730 | expire_buckets(buckets); 1731 | expire_buckets(buckets6); 1732 | 1733 | return 1; 1734 | 1735 | fail: 1736 | free(buckets); 1737 | buckets = NULL; 1738 | free(buckets6); 1739 | buckets6 = NULL; 1740 | return -1; 1741 | } 1742 | 1743 | int 1744 | dht_uninit() 1745 | { 1746 | if(dht_socket < 0 && dht_socket6 < 0) { 1747 | errno = EINVAL; 1748 | return -1; 1749 | } 1750 | 1751 | dht_socket = -1; 1752 | dht_socket6 = -1; 1753 | 1754 | while(buckets) { 1755 | struct bucket *b = buckets; 1756 | buckets = b->next; 1757 | while(b->nodes) { 1758 | struct node *n = b->nodes; 1759 | b->nodes = n->next; 1760 | free(n); 1761 | } 1762 | free(b); 1763 | } 1764 | 1765 | while(buckets6) { 1766 | struct bucket *b = buckets6; 1767 | buckets6 = b->next; 1768 | while(b->nodes) { 1769 | struct node *n = b->nodes; 1770 | b->nodes = n->next; 1771 | free(n); 1772 | } 1773 | free(b); 1774 | } 1775 | 1776 | while(storage) { 1777 | struct storage *st = storage; 1778 | storage = storage->next; 1779 | free(st->peers); 1780 | free(st); 1781 | } 1782 | 1783 | while(searches) { 1784 | struct search *sr = searches; 1785 | searches = searches->next; 1786 | free(sr); 1787 | } 1788 | 1789 | return 1; 1790 | } 1791 | 1792 | /* Rate control for requests we receive. */ 1793 | 1794 | static int 1795 | token_bucket(void) 1796 | { 1797 | if(token_bucket_tokens == 0) { 1798 | token_bucket_tokens = MIN(MAX_TOKEN_BUCKET_TOKENS, 1799 | 100 * (now.tv_sec - token_bucket_time)); 1800 | token_bucket_time = now.tv_sec; 1801 | } 1802 | 1803 | if(token_bucket_tokens == 0) 1804 | return 0; 1805 | 1806 | token_bucket_tokens--; 1807 | return 1; 1808 | } 1809 | 1810 | static int 1811 | neighbourhood_maintenance(int af) 1812 | { 1813 | unsigned char id[20]; 1814 | struct bucket *b = find_bucket(myid, af); 1815 | struct bucket *q; 1816 | struct node *n; 1817 | 1818 | if(b == NULL) 1819 | return 0; 1820 | 1821 | memcpy(id, myid, 20); 1822 | id[19] = random() & 0xFF; 1823 | q = b; 1824 | if(q->next && (q->count == 0 || (random() & 7) == 0)) 1825 | q = b->next; 1826 | if(q->count == 0 || (random() & 7) == 0) { 1827 | struct bucket *r; 1828 | r = previous_bucket(b); 1829 | if(r && r->count > 0) 1830 | q = r; 1831 | } 1832 | 1833 | if(q) { 1834 | /* Since our node-id is the same in both DHTs, it's probably 1835 | profitable to query both families. */ 1836 | int want = dht_socket >= 0 && dht_socket6 >= 0 ? (WANT4 | WANT6) : -1; 1837 | n = random_node(q); 1838 | if(n) { 1839 | unsigned char tid[4]; 1840 | debugf("Sending find_node for%s neighborhood maintenance.\n", 1841 | af == AF_INET6 ? " IPv6" : ""); 1842 | make_tid(tid, "fn", 0); 1843 | send_find_node((struct sockaddr*)&n->ss, n->sslen, 1844 | tid, 4, id, want, 1845 | n->reply_time >= now.tv_sec - 15); 1846 | pinged(n, q); 1847 | } 1848 | return 1; 1849 | } 1850 | return 0; 1851 | } 1852 | 1853 | static int 1854 | bucket_maintenance(int af) 1855 | { 1856 | struct bucket *b; 1857 | 1858 | b = af == AF_INET ? buckets : buckets6; 1859 | 1860 | while(b) { 1861 | struct bucket *q; 1862 | if(b->time < now.tv_sec - 600) { 1863 | /* This bucket hasn't seen any positive confirmation for a long 1864 | time. Pick a random id in this bucket's range, and send 1865 | a request to a random node. */ 1866 | unsigned char id[20]; 1867 | struct node *n; 1868 | int rc; 1869 | 1870 | rc = bucket_random(b, id); 1871 | if(rc < 0) 1872 | memcpy(id, b->first, 20); 1873 | 1874 | q = b; 1875 | /* If the bucket is empty, we try to fill it from a neighbour. 1876 | We also sometimes do it gratuitiously to recover from 1877 | buckets full of broken nodes. */ 1878 | if(q->next && (q->count == 0 || (random() & 7) == 0)) 1879 | q = b->next; 1880 | if(q->count == 0 || (random() & 7) == 0) { 1881 | struct bucket *r; 1882 | r = previous_bucket(b); 1883 | if(r && r->count > 0) 1884 | q = r; 1885 | } 1886 | 1887 | if(q) { 1888 | n = random_node(q); 1889 | if(n) { 1890 | unsigned char tid[4]; 1891 | int want = -1; 1892 | 1893 | if(dht_socket >= 0 && dht_socket6 >= 0) { 1894 | struct bucket *otherbucket; 1895 | otherbucket = 1896 | find_bucket(id, af == AF_INET ? AF_INET6 : AF_INET); 1897 | if(otherbucket && otherbucket->count < 8) 1898 | /* The corresponding bucket in the other family 1899 | is emptyish -- querying both is useful. */ 1900 | want = WANT4 | WANT6; 1901 | else if(random() % 37 == 0) 1902 | /* Most of the time, this just adds overhead. 1903 | However, it might help stitch back one of 1904 | the DHTs after a network collapse, so query 1905 | both, but only very occasionally. */ 1906 | want = WANT4 | WANT6; 1907 | } 1908 | 1909 | debugf("Sending find_node for%s bucket maintenance.\n", 1910 | af == AF_INET6 ? " IPv6" : ""); 1911 | make_tid(tid, "fn", 0); 1912 | send_find_node((struct sockaddr*)&n->ss, n->sslen, 1913 | tid, 4, id, want, 1914 | n->reply_time >= now.tv_sec - 15); 1915 | pinged(n, q); 1916 | /* In order to avoid sending queries back-to-back, 1917 | give up for now and reschedule us soon. */ 1918 | return 1; 1919 | } 1920 | } 1921 | } 1922 | b = b->next; 1923 | } 1924 | return 0; 1925 | } 1926 | 1927 | int 1928 | dht_periodic(const void *buf, size_t buflen, 1929 | const struct sockaddr *from, int fromlen, 1930 | time_t *tosleep, 1931 | dht_callback *callback, void *closure) 1932 | { 1933 | dht_gettimeofday(&now, NULL); 1934 | 1935 | if(buflen > 0) { 1936 | int message; 1937 | unsigned char tid[16], id[20], info_hash[20], target[20]; 1938 | unsigned char nodes[26*16], nodes6[38*16], token[128]; 1939 | int tid_len = 16, token_len = 128; 1940 | int nodes_len = 26*16, nodes6_len = 38*16; 1941 | unsigned short port; 1942 | unsigned char values[2048], values6[2048]; 1943 | int values_len = 2048, values6_len = 2048; 1944 | int want; 1945 | unsigned short ttid; 1946 | 1947 | if(is_martian(from)) 1948 | goto dontread; 1949 | 1950 | if(node_blacklisted(from, fromlen)) { 1951 | debugf("Received packet from blacklisted node.\n"); 1952 | goto dontread; 1953 | } 1954 | 1955 | if(((char*)buf)[buflen] != '\0') { 1956 | debugf("Unterminated message.\n"); 1957 | errno = EINVAL; 1958 | return -1; 1959 | } 1960 | 1961 | message = parse_message(buf, buflen, tid, &tid_len, id, info_hash, 1962 | target, &port, token, &token_len, 1963 | nodes, &nodes_len, nodes6, &nodes6_len, 1964 | values, &values_len, values6, &values6_len, 1965 | &want); 1966 | 1967 | if(message < 0 || message == ERROR || id_cmp(id, zeroes) == 0) { 1968 | debugf("Unparseable message: "); 1969 | debug_printable(buf, buflen); 1970 | debugf("\n"); 1971 | goto dontread; 1972 | } 1973 | 1974 | if(id_cmp(id, myid) == 0) { 1975 | debugf("Received message from self.\n"); 1976 | goto dontread; 1977 | } 1978 | 1979 | if(message > REPLY) { 1980 | /* Rate limit requests. */ 1981 | if(!token_bucket()) { 1982 | debugf("Dropping request due to rate limiting.\n"); 1983 | goto dontread; 1984 | } 1985 | } 1986 | 1987 | switch(message) { 1988 | case REPLY: 1989 | if(tid_len != 4) { 1990 | debugf("Broken node truncates transaction ids: "); 1991 | debug_printable(buf, buflen); 1992 | debugf("\n"); 1993 | /* This is really annoying, as it means that we will 1994 | time-out all our searches that go through this node. 1995 | Kill it. */ 1996 | blacklist_node(id, from, fromlen); 1997 | goto dontread; 1998 | } 1999 | if(tid_match(tid, "pn", NULL)) { 2000 | debugf("Pong!\n"); 2001 | new_node(id, from, fromlen, 2); 2002 | } else if(tid_match(tid, "fn", NULL) || 2003 | tid_match(tid, "gp", NULL)) { 2004 | int gp = 0; 2005 | struct search *sr = NULL; 2006 | if(tid_match(tid, "gp", &ttid)) { 2007 | gp = 1; 2008 | sr = find_search(ttid, from->sa_family); 2009 | } 2010 | debugf("Nodes found (%d+%d)%s!\n", nodes_len/26, nodes6_len/38, 2011 | gp ? " for get_peers" : ""); 2012 | if(nodes_len % 26 != 0 || nodes6_len % 38 != 0) { 2013 | debugf("Unexpected length for node info!\n"); 2014 | blacklist_node(id, from, fromlen); 2015 | } else if(gp && sr == NULL) { 2016 | debugf("Unknown search!\n"); 2017 | new_node(id, from, fromlen, 1); 2018 | } else { 2019 | int i; 2020 | new_node(id, from, fromlen, 2); 2021 | for(i = 0; i < nodes_len / 26; i++) { 2022 | unsigned char *ni = nodes + i * 26; 2023 | struct sockaddr_in sin; 2024 | if(id_cmp(ni, myid) == 0) 2025 | continue; 2026 | memset(&sin, 0, sizeof(sin)); 2027 | sin.sin_family = AF_INET; 2028 | memcpy(&sin.sin_addr, ni + 20, 4); 2029 | memcpy(&sin.sin_port, ni + 24, 2); 2030 | new_node(ni, (struct sockaddr*)&sin, sizeof(sin), 0); 2031 | if(sr && sr->af == AF_INET) { 2032 | insert_search_node(ni, 2033 | (struct sockaddr*)&sin, 2034 | sizeof(sin), 2035 | sr, 0, NULL, 0); 2036 | } 2037 | } 2038 | for(i = 0; i < nodes6_len / 38; i++) { 2039 | unsigned char *ni = nodes6 + i * 38; 2040 | struct sockaddr_in6 sin6; 2041 | if(id_cmp(ni, myid) == 0) 2042 | continue; 2043 | memset(&sin6, 0, sizeof(sin6)); 2044 | sin6.sin6_family = AF_INET6; 2045 | memcpy(&sin6.sin6_addr, ni + 20, 16); 2046 | memcpy(&sin6.sin6_port, ni + 36, 2); 2047 | new_node(ni, (struct sockaddr*)&sin6, sizeof(sin6), 0); 2048 | if(sr && sr->af == AF_INET6) { 2049 | insert_search_node(ni, 2050 | (struct sockaddr*)&sin6, 2051 | sizeof(sin6), 2052 | sr, 0, NULL, 0); 2053 | } 2054 | } 2055 | if(sr) 2056 | /* Since we received a reply, the number of 2057 | requests in flight has decreased. Let's push 2058 | another request. */ 2059 | search_send_get_peers(sr, NULL); 2060 | } 2061 | if(sr) { 2062 | insert_search_node(id, from, fromlen, sr, 2063 | 1, token, token_len); 2064 | if(values_len > 0 || values6_len > 0) { 2065 | debugf("Got values (%d+%d)!\n", 2066 | values_len / 6, values6_len / 18); 2067 | if(callback) { 2068 | if(values_len > 0) 2069 | (*callback)(closure, DHT_EVENT_VALUES, sr->id, 2070 | (void*)values, values_len); 2071 | 2072 | if(values6_len > 0) 2073 | (*callback)(closure, DHT_EVENT_VALUES6, sr->id, 2074 | (void*)values6, values6_len); 2075 | } 2076 | } 2077 | } 2078 | } else if(tid_match(tid, "ap", &ttid)) { 2079 | struct search *sr; 2080 | debugf("Got reply to announce_peer.\n"); 2081 | sr = find_search(ttid, from->sa_family); 2082 | if(!sr) { 2083 | debugf("Unknown search!\n"); 2084 | new_node(id, from, fromlen, 1); 2085 | } else { 2086 | int i; 2087 | new_node(id, from, fromlen, 2); 2088 | for(i = 0; i < sr->numnodes; i++) 2089 | if(id_cmp(sr->nodes[i].id, id) == 0) { 2090 | sr->nodes[i].request_time = 0; 2091 | sr->nodes[i].reply_time = now.tv_sec; 2092 | sr->nodes[i].acked = 1; 2093 | sr->nodes[i].pinged = 0; 2094 | break; 2095 | } 2096 | /* See comment for gp above. */ 2097 | search_send_get_peers(sr, NULL); 2098 | } 2099 | } else { 2100 | debugf("Unexpected reply: "); 2101 | debug_printable(buf, buflen); 2102 | debugf("\n"); 2103 | } 2104 | break; 2105 | case PING: 2106 | debugf("Ping (%d)!\n", tid_len); 2107 | new_node(id, from, fromlen, 1); 2108 | debugf("Sending pong.\n"); 2109 | send_pong(from, fromlen, tid, tid_len); 2110 | break; 2111 | case FIND_NODE: 2112 | debugf("Find node!\n"); 2113 | new_node(id, from, fromlen, 1); 2114 | debugf("Sending closest nodes (%d).\n", want); 2115 | send_closest_nodes(from, fromlen, 2116 | tid, tid_len, target, want, 2117 | 0, NULL, NULL, 0); 2118 | break; 2119 | case GET_PEERS: 2120 | debugf("Get_peers!\n"); 2121 | new_node(id, from, fromlen, 1); 2122 | if(id_cmp(info_hash, zeroes) == 0) { 2123 | debugf("Eek! Got get_peers with no info_hash.\n"); 2124 | send_error(from, fromlen, tid, tid_len, 2125 | 203, "Get_peers with no info_hash"); 2126 | break; 2127 | } else { 2128 | struct storage *st = find_storage(info_hash); 2129 | unsigned char token[TOKEN_SIZE]; 2130 | make_token(from, 0, token); 2131 | if(st && st->numpeers > 0) { 2132 | debugf("Sending found%s peers.\n", 2133 | from->sa_family == AF_INET6 ? " IPv6" : ""); 2134 | send_closest_nodes(from, fromlen, 2135 | tid, tid_len, 2136 | info_hash, want, 2137 | from->sa_family, st, 2138 | token, TOKEN_SIZE); 2139 | } else { 2140 | debugf("Sending nodes for get_peers.\n"); 2141 | send_closest_nodes(from, fromlen, 2142 | tid, tid_len, info_hash, want, 2143 | 0, NULL, token, TOKEN_SIZE); 2144 | } 2145 | } 2146 | break; 2147 | case ANNOUNCE_PEER: 2148 | debugf("Announce peer!\n"); 2149 | new_node(id, from, fromlen, 1); 2150 | if(id_cmp(info_hash, zeroes) == 0) { 2151 | debugf("Announce_peer with no info_hash.\n"); 2152 | send_error(from, fromlen, tid, tid_len, 2153 | 203, "Announce_peer with no info_hash"); 2154 | break; 2155 | } 2156 | if(!token_match(token, token_len, from)) { 2157 | debugf("Incorrect token for announce_peer.\n"); 2158 | send_error(from, fromlen, tid, tid_len, 2159 | 203, "Announce_peer with wrong token"); 2160 | break; 2161 | } 2162 | if(port == 0) { 2163 | debugf("Announce_peer with forbidden port %d.\n", port); 2164 | send_error(from, fromlen, tid, tid_len, 2165 | 203, "Announce_peer with forbidden port number"); 2166 | break; 2167 | } 2168 | storage_store(info_hash, from, port); 2169 | /* Note that if storage_store failed, we lie to the requestor. 2170 | This is to prevent them from backtracking, and hence 2171 | polluting the DHT. */ 2172 | debugf("Sending peer announced.\n"); 2173 | send_peer_announced(from, fromlen, tid, tid_len); 2174 | } 2175 | } 2176 | 2177 | dontread: 2178 | if(now.tv_sec >= rotate_secrets_time) 2179 | rotate_secrets(); 2180 | 2181 | if(now.tv_sec >= expire_stuff_time) { 2182 | expire_buckets(buckets); 2183 | expire_buckets(buckets6); 2184 | expire_storage(); 2185 | expire_searches(); 2186 | } 2187 | 2188 | if(search_time > 0 && now.tv_sec >= search_time) { 2189 | struct search *sr; 2190 | sr = searches; 2191 | while(sr) { 2192 | if(!sr->done && sr->step_time + 5 <= now.tv_sec) { 2193 | search_step(sr, callback, closure); 2194 | } 2195 | sr = sr->next; 2196 | } 2197 | 2198 | search_time = 0; 2199 | 2200 | sr = searches; 2201 | while(sr) { 2202 | if(!sr->done) { 2203 | time_t tm = sr->step_time + 15 + random() % 10; 2204 | if(search_time == 0 || search_time > tm) 2205 | search_time = tm; 2206 | } 2207 | sr = sr->next; 2208 | } 2209 | } 2210 | 2211 | if(now.tv_sec >= confirm_nodes_time) { 2212 | int soon = 0; 2213 | 2214 | soon |= bucket_maintenance(AF_INET); 2215 | soon |= bucket_maintenance(AF_INET6); 2216 | 2217 | if(!soon) { 2218 | if(mybucket_grow_time >= now.tv_sec - 150) 2219 | soon |= neighbourhood_maintenance(AF_INET); 2220 | if(mybucket6_grow_time >= now.tv_sec - 150) 2221 | soon |= neighbourhood_maintenance(AF_INET6); 2222 | } 2223 | 2224 | /* In order to maintain all buckets' age within 600 seconds, worst 2225 | case is roughly 27 seconds, assuming the table is 22 bits deep. 2226 | We want to keep a margin for neighborhood maintenance, so keep 2227 | this within 25 seconds. */ 2228 | if(soon) 2229 | confirm_nodes_time = now.tv_sec + 5 + random() % 20; 2230 | else 2231 | confirm_nodes_time = now.tv_sec + 60 + random() % 120; 2232 | } 2233 | 2234 | if(confirm_nodes_time > now.tv_sec) 2235 | *tosleep = confirm_nodes_time - now.tv_sec; 2236 | else 2237 | *tosleep = 0; 2238 | 2239 | if(search_time > 0) { 2240 | if(search_time <= now.tv_sec) 2241 | *tosleep = 0; 2242 | else if(*tosleep > search_time - now.tv_sec) 2243 | *tosleep = search_time - now.tv_sec; 2244 | } 2245 | 2246 | return 1; 2247 | } 2248 | 2249 | int 2250 | dht_get_nodes(struct sockaddr_in *sin, int *num, 2251 | struct sockaddr_in6 *sin6, int *num6) 2252 | { 2253 | int i, j; 2254 | struct bucket *b; 2255 | struct node *n; 2256 | 2257 | i = 0; 2258 | 2259 | /* For restoring to work without discarding too many nodes, the list 2260 | must start with the contents of our bucket. */ 2261 | b = find_bucket(myid, AF_INET); 2262 | if(b == NULL) 2263 | goto no_ipv4; 2264 | 2265 | n = b->nodes; 2266 | while(n && i < *num) { 2267 | if(node_good(n)) { 2268 | sin[i] = *(struct sockaddr_in*)&n->ss; 2269 | i++; 2270 | } 2271 | n = n->next; 2272 | } 2273 | 2274 | b = buckets; 2275 | while(b && i < *num) { 2276 | if(!in_bucket(myid, b)) { 2277 | n = b->nodes; 2278 | while(n && i < *num) { 2279 | if(node_good(n)) { 2280 | sin[i] = *(struct sockaddr_in*)&n->ss; 2281 | i++; 2282 | } 2283 | n = n->next; 2284 | } 2285 | } 2286 | b = b->next; 2287 | } 2288 | 2289 | no_ipv4: 2290 | 2291 | j = 0; 2292 | 2293 | b = find_bucket(myid, AF_INET6); 2294 | if(b == NULL) 2295 | goto no_ipv6; 2296 | 2297 | n = b->nodes; 2298 | while(n && j < *num6) { 2299 | if(node_good(n)) { 2300 | sin6[j] = *(struct sockaddr_in6*)&n->ss; 2301 | j++; 2302 | } 2303 | n = n->next; 2304 | } 2305 | 2306 | b = buckets6; 2307 | while(b && j < *num6) { 2308 | if(!in_bucket(myid, b)) { 2309 | n = b->nodes; 2310 | while(n && j < *num6) { 2311 | if(node_good(n)) { 2312 | sin6[j] = *(struct sockaddr_in6*)&n->ss; 2313 | j++; 2314 | } 2315 | n = n->next; 2316 | } 2317 | } 2318 | b = b->next; 2319 | } 2320 | 2321 | no_ipv6: 2322 | 2323 | *num = i; 2324 | *num6 = j; 2325 | return i + j; 2326 | } 2327 | 2328 | int 2329 | dht_insert_node(const unsigned char *id, struct sockaddr *sa, int salen) 2330 | { 2331 | struct node *n; 2332 | 2333 | if(sa->sa_family != AF_INET) { 2334 | errno = EAFNOSUPPORT; 2335 | return -1; 2336 | } 2337 | 2338 | n = new_node(id, (struct sockaddr*)sa, salen, 0); 2339 | return !!n; 2340 | } 2341 | 2342 | int 2343 | dht_ping_node(const struct sockaddr *sa, int salen) 2344 | { 2345 | unsigned char tid[4]; 2346 | 2347 | debugf("Sending ping.\n"); 2348 | make_tid(tid, "pn", 0); 2349 | return send_ping(sa, salen, tid, 4); 2350 | } 2351 | 2352 | /* We could use a proper bencoding printer and parser, but the format of 2353 | DHT messages is fairly stylised, so this seemed simpler. */ 2354 | 2355 | #define CHECK(offset, delta, size) \ 2356 | if(delta < 0 || offset + delta > size) goto fail 2357 | 2358 | #define INC(offset, delta, size) \ 2359 | CHECK(offset, delta, size); \ 2360 | offset += delta 2361 | 2362 | #define COPY(buf, offset, src, delta, size) \ 2363 | CHECK(offset, delta, size); \ 2364 | memcpy(buf + offset, src, delta); \ 2365 | offset += delta; 2366 | 2367 | #define ADD_V(buf, offset, size) \ 2368 | if(have_v) { \ 2369 | COPY(buf, offset, my_v, sizeof(my_v), size); \ 2370 | } 2371 | 2372 | static int 2373 | dht_send(const void *buf, size_t len, int flags, 2374 | const struct sockaddr *sa, int salen) 2375 | { 2376 | int s; 2377 | 2378 | if(salen == 0) 2379 | abort(); 2380 | 2381 | if(node_blacklisted(sa, salen)) { 2382 | debugf("Attempting to send to blacklisted node.\n"); 2383 | errno = EPERM; 2384 | return -1; 2385 | } 2386 | 2387 | if(sa->sa_family == AF_INET) 2388 | s = dht_socket; 2389 | else if(sa->sa_family == AF_INET6) 2390 | s = dht_socket6; 2391 | else 2392 | s = -1; 2393 | 2394 | if(s < 0) { 2395 | errno = EAFNOSUPPORT; 2396 | return -1; 2397 | } 2398 | 2399 | return sendto(s, buf, len, flags, sa, salen); 2400 | } 2401 | 2402 | int 2403 | send_ping(const struct sockaddr *sa, int salen, 2404 | const unsigned char *tid, int tid_len) 2405 | { 2406 | char buf[512]; 2407 | int i = 0, rc; 2408 | rc = snprintf(buf + i, 512 - i, "d1:ad2:id20:"); INC(i, rc, 512); 2409 | COPY(buf, i, myid, 20, 512); 2410 | rc = snprintf(buf + i, 512 - i, "e1:q4:ping1:t%d:", tid_len); 2411 | INC(i, rc, 512); 2412 | COPY(buf, i, tid, tid_len, 512); 2413 | ADD_V(buf, i, 512); 2414 | rc = snprintf(buf + i, 512 - i, "1:y1:qe"); INC(i, rc, 512); 2415 | return dht_send(buf, i, 0, sa, salen); 2416 | 2417 | fail: 2418 | errno = ENOSPC; 2419 | return -1; 2420 | } 2421 | 2422 | int 2423 | send_pong(const struct sockaddr *sa, int salen, 2424 | const unsigned char *tid, int tid_len) 2425 | { 2426 | char buf[512]; 2427 | int i = 0, rc; 2428 | rc = snprintf(buf + i, 512 - i, "d1:rd2:id20:"); INC(i, rc, 512); 2429 | COPY(buf, i, myid, 20, 512); 2430 | rc = snprintf(buf + i, 512 - i, "e1:t%d:", tid_len); INC(i, rc, 512); 2431 | COPY(buf, i, tid, tid_len, 512); 2432 | ADD_V(buf, i, 512); 2433 | rc = snprintf(buf + i, 512 - i, "1:y1:re"); INC(i, rc, 512); 2434 | return dht_send(buf, i, 0, sa, salen); 2435 | 2436 | fail: 2437 | errno = ENOSPC; 2438 | return -1; 2439 | } 2440 | 2441 | int 2442 | send_find_node(const struct sockaddr *sa, int salen, 2443 | const unsigned char *tid, int tid_len, 2444 | const unsigned char *target, int want, int confirm) 2445 | { 2446 | char buf[512]; 2447 | int i = 0, rc; 2448 | rc = snprintf(buf + i, 512 - i, "d1:ad2:id20:"); INC(i, rc, 512); 2449 | COPY(buf, i, myid, 20, 512); 2450 | rc = snprintf(buf + i, 512 - i, "6:target20:"); INC(i, rc, 512); 2451 | COPY(buf, i, target, 20, 512); 2452 | if(want > 0) { 2453 | rc = snprintf(buf + i, 512 - i, "4:wantl%s%se", 2454 | (want & WANT4) ? "2:n4" : "", 2455 | (want & WANT6) ? "2:n6" : ""); 2456 | INC(i, rc, 512); 2457 | } 2458 | rc = snprintf(buf + i, 512 - i, "e1:q9:find_node1:t%d:", tid_len); 2459 | INC(i, rc, 512); 2460 | COPY(buf, i, tid, tid_len, 512); 2461 | ADD_V(buf, i, 512); 2462 | rc = snprintf(buf + i, 512 - i, "1:y1:qe"); INC(i, rc, 512); 2463 | return dht_send(buf, i, confirm ? MSG_CONFIRM : 0, sa, salen); 2464 | 2465 | fail: 2466 | errno = ENOSPC; 2467 | return -1; 2468 | } 2469 | 2470 | int 2471 | send_nodes_peers(const struct sockaddr *sa, int salen, 2472 | const unsigned char *tid, int tid_len, 2473 | const unsigned char *nodes, int nodes_len, 2474 | const unsigned char *nodes6, int nodes6_len, 2475 | int af, struct storage *st, 2476 | const unsigned char *token, int token_len) 2477 | { 2478 | char buf[2048]; 2479 | int i = 0, rc, j0, j, k, len; 2480 | 2481 | rc = snprintf(buf + i, 2048 - i, "d1:rd2:id20:"); INC(i, rc, 2048); 2482 | COPY(buf, i, myid, 20, 2048); 2483 | if(nodes_len > 0) { 2484 | rc = snprintf(buf + i, 2048 - i, "5:nodes%d:", nodes_len); 2485 | INC(i, rc, 2048); 2486 | COPY(buf, i, nodes, nodes_len, 2048); 2487 | } 2488 | if(nodes6_len > 0) { 2489 | rc = snprintf(buf + i, 2048 - i, "6:nodes6%d:", nodes6_len); 2490 | INC(i, rc, 2048); 2491 | COPY(buf, i, nodes6, nodes6_len, 2048); 2492 | } 2493 | if(token_len > 0) { 2494 | rc = snprintf(buf + i, 2048 - i, "5:token%d:", token_len); 2495 | INC(i, rc, 2048); 2496 | COPY(buf, i, token, token_len, 2048); 2497 | } 2498 | 2499 | if(st && st->numpeers > 0) { 2500 | /* We treat the storage as a circular list, and serve a randomly 2501 | chosen slice. In order to make sure we fit within 1024 octets, 2502 | we limit ourselves to 50 peers. */ 2503 | 2504 | len = af == AF_INET ? 4 : 16; 2505 | j0 = random() % st->numpeers; 2506 | j = j0; 2507 | k = 0; 2508 | 2509 | rc = snprintf(buf + i, 2048 - i, "6:valuesl"); INC(i, rc, 2048); 2510 | do { 2511 | if(st->peers[j].len == len) { 2512 | unsigned short swapped; 2513 | swapped = htons(st->peers[j].port); 2514 | rc = snprintf(buf + i, 2048 - i, "%d:", len + 2); 2515 | INC(i, rc, 2048); 2516 | COPY(buf, i, st->peers[j].ip, len, 2048); 2517 | COPY(buf, i, &swapped, 2, 2048); 2518 | k++; 2519 | } 2520 | j = (j + 1) % st->numpeers; 2521 | } while(j != j0 && k < 50); 2522 | rc = snprintf(buf + i, 2048 - i, "e"); INC(i, rc, 2048); 2523 | } 2524 | 2525 | rc = snprintf(buf + i, 2048 - i, "e1:t%d:", tid_len); INC(i, rc, 2048); 2526 | COPY(buf, i, tid, tid_len, 2048); 2527 | ADD_V(buf, i, 2048); 2528 | rc = snprintf(buf + i, 2048 - i, "1:y1:re"); INC(i, rc, 2048); 2529 | 2530 | return dht_send(buf, i, 0, sa, salen); 2531 | 2532 | fail: 2533 | errno = ENOSPC; 2534 | return -1; 2535 | } 2536 | 2537 | static int 2538 | insert_closest_node(unsigned char *nodes, int numnodes, 2539 | const unsigned char *id, struct node *n) 2540 | { 2541 | int i, size; 2542 | 2543 | if(n->ss.ss_family == AF_INET) 2544 | size = 26; 2545 | else if(n->ss.ss_family == AF_INET6) 2546 | size = 38; 2547 | else 2548 | abort(); 2549 | 2550 | for(i = 0; i< numnodes; i++) { 2551 | if(id_cmp(n->id, nodes + size * i) == 0) 2552 | return numnodes; 2553 | if(xorcmp(n->id, nodes + size * i, id) < 0) 2554 | break; 2555 | } 2556 | 2557 | if(i == 8) 2558 | return numnodes; 2559 | 2560 | if(numnodes < 8) 2561 | numnodes++; 2562 | 2563 | if(i < numnodes - 1) 2564 | memmove(nodes + size * (i + 1), nodes + size * i, 2565 | size * (numnodes - i - 1)); 2566 | 2567 | if(n->ss.ss_family == AF_INET) { 2568 | struct sockaddr_in *sin = (struct sockaddr_in*)&n->ss; 2569 | memcpy(nodes + size * i, n->id, 20); 2570 | memcpy(nodes + size * i + 20, &sin->sin_addr, 4); 2571 | memcpy(nodes + size * i + 24, &sin->sin_port, 2); 2572 | } else if(n->ss.ss_family == AF_INET6) { 2573 | struct sockaddr_in6 *sin6 = (struct sockaddr_in6*)&n->ss; 2574 | memcpy(nodes + size * i, n->id, 20); 2575 | memcpy(nodes + size * i + 20, &sin6->sin6_addr, 16); 2576 | memcpy(nodes + size * i + 36, &sin6->sin6_port, 2); 2577 | } else { 2578 | abort(); 2579 | } 2580 | 2581 | return numnodes; 2582 | } 2583 | 2584 | static int 2585 | buffer_closest_nodes(unsigned char *nodes, int numnodes, 2586 | const unsigned char *id, struct bucket *b) 2587 | { 2588 | struct node *n = b->nodes; 2589 | while(n) { 2590 | if(node_good(n)) 2591 | numnodes = insert_closest_node(nodes, numnodes, id, n); 2592 | n = n->next; 2593 | } 2594 | return numnodes; 2595 | } 2596 | 2597 | int 2598 | send_closest_nodes(const struct sockaddr *sa, int salen, 2599 | const unsigned char *tid, int tid_len, 2600 | const unsigned char *id, int want, 2601 | int af, struct storage *st, 2602 | const unsigned char *token, int token_len) 2603 | { 2604 | unsigned char nodes[8 * 26]; 2605 | unsigned char nodes6[8 * 38]; 2606 | int numnodes = 0, numnodes6 = 0; 2607 | struct bucket *b; 2608 | 2609 | if(want < 0) 2610 | want = sa->sa_family == AF_INET ? WANT4 : WANT6; 2611 | 2612 | if((want & WANT4)) { 2613 | b = find_bucket(id, AF_INET); 2614 | if(b) { 2615 | numnodes = buffer_closest_nodes(nodes, numnodes, id, b); 2616 | if(b->next) 2617 | numnodes = buffer_closest_nodes(nodes, numnodes, id, b->next); 2618 | b = previous_bucket(b); 2619 | if(b) 2620 | numnodes = buffer_closest_nodes(nodes, numnodes, id, b); 2621 | } 2622 | } 2623 | 2624 | if((want & WANT6)) { 2625 | b = find_bucket(id, AF_INET6); 2626 | if(b) { 2627 | numnodes6 = buffer_closest_nodes(nodes6, numnodes6, id, b); 2628 | if(b->next) 2629 | numnodes6 = 2630 | buffer_closest_nodes(nodes6, numnodes6, id, b->next); 2631 | b = previous_bucket(b); 2632 | if(b) 2633 | numnodes6 = buffer_closest_nodes(nodes6, numnodes6, id, b); 2634 | } 2635 | } 2636 | debugf(" (%d+%d nodes.)\n", numnodes, numnodes6); 2637 | 2638 | return send_nodes_peers(sa, salen, tid, tid_len, 2639 | nodes, numnodes * 26, 2640 | nodes6, numnodes6 * 38, 2641 | af, st, token, token_len); 2642 | } 2643 | 2644 | int 2645 | send_get_peers(const struct sockaddr *sa, int salen, 2646 | unsigned char *tid, int tid_len, unsigned char *infohash, 2647 | int want, int confirm) 2648 | { 2649 | char buf[512]; 2650 | int i = 0, rc; 2651 | 2652 | rc = snprintf(buf + i, 512 - i, "d1:ad2:id20:"); INC(i, rc, 512); 2653 | COPY(buf, i, myid, 20, 512); 2654 | rc = snprintf(buf + i, 512 - i, "9:info_hash20:"); INC(i, rc, 512); 2655 | COPY(buf, i, infohash, 20, 512); 2656 | if(want > 0) { 2657 | rc = snprintf(buf + i, 512 - i, "4:wantl%s%se", 2658 | (want & WANT4) ? "2:n4" : "", 2659 | (want & WANT6) ? "2:n6" : ""); 2660 | INC(i, rc, 512); 2661 | } 2662 | rc = snprintf(buf + i, 512 - i, "e1:q9:get_peers1:t%d:", tid_len); 2663 | INC(i, rc, 512); 2664 | COPY(buf, i, tid, tid_len, 512); 2665 | ADD_V(buf, i, 512); 2666 | rc = snprintf(buf + i, 512 - i, "1:y1:qe"); INC(i, rc, 512); 2667 | return dht_send(buf, i, confirm ? MSG_CONFIRM : 0, sa, salen); 2668 | 2669 | fail: 2670 | errno = ENOSPC; 2671 | return -1; 2672 | } 2673 | 2674 | int 2675 | send_announce_peer(const struct sockaddr *sa, int salen, 2676 | unsigned char *tid, int tid_len, 2677 | unsigned char *infohash, unsigned short port, 2678 | unsigned char *token, int token_len, int confirm) 2679 | { 2680 | char buf[512]; 2681 | int i = 0, rc; 2682 | 2683 | rc = snprintf(buf + i, 512 - i, "d1:ad2:id20:"); INC(i, rc, 512); 2684 | COPY(buf, i, myid, 20, 512); 2685 | rc = snprintf(buf + i, 512 - i, "9:info_hash20:"); INC(i, rc, 512); 2686 | COPY(buf, i, infohash, 20, 512); 2687 | rc = snprintf(buf + i, 512 - i, "4:porti%ue5:token%d:", (unsigned)port, 2688 | token_len); 2689 | INC(i, rc, 512); 2690 | COPY(buf, i, token, token_len, 512); 2691 | rc = snprintf(buf + i, 512 - i, "e1:q13:announce_peer1:t%d:", tid_len); 2692 | INC(i, rc, 512); 2693 | COPY(buf, i, tid, tid_len, 512); 2694 | ADD_V(buf, i, 512); 2695 | rc = snprintf(buf + i, 512 - i, "1:y1:qe"); INC(i, rc, 512); 2696 | 2697 | return dht_send(buf, i, confirm ? 0 : MSG_CONFIRM, sa, salen); 2698 | 2699 | fail: 2700 | errno = ENOSPC; 2701 | return -1; 2702 | } 2703 | 2704 | static int 2705 | send_peer_announced(const struct sockaddr *sa, int salen, 2706 | unsigned char *tid, int tid_len) 2707 | { 2708 | char buf[512]; 2709 | int i = 0, rc; 2710 | 2711 | rc = snprintf(buf + i, 512 - i, "d1:rd2:id20:"); INC(i, rc, 512); 2712 | COPY(buf, i, myid, 20, 512); 2713 | rc = snprintf(buf + i, 512 - i, "e1:t%d:", tid_len); 2714 | INC(i, rc, 512); 2715 | COPY(buf, i, tid, tid_len, 512); 2716 | ADD_V(buf, i, 512); 2717 | rc = snprintf(buf + i, 512 - i, "1:y1:re"); INC(i, rc, 512); 2718 | return dht_send(buf, i, 0, sa, salen); 2719 | 2720 | fail: 2721 | errno = ENOSPC; 2722 | return -1; 2723 | } 2724 | 2725 | static int 2726 | send_error(const struct sockaddr *sa, int salen, 2727 | unsigned char *tid, int tid_len, 2728 | int code, const char *message) 2729 | { 2730 | char buf[512]; 2731 | int i = 0, rc, message_len; 2732 | 2733 | message_len = strlen(message); 2734 | rc = snprintf(buf + i, 512 - i, "d1:eli%de%d:", code, message_len); 2735 | INC(i, rc, 512); 2736 | COPY(buf, i, message, message_len, 512); 2737 | rc = snprintf(buf + i, 512 - i, "e1:t%d:", tid_len); INC(i, rc, 512); 2738 | COPY(buf, i, tid, tid_len, 512); 2739 | ADD_V(buf, i, 512); 2740 | rc = snprintf(buf + i, 512 - i, "1:y1:ee"); INC(i, rc, 512); 2741 | return dht_send(buf, i, 0, sa, salen); 2742 | 2743 | fail: 2744 | errno = ENOSPC; 2745 | return -1; 2746 | } 2747 | 2748 | #undef CHECK 2749 | #undef INC 2750 | #undef COPY 2751 | #undef ADD_V 2752 | 2753 | #ifdef HAVE_MEMMEM 2754 | 2755 | static void * 2756 | dht_memmem(const void *haystack, size_t haystacklen, 2757 | const void *needle, size_t needlelen) 2758 | { 2759 | return memmem(haystack, haystacklen, needle, needlelen); 2760 | } 2761 | 2762 | #else 2763 | 2764 | static void * 2765 | dht_memmem(const void *haystack, size_t haystacklen, 2766 | const void *needle, size_t needlelen) 2767 | { 2768 | const char *h = haystack; 2769 | const char *n = needle; 2770 | size_t i; 2771 | 2772 | /* size_t is unsigned */ 2773 | if(needlelen > haystacklen) 2774 | return NULL; 2775 | 2776 | for(i = 0; i <= haystacklen - needlelen; i++) { 2777 | if(memcmp(h + i, n, needlelen) == 0) 2778 | return (void*)(h + i); 2779 | } 2780 | return NULL; 2781 | } 2782 | 2783 | #endif 2784 | 2785 | static int 2786 | parse_message(const unsigned char *buf, int buflen, 2787 | unsigned char *tid_return, int *tid_len, 2788 | unsigned char *id_return, unsigned char *info_hash_return, 2789 | unsigned char *target_return, unsigned short *port_return, 2790 | unsigned char *token_return, int *token_len, 2791 | unsigned char *nodes_return, int *nodes_len, 2792 | unsigned char *nodes6_return, int *nodes6_len, 2793 | unsigned char *values_return, int *values_len, 2794 | unsigned char *values6_return, int *values6_len, 2795 | int *want_return) 2796 | { 2797 | const unsigned char *p; 2798 | 2799 | /* This code will happily crash if the buffer is not NUL-terminated. */ 2800 | if(buf[buflen] != '\0') { 2801 | debugf("Eek! parse_message with unterminated buffer.\n"); 2802 | return -1; 2803 | } 2804 | 2805 | #define CHECK(ptr, len) \ 2806 | if(((unsigned char*)ptr) + (len) > (buf) + (buflen)) goto overflow; 2807 | 2808 | if(tid_return) { 2809 | p = dht_memmem(buf, buflen, "1:t", 3); 2810 | if(p) { 2811 | long l; 2812 | char *q; 2813 | l = strtol((char*)p + 3, &q, 10); 2814 | if(q && *q == ':' && l > 0 && l < *tid_len) { 2815 | CHECK(q + 1, l); 2816 | memcpy(tid_return, q + 1, l); 2817 | *tid_len = l; 2818 | } else 2819 | *tid_len = 0; 2820 | } 2821 | } 2822 | if(id_return) { 2823 | p = dht_memmem(buf, buflen, "2:id20:", 7); 2824 | if(p) { 2825 | CHECK(p + 7, 20); 2826 | memcpy(id_return, p + 7, 20); 2827 | } else { 2828 | memset(id_return, 0, 20); 2829 | } 2830 | } 2831 | if(info_hash_return) { 2832 | p = dht_memmem(buf, buflen, "9:info_hash20:", 14); 2833 | if(p) { 2834 | CHECK(p + 14, 20); 2835 | memcpy(info_hash_return, p + 14, 20); 2836 | } else { 2837 | memset(info_hash_return, 0, 20); 2838 | } 2839 | } 2840 | if(port_return) { 2841 | p = dht_memmem(buf, buflen, "porti", 5); 2842 | if(p) { 2843 | long l; 2844 | char *q; 2845 | l = strtol((char*)p + 5, &q, 10); 2846 | if(q && *q == 'e' && l > 0 && l < 0x10000) 2847 | *port_return = l; 2848 | else 2849 | *port_return = 0; 2850 | } else 2851 | *port_return = 0; 2852 | } 2853 | if(target_return) { 2854 | p = dht_memmem(buf, buflen, "6:target20:", 11); 2855 | if(p) { 2856 | CHECK(p + 11, 20); 2857 | memcpy(target_return, p + 11, 20); 2858 | } else { 2859 | memset(target_return, 0, 20); 2860 | } 2861 | } 2862 | if(token_return) { 2863 | p = dht_memmem(buf, buflen, "5:token", 7); 2864 | if(p) { 2865 | long l; 2866 | char *q; 2867 | l = strtol((char*)p + 7, &q, 10); 2868 | if(q && *q == ':' && l > 0 && l < *token_len) { 2869 | CHECK(q + 1, l); 2870 | memcpy(token_return, q + 1, l); 2871 | *token_len = l; 2872 | } else 2873 | *token_len = 0; 2874 | } else 2875 | *token_len = 0; 2876 | } 2877 | 2878 | if(nodes_len) { 2879 | p = dht_memmem(buf, buflen, "5:nodes", 7); 2880 | if(p) { 2881 | long l; 2882 | char *q; 2883 | l = strtol((char*)p + 7, &q, 10); 2884 | if(q && *q == ':' && l > 0 && l <= *nodes_len) { 2885 | CHECK(q + 1, l); 2886 | memcpy(nodes_return, q + 1, l); 2887 | *nodes_len = l; 2888 | } else 2889 | *nodes_len = 0; 2890 | } else 2891 | *nodes_len = 0; 2892 | } 2893 | 2894 | if(nodes6_len) { 2895 | p = dht_memmem(buf, buflen, "6:nodes6", 8); 2896 | if(p) { 2897 | long l; 2898 | char *q; 2899 | l = strtol((char*)p + 8, &q, 10); 2900 | if(q && *q == ':' && l > 0 && l <= *nodes6_len) { 2901 | CHECK(q + 1, l); 2902 | memcpy(nodes6_return, q + 1, l); 2903 | *nodes6_len = l; 2904 | } else 2905 | *nodes6_len = 0; 2906 | } else 2907 | *nodes6_len = 0; 2908 | } 2909 | 2910 | if(values_len || values6_len) { 2911 | p = dht_memmem(buf, buflen, "6:valuesl", 9); 2912 | if(p) { 2913 | int i = p - buf + 9; 2914 | int j = 0, j6 = 0; 2915 | while(1) { 2916 | long l; 2917 | char *q; 2918 | l = strtol((char*)buf + i, &q, 10); 2919 | if(q && *q == ':' && l > 0) { 2920 | CHECK(q + 1, l); 2921 | i = q + 1 + l - (char*)buf; 2922 | if(l == 6) { 2923 | if(j + l > *values_len) 2924 | continue; 2925 | memcpy((char*)values_return + j, q + 1, l); 2926 | j += l; 2927 | } else if(l == 18) { 2928 | if(j6 + l > *values6_len) 2929 | continue; 2930 | memcpy((char*)values6_return + j6, q + 1, l); 2931 | j6 += l; 2932 | } else { 2933 | debugf("Received weird value -- %d bytes.\n", (int)l); 2934 | } 2935 | } else { 2936 | break; 2937 | } 2938 | } 2939 | if(i >= buflen || buf[i] != 'e') 2940 | debugf("eek... unexpected end for values.\n"); 2941 | if(values_len) 2942 | *values_len = j; 2943 | if(values6_len) 2944 | *values6_len = j6; 2945 | } else { 2946 | if(values_len) 2947 | *values_len = 0; 2948 | if(values6_len) 2949 | *values6_len = 0; 2950 | } 2951 | } 2952 | 2953 | if(want_return) { 2954 | p = dht_memmem(buf, buflen, "4:wantl", 7); 2955 | if(p) { 2956 | int i = p - buf + 7; 2957 | *want_return = 0; 2958 | while(buf[i] > '0' && buf[i] <= '9' && buf[i + 1] == ':' && 2959 | i + 2 + buf[i] - '0' < buflen) { 2960 | CHECK(buf + i + 2, buf[i] - '0'); 2961 | if(buf[i] == '2' && memcmp(buf + i + 2, "n4", 2) == 0) 2962 | *want_return |= WANT4; 2963 | else if(buf[i] == '2' && memcmp(buf + i + 2, "n6", 2) == 0) 2964 | *want_return |= WANT6; 2965 | else 2966 | debugf("eek... unexpected want flag (%c)\n", buf[i]); 2967 | i += 2 + buf[i] - '0'; 2968 | } 2969 | if(i >= buflen || buf[i] != 'e') 2970 | debugf("eek... unexpected end for want.\n"); 2971 | } else { 2972 | *want_return = -1; 2973 | } 2974 | } 2975 | 2976 | #undef CHECK 2977 | 2978 | if(dht_memmem(buf, buflen, "1:y1:r", 6)) 2979 | return REPLY; 2980 | if(dht_memmem(buf, buflen, "1:y1:e", 6)) 2981 | return ERROR; 2982 | if(!dht_memmem(buf, buflen, "1:y1:q", 6)) 2983 | return -1; 2984 | if(dht_memmem(buf, buflen, "1:q4:ping", 9)) 2985 | return PING; 2986 | if(dht_memmem(buf, buflen, "1:q9:find_node", 14)) 2987 | return FIND_NODE; 2988 | if(dht_memmem(buf, buflen, "1:q9:get_peers", 14)) 2989 | return GET_PEERS; 2990 | if(dht_memmem(buf, buflen, "1:q13:announce_peer", 19)) 2991 | return ANNOUNCE_PEER; 2992 | return -1; 2993 | 2994 | overflow: 2995 | debugf("Truncated message.\n"); 2996 | return -1; 2997 | } 2998 | --------------------------------------------------------------------------------