首页 Emule Kad 网络分析

Emule Kad 网络分析

举报
开通vip

Emule Kad 网络分析Emule Kad协议手册 文档编写:kernel,huby 版权所有: emuledev@verycd.com 3 一、概述 3 二、协议参数分析 3 2.1 BootStrap Req/Res 4 2.2 Hello Req/Res 4 2.3 Kad Req/Res 5 2.4 Kad Search/Publish Req/Res 6 2.5 Kad Firewalled Req/Res 6 2.6 Kad FindBuddy Req/Res 6 2.7 kad Call...

Emule Kad 网络分析
Emule Kad协议手册 文档编写:kernel,huby 版权所有: emuledev@verycd.com 3 一、概述 3 二、协议参数分析 3 2.1 BootStrap Req/Res 4 2.2 Hello Req/Res 4 2.3 Kad Req/Res 5 2.4 Kad Search/Publish Req/Res 6 2.5 Kad Firewalled Req/Res 6 2.6 Kad FindBuddy Req/Res 6 2.7 kad Callback Req 7 三、KAD Search Action 7 3.1、SendFindValue 8 3.2、StorePackt 8 3.2.1 GetInfo相关协议: 8 3.2.2 Publish 相关协议: 9 四、Emule Buddy机制分析 9 4.1 网络协议包序列图: 11 五、Emule Kad 数据结构分析 12 附录1( OPCode List): 14 附录2(Question List): 一、概述 Kad使用UDP协议,通过eMule软件的UDP端口发送和接收数据 这个宏定义了我能够接受的KAD最高版本 #define KADEMLIA_VERSION 0x02 在ed2k协议里面被使用 CUpDownClient::SendHelloTypePacket Kad版本:分为1.0和2.0 区别:使用两套独立的opcode 从2.0开始具有可扩展性,将版本信息写入协议,日后的扩展不再需要修改opcode 0.47a默认使用的版本为Kad1.0,但是支持2.0 0.47c没有测试过 KAD协议基本上是成对的一个REQ(Request)就有一个对应的RES(Respone) 所有具有KAD头的包,(有些可能是压缩的),最终被送到Kademlia::Process中处理 Process处理各种不同的opcode并将这些数据送到对应的处理函数,在REQ消息的处理函数中,解析发送过来的数据,并且构造RES数据包并发送出去 二、协议参数分析 2.1 BootStrap Req/Res 0x00 KADEMLIA_BOOTSTRAP_REQ 发送请求,这个时候急需扩大自己的KAD网络 总共发送25B, 参照CKademliaUDPListener::SendMyDetails 16B The sender Kad ID 4B The sender IP 2B The sender UDP Port 2B The sender TCP Port 1B 0 0x08 KADEMLIA_BOOTSTRAP_RES Packet Param: 返回20个Peer信息+自己的信息 KADEMLIA2_BOOTSTRAP_REQ KADEMLIA2_BOOTSTRAP_RES 2.2 Hello Req/Res 0x10 KADEMLIA_HELLO_REQ 总共发送2B+25B, 参照CKademliaUDPListener::SendMyDetails 1B OP_KADEMLIAHEADER 1B byOpcode 16B The sender Kad ID 4B The sender IP 2B The sender UDP Port 2B The sender TCP Port 1B 0 0x18 KADEMLIA_HELLO_RES 回应KADEMLIA_HELLO_REQ,协议包格式和KADEMLIA_HELLO_REQ一样 KADEMLIA2_HELLO_REQ 参照CKademliaUDPListener::SendMyDetails 1B OP_KADEMLIAHEADER 1B byOpcode 16B The Sender KadId 2B The sender UDP Port 1B KADEMLIA_VERSION 1B Tag Count(2) 1B+32B TAG_USER_COUNT(uint32) 1B+32B TAG_FILE_COUNT(uint32) KADEMLIA2_HELLO_RES 回应KADEMLIA2_HELLO_REQ,协议包格式和KADEMLIA2_HELLO_REQ一样 我们可以看到,在2.0版本中,KadHello交换数据包括了自己Kad中已知的用户数和文件数, 但接收方都没有处理其中的Tag信息 2.3 Kad Req/Res 0x20 KADEMLIA_REQ 向一个Contact发送KAD Search 请求,希望得到更接近一个Hash 值的Contact 信息 Search类型包括:KADEMLIA_FIND_VALUE KADEMLIA_STORE KADEMLIA_FIND_NODE 参考 CSearch::SendFindValue(CContact* pContact) 1B OP_KADEMLIAHEADER 1B byOpcode 1B Search Tye 16B Target Hash 16B 当前Contacting 的Contact ID 0x28 KADEMLIA_RES 返回更接近一个hash value的Contact信息, 这样我们可以获得更加逼近hash的Contact 信息,也就是说我们更加有可能找到含有这个hash信息的Contact 〔回应方不管具体的Search类型,只是把有更接近Target的Contact 发送给请求方〕 参考 CKademliaUDPListener::Process_KADEMLIA_REQ 和 CKademliaUDPListener::Process_KADEMLIA_RES 1B OP_KADEMLIAHEADER 1B byOpcode 16B Target UINT128 1B 更接近Target的Contact Count // Max count is 32. size 817.. // 16B + 1B + 25B(32) n*25B 16B Contact ID 4B IP 2B UDP Port 2B TCP Port 1B Type (发送这个信息时有填写ContactType值,但Response中处理的时候好像没处理) Kad2.0 0x21 KADEMLIA2_REQ 参考 CSearch::SendFindValue(CContact* pContact) 1B OP_KADEMLIAHEADER 1B byOpcode 1B Search Tye 16B Target Hash 16B 当前Contacting 的Contact ID 0x29 KADEMLIA2_RES 参考 CKademliaUDPListener::Process_KADEMLIA2_REQ 和 CKademliaUDPListener::Process_KADEMLIA2_RES 1B OP_KADEMLIAHEADER 1B byOpcode 16B Target UINT128 1B 更接近Target的Contact Count // Max count is 32. size 817.. // 16B + 1B + 25B(32) n*25B 16B Contact ID 4B IP 2B UDP Port 2B TCP Port 2.4 Kad Search/Publish Req/Res 在kad 网络内获取需要的索引信息或发布信息 GetInfo相关协议: KADEMLIA_SEARCH_REQ //UnUsed(老的协议) KADEMLIA_SEARCH_NOTES_REQ KADEMLIA2_SEARCH_KEY_REQ KADEMLIA2_SEARCH_SOURCE_REQ KADEMLIA2_SEARCH_NOTES_REQ KADEMLIA_SEARCH_RES KADEMLIA_SEARCH_NOTES_RES KADEMLIA2_SEARCH_RES Publish 相关协议: KADEMLIA_PUBLISH_REQ //UnUsed(老的协议) KADEMLIA_PUBLISH_NOTES_REQ KADEMLIA2_PUBLISH_KEY_REQ KADEMLIA2_PUBLISH_SOURCE_REQ KADEMLIA2_PUBLISH_NOTES_REQ KADEMLIA_PUBLISH_RES KADEMLIA_PUBLISH_NOTES_RES KADEMLIA2_PUBLISH_RES 2.5 Kad Firewalled Req/Res 请求别的Peer检测自己是否FireWalled 0x50 KADEMLIA_FIREWALLED_REQ 0x58 KADEMLIA_FIREWALLED_RES 2.6 Kad FindBuddy Req/Res Emule 中的LowId 需要积极主动找 HighId作自己的Buddy,以便于和其它Peer通信 Exam: LowId(A) 主动FindBuddy HighId(B) 0x51 KADEMLIA_FINDBUDDY_REQ //packet param: <128bit Target(Low.A KadId~)> 0x5a KADEMLIA_FINDBUDDY_RES //packet param: //B在接收到了FINDBUDDY_REQ之后,立即回答自己的TCP Port Buddy 之间互相保持通信联系: OP_BUDDYPING Param OP_BUDDYPONG Param 20Minute间隔交互PINGPONG一次,并且HighId一方有防止LowId 频繁发送PING(LowId至少必须间隔10Min发送一次) 2.7 kad Callback Req 0x52 KADEMLIA_CALLBACK_REQ OP_CALLBACK 三、KAD Search Action KAD 网络中的Search 主要分为以下三组Action操作: #define KADEMLIA_FIND_VALUE 0x02 #define KADEMLIA_STORE 0x04 #define KADEMLIA_FIND_NODE 0x0B ActionType SearchType 说明 KADEMLIA_FIND_VALUE STOREFILE STOREKEYWORD STORENOTES FINDBUDDY KADEMLIA_STORE FILE KEYWORD NOTES: FINDSOURCE: KADEMLIA_FIND_NODE NODE: NODECOMPLETE: Kad的操作又分为两个阶段 (Ⅰ)先尽量找到与Target最近的 的Contact〔SendFindValue〕 (Ⅱ)直到找不到更近的Contact后,就在当前最近的Contact开始做具体的StorePacket Value操作(Publish or GetInfo) [Emule目前代码实现是:一个Contact如果3s之内没有返回更接近Target的Contact,则可以对该Contact进行Value操作了] 3.1、SendFindValue 查找与Target 更接近的 的Contact: # Trace: Kad SendFindValue(CContact* pContact) CallStack CSearch::Go( ) |->CSearch::SendFindValue( ... ) CSearch::JumpStart( ) |->CSearch::SendFindValue CSearch::ProcessResponse |->CSearch::SendFindValue //从Res结果中筛选出最好,继续SendFindValue 相关协议: KADEMLIA_REQ KADEMLIA2_REQ KADEMLIA_RES KADEMLIA2_RES 3.2、StorePackt 对Contact 发包,完成不同Action的Value操作 (主要是Publish和GetInfo) #Trace: Csearch::StorePackt CKademlia::Process( ) |->CSearchManager::JumpStart( ) |->CSearch::JumpStart( ) |->CSearch::StorePacket( ) 3.2.1 GetInfo相关协议: KADEMLIA_SEARCH_REQ //UnUsed(老的协议) KADEMLIA_SEARCH_NOTES_REQ KADEMLIA2_SEARCH_KEY_REQ KADEMLIA2_SEARCH_SOURCE_REQ KADEMLIA2_SEARCH_NOTES_REQ KADEMLIA_SEARCH_RES KADEMLIA_SEARCH_NOTES_RES KADEMLIA2_SEARCH_RES 3.2.2 Publish 相关协议: KADEMLIA_PUBLISH_REQ //UnUsed(老的协议) KADEMLIA_PUBLISH_NOTES_REQ KADEMLIA2_PUBLISH_KEY_REQ KADEMLIA2_PUBLISH_SOURCE_REQ KADEMLIA2_PUBLISH_NOTES_REQ KADEMLIA_PUBLISH_RES KADEMLIA_PUBLISH_NOTES_RES KADEMLIA2_PUBLISH_RES 四、Emule Buddy机制分析 Emule 中的Buddy 机制是为了增进Emule中HihgId-LowId/LowId-LowId的通信,使得一个公网的Peer可以和处于NAT内的Peer之间相互通信,同时加上适当的策略,也可以让两个处于NAT内的Peer之间相互通信。下面是关于Emule Buddy的一些分析结论: LowId 发现自己处于NAT内时,则主动开始在Kad网络内寻找Buddy,如果一个HighId没有为别的LowId做Buddy,则可以成为该LowId的Buddy。 LowId 的Buddy 必须是 HighId,反之,HighId的Buddy必须是LowId。 目前,0.47c 版本的Buddy 机制还是一对一。 LowId不是在自己的KadId周围附近找Buddy,是在KadId~方向找自己的Buddy,这样可以增进Kad网络的交互,不会引起小范围内的信息孤岛现象。 一个LowId 拿到HighId的Buddy后就可以向Kad网络内发布自己的Peer信息了。 〔发布信息包含: 自己的KadId~,Buddy IP,Buddy Udp Port〕 第一次的FINDBUDY 必须是在程序启动后的五分钟之后,因为之后的FINDBUDDY 是在丢失了 BUDDY 之后进行(但同时) 4.1 网络协议包序列图: 4.2 FindBuddy 过程状态图 4.3 Buddy实现框架代码List: # LowId(A) ① 发送 KADEMLIA_FINDBUDDY_REQ CSearch::StorePacket( ) { Case FINDBUDDY: //packet param: <128bit Target(Low.A KadId~)> CKademlia::GetUDPListener()->SendPacket(&m_pfileSearchTerms, KADEMLIA_FINDBUDDY_REQ, pFromContact->GetIPAddress(), pFromContact->GetUDPPort()); } ② 接收 KADEMLIA_FINDBUDDY_RES CKademliaUDPListener::Process_KADEMLIA_FINDBUDDY_RES (const byte *pbyPacketData, uint32 uLenPacket, uint32 uIP, uint16 uUDPPort) { theApp.clientlist->RequestBuddy(&contact); // now Peer.B Kad State is KS_QUEUED_BUDDY } ③ Low.A TryToConnect to High.B CClietList::Process( ... ) { cur_client->SetKadState(KS_CONNECTING_BUDDY);// Peer.B KadState Changed to KS_CONNECTING_BUDDY cur_client->TryToConnect(true); // Low.A TryToConnect to High.B } ④ Low.A 连接 High.B 成功 CUpDownClient::ConnectionEstablished() { … case KS_CONNECTING_BUDDY: SetKadState(KS_CONNECTED_BUDDY); //Peer.B Kad State changed to KS_CONNECTED_BUDDY } # HighId(B) ① 接收 KADEMLIA_FINDBUDDY_REQ CKademliaUDPListener::Process_KADEMLIA_FINDBUDDY_REQ (const byte *pbyPacketData, uint32 uLenPacket, uint32 uIP, uint16 uUDPPort) { theApp.clientlist->IncomingBuddy(&contact, &BuddyID); //Peer.A Kad State is KS_INCOMING_BUDDY //回发 KADEMLIA_FINDBUDDY_RES packet //packet param: SendPacket(&fileIO2, KADEMLIA_FINDBUDDY_RES, uIP, uUDPPort); } ② CUpDownClient::ConectionEstablished( ) { case KS_INCOMING_BUDDY: SetKadState(KS_CONNECTED_BUDDY); //Peer.A Kad State changed to KS_CONNECTED_BUDDY } 五、Emule Kad 数据结构分析 附录1( OPCode List): 关于KAD的Opcodes,Kad1.0个2.0相互对应 // KADEMLIA (opcodes) (udp) #define KADEMLIA_BOOTSTRAP_REQ 0x00 // #define KADEMLIA2_BOOTSTRAP_REQ 0x01 // #define KADEMLIA_BOOTSTRAP_RES 0x08 // *(CNT) #define KADEMLIA2_BOOTSTRAP_RES 0x09 // #define KADEMLIA_HELLO_REQ 0x10 // #define KADEMLIA2_HELLO_REQ 0x11 // #define KADEMLIA_HELLO_RES 0x18 // #define KADEMLIA2_HELLO_RES 0x19 // #define KADEMLIA_REQ 0x20 // #define KADEMLIA2_REQ 0x21 // #define KADEMLIA_RES 0x28 // *(CNT) #define KADEMLIA2_RES 0x29 // #define KADEMLIA_SEARCH_REQ 0x30 // [ext] //#define UNUSED 0x31 // Old Opcode, don't use. #define KADEMLIA_SEARCH_NOTES_REQ 0x32 // #define KADEMLIA2_SEARCH_KEY_REQ 0x33 // #define KADEMLIA2_SEARCH_SOURCE_REQ 0x34 // #define KADEMLIA2_SEARCH_NOTES_REQ 0x35 // #define KADEMLIA_SEARCH_RES 0x38 // ( *(CNT2))*(CNT1) //#define UNUSED 0x39 // Old Opcode, don't use. #define KADEMLIA_SEARCH_NOTES_RES 0x3A // ( *(CNT2))*(CNT1) #define KADEMLIA2_SEARCH_RES 0x3B // #define KADEMLIA_PUBLISH_REQ 0x40 // ( *(CNT2))*(CNT1) //#define UNUSED 0x41 // Old Opcode, don't use. #define KADEMLIA_PUBLISH_NOTES_REQ 0x42 // *(CNT2))*(CNT1) #define KADEMLIA2_PUBLISH_KEY_REQ 0x43 // #define KADEMLIA2_PUBLISH_SOURCE_REQ 0x44 // #define KADEMLIA2_PUBLISH_NOTES_REQ 0x45 // #define KADEMLIA_PUBLISH_RES 0x48 // //#define UNUSED 0x49 // Old Opcode, don't use. #define KADEMLIA_PUBLISH_NOTES_RES 0x4A // #define KADEMLIA2_PUBLISH_RES 0x4B // #define KADEMLIA_FIREWALLED_REQ 0x50 // #define KADEMLIA_FINDBUDDY_REQ 0x51 // #define KADEMLIA_CALLBACK_REQ 0x52 // #define KADEMLIA_FIREWALLED_RES 0x58 // #define KADEMLIA_FIREWALLED_ACK_RES 0x59 // (null) #define KADEMLIA_FINDBUDDY_RES 0x5A // 附录2(Question List): 1 对方的KadId 是怎么知道的? :如果这个Source是server告诉我的,那么就发Hello后知道的? :对方通过kad opcode 协议发Source告诉我的(20个)? 存储在自己的KadContact列表中等待处理 2 对方的Buddy信息我是怎么知道的? 在tcp hello的时候,有两个tag指明buddy的ip和udpport 之后当我们要通知LowID的Peer来callback我的时候,我们调用CUpDownClient::TryToConnect,发用KAD消息给BUDDY,并把这个Client的连接状态设定为等待回连(DS_WAITCALLBACKKAD) 3 Buddy是怎么确认的?(怎么在多个Contact中选一个作为我的Buddy) KadState切换顺序? 4 Buddy相互之间(LowId<->HighId)如何长期保持联系? 当Buddy连接后会通过Ping的方式保持连接,Ping的发送方是LowID,每10分钟发送一次OP_BUDDYPING,而HighID在延时大于13分钟才回复一次OP_BUDDYPONG,这样导致的结果是最终LowID Ping两次HighID回复一次。 Buddy现在是一对一的,可以做成一对多吗?可以有小量Peer抱成团吗? 需要修改数据结构 我认为可以做成一对多,可以增加一个BuddyList来保存 5 Kad1,Kad2 ?什么时候开始用Kad2? Kad2 兼容Kad1 是怎么做到的? 我们可以很方便的扩充Kad2吗? 当对方的用户使用KAD2的opcode请求的时候,我们就使用KAD2的opcode进行回复 由于KAD1和2使用不同的opcode,所以只要实现这两套opcode的process函数就可以轻松处理 KAD1和2的主要功能是重复的,但是有一些小的改进,比如在KAD2中HELLO支持Tag,并且加入了两个Tag,内容分别是Peer自己KAD所知的用户数和文件数(这些信息可能用来改善KAD的算法) 25个字节的Peer信息最后一个字节被设定为KAD版本信息,KAD2的改进 此外,我们需要得到对方支持的opcode的最高版本,在tcp hello握手的时候会相互交换信息。 KAD2的扩展是有可能的,但是如果增加版本号,有可能和未来的KAD协议相冲突。在某些OPCODE中增加Tag信息,则是有可能的。 6 所有不同way拿到的source,都包含了这个Peer的哪些信息? 如果需要一个Peer更丰富的信息,通过哪些途径可以获取信息? :以下途径都可以获取Source,但获取的信息都不一定是完整的 SF_SERVER SF_KADEMLIA SF_SOURCE_EXCHANGE SF_PASSIVE SF_LINK 7 是怎么表示我是否已经有了Buddy? 在CClientList中Process不断处理KAD的状态转换,当状态是KS_CONNECTED_BUDDY的时候就说明已经有连接,此时必须每隔一段时间发送PING PONG等成对的opcode 是通过CClientList的成员变量 m_nBuddyStatus 来表示当前的Buddy的状态的。Buddy的状态如下: enum buddyState {         Disconnected,    // 没有连接上Buddy         Connecting,      // 正在连接Buddy         Connected       // 已经连接上Buddy }; CClientList创建时m_nBuddyStatus = Disconnected Buddy的状态为未连接。具体的状态切换我已经在图四里面用绿色字体标示出来了。 8 第一次加入Kad应该做什么?是怎么加入kad的 ? 需要更多Contact的时候发 BootStrap Req 吗? 确定是否已经加入了KAD网络,调用CKademlia::IsConnected()来检测 IsConnected()函数调用m_pInstance->m_pPrefs->HasHadContact(); 来确定,也就是说,我们加入KAD网络的标准就是有没有联系人(当然是活动的,不是存储的静态列表) 9 、一个peer的Buddy丢了以后,重新找了Buddy,别的peer 怎么知道呢?
本文档为【Emule Kad 网络分析】,请使用软件OFFICE或WPS软件打开。作品中的文字与图均可以修改和编辑, 图片更改请在作品中右键图片并更换,文字修改请直接点击文字进行修改,也可以新增和删除文档中的内容。
该文档来自用户分享,如有侵权行为请发邮件ishare@vip.sina.com联系网站客服,我们会及时删除。
[版权声明] 本站所有资料为用户分享产生,若发现您的权利被侵害,请联系客服邮件isharekefu@iask.cn,我们尽快处理。
本作品所展示的图片、画像、字体、音乐的版权可能需版权方额外授权,请谨慎使用。
网站提供的党政主题相关内容(国旗、国徽、党徽..)目的在于配合国家政策宣传,仅限个人学习分享使用,禁止用于任何广告和商用目的。
下载需要: 免费 已有0 人下载
最新资料
资料动态
专题动态
is_796324
暂无简介~
格式:doc
大小:124KB
软件:Word
页数:16
分类:
上传时间:2011-11-07
浏览量:33