1 (* Copyright 2001, 2002 b8_bavard, b8_fee_carabine, INRIA *)
3 This file is part of mldonkey.
5 mldonkey is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
10 mldonkey is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with mldonkey; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
38 let log_prefix = "[KAD]"
41 lprintf_nl2
log_prefix fmt
44 lprintf2
log_prefix fmt
47 lprintf2
log_prefix fmt
51 "\243", Field_KNOWN
"encryption"; (* 0xF3 *)
52 "\248", Field_KNOWN
"buddyhash"; (* 0xF8 *)
53 "\249", Field_KNOWN
"clientlowid"; (* 0xF9 *)
54 "\250", Field_KNOWN
"serverport"; (* 0xFA *)
55 "\251", Field_KNOWN
"serverip"; (* 0xFB *)
56 "\252", Field_KNOWN
"sourceuport"; (* 0xFC *)
57 "\253", Field_KNOWN
"sourceport"; (* 0xFD *)
58 "\254", Field_KNOWN
"sourceip"; (* 0xFE *)
59 "\255", Field_KNOWN
"sourcetype"; (* 0xFF *)
62 (* This fucking Emule implementation uses 4 32-bits integers instead of
63 16 8-bits integers... welcome back to the non-portability problems... *)
65 let ss = String.create
16 in
82 ss.[12] <- s
.[pos
+15];
83 ss.[13] <- s
.[pos
+14];
84 ss.[14] <- s
.[pos
+13];
85 ss.[15] <- s
.[pos
+12];
87 Md4.direct_of_string
@@ Bytes.unsafe_to_string
ss
90 let s = Md4.direct_to_string
s in
92 let ss = String.create
16 in
105 ss.[8] <- s.[pos+11];
106 ss.[9] <- s.[pos+10];
107 ss.[10] <- s.[pos+9];
108 ss.[11] <- s.[pos+8];
110 ss.[12] <- s.[pos+15];
111 ss.[13] <- s.[pos+14];
112 ss.[14] <- s.[pos+13];
113 ss.[15] <- s.[pos+12];
115 Buffer.add_bytes buf
ss
118 (* Strange: why was the IP format changed for Kademlia ? *)
120 let c1 = int_of_char
s.[pos] in
121 let c2 = int_of_char
s.[pos+1] in
122 let c3 = int_of_char
s.[pos+2] in
123 let c4 = int_of_char
s.[pos+3] in
124 Ip.of_ints
(c4, c3, c2, c1)
127 let (ip3
,ip2
,ip1
,ip0
) = Ip.to_ints ip
in
134 buf_md4 buf p
.peer_md4
;
135 buf_ip buf p
.peer_ip
;
136 buf_int16 buf p
.peer_port
;
137 buf_int16 buf p
.peer_tcpport
;
138 buf_int8 buf p
.peer_kind
142 | OvernetConnect p
->
146 | OvernetConnectReply peers
->
148 buf_int16 buf
(List.length peers
);
149 List.iter
(buf_peer buf
) peers
151 | OvernetPublicize p
->
155 | OvernetPublicized
(Some p
) ->
159 | OvernetSearch
(nresults
, target
, Some uid
) ->
161 buf_int8 buf
(nresults
land 0x1f);
165 | OvernetSearchReply
(md4
, peers
) ->
168 buf_int8 buf
(List.length peers
);
169 List.iter
(buf_peer buf
) peers
171 | OvernetGetSearchResults
(target
, kind
, min
, max
) ->
179 | Search_for_keyword None
->
181 | Search_for_keyword
(Some e
) ->
185 | OvernetSearchFilesResults
(target
, results
) ->
188 buf_int16 buf
(List.length results
);
189 List.iter
(fun (md4
, tags
) ->
191 buf_int8 buf
(List.length tags
);
192 List.iter
(fun tag
->
193 buf_tag buf tag
names_of_tag
197 | OvernetPublishFiles
(target
, results
) ->
200 buf_int16 buf
(List.length results
);
201 List.iter
(fun (md4
, tags
) ->
203 buf_int8 buf
(List.length tags
);
204 List.iter
(fun tag
->
205 buf_tag buf tag
names_of_tag
209 | OvernetPublishSources _
210 | OvernetSearchSourcesResults _
212 | OvernetPeerNotFound _
213 | OvernetFirewallConnectionNACK _
214 | OvernetFirewallConnectionACK _
215 | OvernetFirewallConnection
(_
, _
)
216 | OvernetGetMyIPResult _
220 | OvernetSearch
(_
,_
, None
)
221 | OvernetPublicized None
222 | OvernetGetMyIPDone
-> raise MessageNotImplemented
224 | OvernetUnknown
(opcode
, s) ->
226 Buffer.add_string buf
s
230 let md4 = get_md4 s pos in
231 let ip = get_ip s (pos+16) in
232 let udp_port = get_int16
s (pos + 20) in
233 let tcp_port = get_int16
s (pos + 22) in
234 (* let kind = get_uint8 s (pos + 24) in *)
238 peer_port
= udp_port;
239 peer_tcpport
= tcp_port;
240 peer_country_code
= Geoip.get_country_code_option
ip;
244 peer_created
= last_time
();
247 let get_peers_from_results ip port answers
=
248 List.map
(fun (r_md4
, r_tags
) ->
249 let peer_ip = ref ip in
250 let peer_udpport = ref port
in
251 let peer_tcpport = ref 0 in
252 let peer_kind = ref 0 in
253 List.iter
(fun tag
->
254 match tag
.tag_name
with
255 Field_KNOWN
"sourceport" ->
256 for_int_tag tag
(fun port
->
257 peer_tcpport := port
)
258 | Field_KNOWN
"sourceuport" ->
259 for_int_tag tag
(fun port
->
260 peer_udpport := port
)
261 | Field_KNOWN
"sourceip" ->
262 for_int64_tag tag
(fun ip ->
263 peer_ip := Ip.of_int64
ip
265 | Field_KNOWN
"sourcetype" ->
266 for_int_tag tag
(fun kind ->
269 if !verbose_unknown_messages
then
270 lprintf_nl "Unused source tag [%s]"
271 (escaped_string_of_field tag
)
275 peer_port
= !peer_udpport;
276 peer_tcpport = !peer_tcpport;
277 peer_country_code
= Geoip.get_country_code_option
!peer_ip;
282 peer_created
= last_time
();
286 let parse ip port opcode
s =
289 let p, pos = get_peer s 0 in
293 (* let n = get_int16 s 0 in *)
294 let peers, pos = get_list16
get_peer s 0 in
295 OvernetConnectReply
peers
298 let p, pos = get_peer s 0 in
302 let p, pos = get_peer s 0 in
303 OvernetPublicized
(Some
p)
306 let nresults = (get_uint8
s 0) land 0x1f in
307 let target = get_md4 s 1 in
308 let uid = get_md4 s 17 in
309 OvernetSearch
(nresults, target, Some
uid)
312 let target = get_md4 s 0 in
313 let peers, pos = get_list8
get_peer s 16 in
314 OvernetSearchReply
(target, peers)
317 let target = get_md4 s 0 in
318 let kind = get_uint8
s 16 in
320 if String.length
s = 17 then
321 if kind = 1 then Search_for_file
else
322 Search_for_keyword None
326 OvernetGetSearchResults
(target, kind, 0, 100)
329 let target = get_md4 s 0 in
330 let answers, pos = get_list16
(fun s pos ->
331 let uid = get_md4 s pos in
332 let tags, pos = get_list8
(get_tag
names_of_tag)
338 (_
, first_tags
) :: _
->
339 let sources = ref false in
340 List.iter
(fun tag
->
341 if tag
.tag_name
= Field_KNOWN
"sourceport" then sources := true;
344 let peers = get_peers_from_results Ip.null
0 answers in
345 OvernetSearchSourcesResults
(target, peers)
348 OvernetSearchFilesResults
(target, answers)
350 OvernetSearchFilesResults
(target, answers)
354 let target = get_md4 s 0 in
355 let answers, pos = get_list16
(fun s pos ->
356 let uid = get_md4 s pos in
357 let tags, pos = get_list8
(get_tag
names_of_tag)
364 (_
, first_tags
) :: _
->
365 let sources = ref false in
366 List.iter
(fun tag
->
367 if tag
.tag_name
= Field_KNOWN
"sourceport" then sources := true;
370 let peers = get_peers_from_results ip port
answers in
371 OvernetPublishSources
(target, peers)
374 OvernetPublishFiles
(target, answers)
376 OvernetPublishFiles
(target, answers)
380 let target = get_md4 s 0 in
381 OvernetPublished
target
384 #define KADEMLIA_SRC_NOTES_RES 0x3A // <HASH (key) [16]> <CNT1 [2]> (<HASH (answer) [16]> <CNT2 [2]> <META>*(CNT2))*(CNT1)
385 #define KADEMLIA_PUB_NOTES_REQ 0x42 // <HASH (key) [16]> <HASH (target) [16]> <CNT2 [2]> <META>*(CNT2))*(CNT1)
386 #define KADEMLIA_PUB_NOTES_RES 0x4A // <HASH (key) [16]>
387 #define KADEMLIA_FIREWALLED_REQ 0x50 // <TCPPORT (sender) [2]>
388 #define KADEMLIA_FINDBUDDY_REQ 0x51 // <TCPPORT (sender) [2]>
389 #define KADEMLIA_CALLBACK_REQ 0x52 // <TCPPORT (sender) [2]>
390 #define KADEMLIA_FIREWALLED_RES 0x58 // <IP (sender) [4]>
391 #define KADEMLIA_FIREWALLED_ACK 0x59 // (null)
392 #define KADEMLIA_FINDBUDDY_RES 0x5A // <TCPPORT (sender) [2]>
396 OvernetUnknown
(opcode
, String.sub
s 1 (String.length
s - 1))
398 let udp_buf = Buffer.create
2000
400 let kademlia_header_code = char_of_int
0xE4
401 let kademlia_packed_header_code = char_of_int
0xE5
402 let kademlia_header = String.make
1 kademlia_header_code
403 let kademlia_packed_header = String.make
1 kademlia_packed_header_code
405 let parse_message ip port pbuf
=
406 let len = String.length pbuf
in
408 (let magic = pbuf
.[0] in
409 magic <> kademlia_header_code &&
410 magic <> kademlia_packed_header_code) then
412 if !CommonOptions.verbose_unknown_messages
then begin
413 lprintf_nl "Received unknown UDP packet";
420 let magic = pbuf
.[0] in
421 let opcode = int_of_char pbuf
.[1] in
422 let msg = String.sub pbuf
2 (len-2) in
423 let msg = if magic = kademlia_packed_header_code then
424 let s = Zlib2.uncompress_string2
msg in
425 (* lprintf "Uncompressed:\n";
430 let t = parse ip port
opcode msg in
433 let udp_send sock
ip port ping
msg =
435 Buffer.reset
udp_buf;
437 let s = Buffer.contents
udp_buf in
440 if String.length
s > 200 then
441 let opcode = String.sub
s 0 1 in
442 let args = String.sub
s 1 (String.length
s - 1) in
443 kademlia_packed_header ^
opcode ^
(Zlib2.compress_string
args)
448 if !verbose_overnet
then
450 lprintf_nl "UDP to %s:%d op 0x%02X len %d type %s"
451 (Ip.to_string
ip) port
(get_uint8
s 1) (String.length
s) (message_to_string
msg);
454 let len = String.length s in
455 let t = parse_message ip port s in
456 if t <> msg then begin
457 lprintf "********** SENT MESSAGE DIFFERS FROM EXPECTED ******\n";
461 UdpSocket.write sock ping
(Bytes.unsafe_of_string
s) ip port
463 | MessageNotImplemented
-> ()
464 | e
-> lprintf_nl "Exception %s in udp_send" (Printexc2.to_string e
)
466 let udp_handler f sock event
=
468 UdpSocket.READ_DONE
->
469 UdpSocket.read_packets sock
(fun p ->
471 let pbuf = p.UdpSocket.udp_content
in
474 match p.UdpSocket.udp_addr
with
475 Unix.ADDR_INET
(inet
, port
) ->
476 Ip.of_inet_addr inet
, port
479 let t = parse_message ip port
(Bytes.unsafe_to_string
pbuf) in
480 let is_not_banned ip =
481 match !Ip.banned
(ip, None
) with
484 if !verbose_overnet
then
485 lprintf_nl "%s blocked: %s" (Ip.to_string
ip) reason
;
488 if is_not_banned ip then f
t p
490 if !verbose_unknown_messages
then
492 lprintf_nl "Error %s in udp_handler, dump of packet:"
493 (Printexc2.to_string e
);
494 dump
(Bytes.unsafe_to_string
p.UdpSocket.udp_content
);
500 let checking_kind_timeout = 120
502 let redirector_section = "DKKA"
503 let options_section_name = "Kademlia"
505 let enable_overnet = enable_kademlia
506 let source_brand = false
508 let overnet_section = file_section donkey_ini
509 [ options_section_name ]
513 define_option
overnet_section [options_section_name; "port"]
515 int_option
(2000 + Random.int 20000)
517 let overnet_tcpport = donkey_port
518 let command_prefix = "kad_"
521 let web_info_descr = "Kad network boot peers"
524 module Kademlia
= Make
(P
)