admin管理员组文章数量:1530842
2023年12月17日发(作者:)
Emule Kad协议手册
文档编写:kernel,huby
版权所有: emuledev@
一、概述 3
二、协议参数分析 ........................................................................................................................... 3
2.1 BootStrap Req/Res .............................................................................................................. 3
2.2 Hello Req/Res ..................................................................................................................... 4
2.3 Kad Req/Res .................................................................................................................... 4
2.4 Kad Search/Publish Req/Res ............................................................................................... 6
2.5 Kad Firewalled Req/Res ..................................................................................................... 6
2.6 Kad FindBuddy 7
2.7 kad Callback Req ................................................................................................................ 7
三、KAD Search Action .................................................................................................................. 7
3.1、SendFindValue ................................................................................................................. 8
3.2、StorePackt ........................................................................................................................ 8
3.2.1 GetInfo相关协议: ................................................................................................ 9
3.2.2 Publish 相关协议: ............................................................................................. 9
四、Emule Buddy机制分析 ............................................................................................................ 9
4.1 网络协议包序列图: ...................................................................................................... 10
五、Emule Kad 数据结构分析 ..................................................................................................... 11
附录1( OPCode List): .................................................................................................................... 12
附录2(Question List): ................................................................................................................. 14
一、概述
Kad使用UDP协议,通过eMule软件的UDP端口发送和接收数据
这个宏定义了我能够接受的KAD最高版本
#define KADEMLIA_VERSION
在ed2k协议里面被使用
CUpDownClient::SendHelloTypePacket
0x02
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
4B
2B
2B
1B
The sender Kad ID
The sender IP
The sender UDP Port
The sender TCP Port
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
1B
16B
4B
2B
2B
1B
0x18
KADEMLIA_HELLO_RES
回应KADEMLIA_HELLO_REQ,协议包格式和KADEMLIA_HELLO_REQ一样
OP_KADEMLIAHEADER
byOpcode
The sender Kad ID
The sender IP
The sender UDP Port
The sender TCP Port
0
KADEMLIA2_HELLO_REQ
参照CKademliaUDPListener::SendMyDetails
1B
1B
16B
2B
1B
1B
1B+32B
1B+32B
KADEMLIA2_HELLO_RES
回应KADEMLIA2_HELLO_REQ,协议包格式和KADEMLIA2_HELLO_REQ一样
OP_KADEMLIAHEADER
byOpcode
The Sender KadId
The sender UDP Port
KADEMLIA_VERSION
Tag Count(2)
TAG_USER_COUNT(uint32)
TAG_FILE_COUNT(uint32)
我们可以看到,在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
1B
1B
16B
16B
OP_KADEMLIAHEADER
byOpcode
Search Tye
Target Hash
当前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
1B
16B
1B
n*25B 16B
4B
2B
2B
1B
Kad2.0
0x21 KADEMLIA2_REQ
参考 CSearch::SendFindValue(CContact* pContact)
1B
1B
1B
16B
16B
0x29 KADEMLIA2_RES
OP_KADEMLIAHEADER
byOpcode
Search Tye
Target Hash
当前Contacting 的Contact ID
OP_KADEMLIAHEADER
byOpcode
Target UINT128
更接近Target的Contact Count
// Max count is 32. size 817.. // 16B + 1B + 25B(32)
Contact ID
IP
UDP Port
TCP Port
Type (发送这个信息时有填写ContactType值,但Response中处理的时候好像没处理)
参考 CKademliaUDPListener::Process_KADEMLIA2_REQ
和 CKademliaUDPListener::Process_KADEMLIA2_RES
1B
1B
16B
1B
n*25B
16B
4B
2B
2B
OP_KADEMLIAHEADER
byOpcode
Target UINT128
更接近Target的Contact Count
// Max count is 32. size 817.. // 16B + 1B + 25B(32)
Contact ID
IP
UDP Port
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
KADEMLIA_FIND_VALUE
KADEMLIA_STORE
SearchType
FILE
KEYWORD
NOTES
FINDSOURCE
STOREFILE
说明
STOREKEYWORD
STORENOTES:
FINDBUDDY
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
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
//UnUsed(老的协议)
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)
{
list->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)
{
list->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
#define KADEMLIA2_BOOTSTRAP_REQ
#define KADEMLIA_BOOTSTRAP_RES
#define KADEMLIA2_BOOTSTRAP_RES
#define KADEMLIA_HELLO_REQ
#define KADEMLIA2_HELLO_REQ
#define KADEMLIA_HELLO_RES
#define KADEMLIA2_HELLO_RES
#define KADEMLIA_REQ
(receiver) 16>
#define KADEMLIA2_REQ
#define KADEMLIA_RES
#define KADEMLIA_SEARCH_REQ
//#define UNUSED
0x31 // Old Opcode, don't use.
0x32 //
0x34 //
0x35 //
0x38 // 0x39 // Old Opcode, don't use. 0x3A // 0x3B // 0x40 // 0x41 // Old Opcode, don't use. 0x42 // #define KADEMLIA_SEARCH_NOTES_REQ #define KADEMLIA2_SEARCH_KEY_REQ #define KADEMLIA2_SEARCH_NOTES_REQ #define KADEMLIA_SEARCH_RES //#define UNUSED [16]> #define KADEMLIA_SEARCH_NOTES_RES #define KADEMLIA2_SEARCH_RES #define KADEMLIA_PUBLISH_REQ //#define UNUSED [16]> #define KADEMLIA_PUBLISH_NOTES_REQ [2]> *(CNT2))*(CNT1) 0x30 // 0x28 // 0x29 // #define KADEMLIA2_RES 0x21 // 0x20 // 0x18 // 0x19 // 0x10 // 0x11 // 0x08 // 0x09 // 0x00 // 0x01 // 0x33 // #define KADEMLIA2_SEARCH_SOURCE_REQ [16]> #define KADEMLIA2_PUBLISH_KEY_REQ #define KADEMLIA2_PUBLISH_SOURCE_REQ #define KADEMLIA2_PUBLISH_NOTES_REQ #define KADEMLIA_PUBLISH_RES //#define UNUSED #define KADEMLIA_PUBLISH_NOTES_RES #define KADEMLIA2_PUBLISH_RES #define KADEMLIA_FIREWALLED_REQ #define KADEMLIA_FINDBUDDY_REQ #define KADEMLIA_CALLBACK_REQ #define KADEMLIA_FIREWALLED_RES #define KADEMLIA_FIREWALLED_ACK_RES #define KADEMLIA_FINDBUDDY_RES 0x43 // 0x44 // 0x45 // 0x48 // 0x49 // Old Opcode, don't use. 0x4A // 0x4B // 0x50 // 0x51 // 0x52 // 0x58 // 0x59 // (null) 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 网络分析 内容由热心网友自发贡献,该文观点仅代表作者本人,
转载请联系作者并注明出处:https://m.elefans.com/dianzi/1702788092a24354.html,
本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论