必知的技术知识:eDonkey协议

简介: 必知的技术知识:eDonkey协议

-->


1.简介


ED2K 协议 用于对等的客户端之间的通讯,众多对等的客户端形成了基于服务器的P2P文件共享网络。


下面几个词语用于包格式字符串:


u8 unsigned 8-bit integer


u16 unsigned 16-bit integer


u32 unsigned 32-bit integer


hash 16-bytes md4 checksum


string 16-bit integer (specifying string length) followed by the string


Taglist 32-bit integer (specifying number of tags) followed by the tags


一些定义:


part:


最大9500kb的文件片断,每个片断都有对应的MD4 PartHash.


chunk:


最大180kb的文件片断,每个片断都可以被远程的客户端请求


block:


chunk片断,每个片断被封装成单独的数据包在客户端之间传输。


2.Header 规格


+--------+--------+--------+--------+--------+--------+--------+--------+----


|protocol| packet length | packet data (length bytes)


+--------+--------+--------+--------+--------+--------+--------+--------+----


每个ED2K包协议以协议代码开始,后面跟着的是包的长度(32-bit unsigned的整数)。


现在的协议代码有下面三个:


PR_ED2K = 0xe3, //!< Standard, historical eDonkey2000 protocol


PR_EMULE = 0xc5, //!< eMule extended protocol


PR_ZLIB = 0xd4 //!< Packet payload is compressed with gzip


包数据通常以8-bit的代码开始,用于指示包的内容,如果以PR_ZLIB协议发送包,


包的数据经过压缩的。


3.客户端-服务端通讯


3.1 登陆服务器


客户端如果要连接到eDonkey2000服务器,发送OP_LOGINREQUEST给服务器.


OP_LOGINREQUEST = 0x01, //!< hashipporttags


这个包可能包括下面的标签(tags):


CT_NICK = 0x01, //!< nick


CT_VERSION = 0x11, //!< 0x3c


CT_PORT = 0x0f, //!< port


CT_MULEVERSION = 0xfb, //!< ver


CT_FLAGS = 0x20, //!< flags


flags可能包含下面信息:


FL_ZLIB = 0x01, //!< zlib compression support


FL_IPINLOGIN = 0x02, //!< Client sends its own ip during login


FL_AUXPORT = 0x04, //!< ?


FL_NEWTAGS = 0x08, //!< support for new-styled eMule tags


FL_UNICODE = 0x10 //!< support for unicode


对一个良好格式的OP_LOGINREQUEST包,服务器先以这个包报告的监听端口尝试连接到发送这个数据包的客户端,


之后如果服务器收到一个OP_HELLOANSWER包,说明连接成功,那么服务为该客户端分配一个高ID,否则可能是因为某些原因连接失败,那么//代码效果参考:http://www.lyjsj.net.cn/wx/art_24177.html

为该客户端分配一个低ID。

服务器发送下面的数据包通知客户端连接已经建立,同时也提供了和服务器有关的更新信息。


OP_SERVERMESSAGE = 0x38, //!< lenmessage


OP_SERVERSTATUS = 0x34, //!< usersfiles


OP_IDCHANGE = 0x40 //!< newid


注意:Lugdunum 16.44+服务器(什么来的?)发送一个附加的u32的ID_CHANGE数据包,包含了一些支持特性,包括:


FL_ZLIB = 0x01, //!< zlib compression support


FL_NEWTAGS = 0x08, //!< support for new-styled eMule tags


FL_UNICODE = 0x10 //!< support for unicode


3.2 更新服务器列表和信息


和服务器建立连接之后,客户端可以象服务器请求其他信息,象服务器列表:


OP_GETSERVERLIST = 0x14, //!< (no payload)


服务器用下面的包回应:


OP_SERVERLIST = 0x32, //!< count【{ipport}count】


OP_SERVERIDENT = 0x41, //!< hashipporttags


后面包含着下面的tags:


CT_SERVERNAME = 0x01, //!< name


CT_SERVERDESC = 0x0b //!< desc


3.2 发布共享文件


和服务器建立连接之后,客户端必须用OP_OFFERFILES包发布共享文件,如果服务器支持的话这些包必须被压缩以节省带宽。


//! count【{filehashipporttags}】


OP_OFFERFILES = 0x15,


这个包可能包含下面的tags:


CT_FILENAME = 0x01, //!< name


CT_FILESIZE = 0x02, //!< size


CT_FILETYPE = 0x03, //!< type


注意:


文件类型用字符串发送,下面的字符串会被识别:


#define FT_ED2K_AUDIO "Audio" //!< mp3/ogg/wma etc


#define FT_ED2K_VIDEO "Video" //!< avi/mpg/mpeg/wmv etc


#define FT_ED2K_IMAGE "Image" //!< png/jpg/gif/tiff etc


#define FT_ED2K_DOCUMENT "Doc" //!< txt/doc/rtf etc


#define FT_ED2K_PROGRAM "Pro" //!< exe/bin/cue/iso etc


这个包在下面时机会被发送:


.拥有一个共享文件列表,并连接到服务器的时候。


.添加新的共享文件的时候。


.As empty packet, as server keep-alive packet at regular intervals Additionally,可以用两对特殊的IP/PORT 值来指示共享的文件是部分的还是完整的。


FL_COMPLETE_ID = 0xfcfcfcfc, //!< File is complete - send this as ID


FL_COMPLETE_PORT = 0xfcfc, //!< File is complete - send this as port


FL_PARTIAL_ID = 0xfbfbfbfb, //!< File is partial - send this as ID


FL_PARTIAL_PORT = 0xfbfb //!< File is partial - send this as port


3.3 搜索


搜索在eDonkey2000网络是基于服务器的。客户端发送SEARCHR包给服务器,接着服务器返回一个或多个SEARCHRESULT包。这些都只是和当前连接的服务器的TCP层进行。但是,客户端也可以用GLOBSEARCH代码,通过UDP发送相同的请求包给所有已经的服务器,之后服务器也会用 GLOBSEARCHRES包回应(也是UDP)。


OP_SEARCH = 0x16, //!<


//! count【{hashidporttags}】


OP_SEARCHRESULT = 0x33,


搜索结果可能包含下面的tags:


CT_FILENAME = 0x01, //!< name


CT_FILESIZE = 0x02, //!< size


CT_FILETYPE = 0x03, //!< type


CT_SOURCES = 0x15, //!< numsrc


CT_COMPLSRC = 0x30, //!< numcomplsrc


4.客户端 - 客户端通信


4.1 get-to-know-you chit-chat


为了初始化和远程客户端的连接,客户端先要发送 Hello 包,


OP_HELLO = 0x01, //!< hashipporttags


Hello 可以 包含下面的 tags:


CT_NICK = 0x01, //!< nick


CT_PORT = 0x0f, //!< port


CT_MULEVERSION = 0xfb, //!< ver


CT_MODSTR = 0x55, //!< modstring


CT_UDPPORTS = 0xf9, //!< kadudpported2kudpport


CT_MISCFEATURES = 0xfa, //!< features bitset


对OP_HELLO正确的回应是OP_HELLOANSWER。这个HelloAnswer包的格式和OP_HELLO是一样的,只是HelloAnswer还包括了8-bit的hash长度。这个域的值必须是0x0f。


CT_MULEVERSION是一个32-bit的值,下面是bits的意义:


1 2 3 4 5 【bytes】


11111111222222233333334445555555 【bits】


00000000000000001010101100000000 eMule 42g version info


| | | | +---- Build version (unused by eMule)


| | | +--------- Update version 6 (a = 0, g = 6)


| | +-------------- Minor version 42


| +--------------------- Major version (unused by eMule)


+---------------------------- Compatible Client ID (CS_EMULE = 0x00)


如果两个客户端是eMule-compatible兼容的,那么他们必须交换MuleInfo包:


OP_MULEINFO = 0x01, //!< clientverprotvertags


OP_MULEINFOANSWER = 0x02 //!< clientverprotvertags


注意:所有这两个包都是用PR_EMULE来发送的。


在MuleInfo包里面的tags有:


CT_COMPRESSION = 0x20, //!< u32 compression version


CT_UDPPORT = 0x21, //!< u32 udp port


CT_UDPVER = 0x22, //!< u32 udp protocol version


CT_SOURCEEXCH = 0x23, //!< u32 source exchange version


CT_COMMENTS = 0x24, //!< u32 comment version


CT_EXTREQ = 0x25, //!< u32 extended request version


CT_COMPATCLIENT = 0x26, //!< u32 compatible client ID


CT_FEATURES = 0x27, //!< u32 supported features bitset


CT_MODVERSION = 0x55, //!< modversion (may also be int)


CT_MODPLUS = 0x99, //!< mh? (Source: eMule+ Forums ... )


CT_L2HAC = 0x3e, //!< mh? (Source: eMule+ Forums ... )


Feature 集标志为 是32-bit 值,意义如下:


12345678123456781234567812345678


00000100000100110011001000011110 eMule 43b


00110100000100110011001000011110 eMule 44b


11123333444455556666777788889abc


| | | | | | | | |||+-- Preview


| | | | | | | | ||+--- Multipacket


| | | | | | | | |+---- No `view shared files' supported


| | | | | | | | +----- Peercache


| | | | | | | +-------- Comments


| | | | | | +----------- Extended requests


| | | | | +---------------- Source exchange


| | | | +-------------------- Secure ident


| | | +----------------------- Data compression version


| | +--------------------------- UDP version


| +------------------------------ Unicode


+-------------------------------- AICH version (0 - not supported)


4.2 请求一个文件


在完成入 4.1所描述的握手之后,客户端现在可以请求一个文件了。这个由ReqFile包来完成。


OP_REQFILE = 0x58, //!< hash


OP_FILENAME和 OP_FILEDESC回应ReqFile


OP_FILENAME = 0x59, //!< hashlenname


OP_FILEDESC = 0x61, //!< ratinglencomment


接收了上面的数据包之后,下载方客户端发送SETREQFILEID 把刚才请求的文件绑定到一个hash上,这意味着现在客户端被绑定到被请求的hash上,直到它接受到它所请求的东西。


FileDesc用 PR_EMULE发送,但并不包含描述所属的文件的hash,然而,由于它经常跟着OP_FILENAME发送,所以客户端可以假定FileDesc属于最近所请求的那个文件。


发送这个包之后客户端会期望得到回应是OP_FILESTATUS


OP_REQFILE_STATUS = 0x50, //!< hashcountpartmap


如果上传方客户端认识到它并没有共享被要求上传的文件,那么它会发送OP_REQFILE_NOFILE。File status包含了有效parts的partmap.这被定义为为一个bitfield,每个bit代表了一个ED2K part(由ED2K_PARTSIZE定义).多处理的bit被0填充。


先于bitset的count指示了总的parts的数量。注意sending partmap完全是可选,并且只有当然共享文件是部分的才可以发送,如果共享文件是完整的,那么partmap将被忽略.


OP_REQFILE_NOFILE = 0x48, //!< hash


如果下载方客户端需要一个文件的hashset,它可以通过发送OP_REQHASHSET向上传方请求。期望得到的回应是OP_HASHSET


OP_REQHASHSET = 0x51, //!< hash


OP_HASHSET = 0x52, //!< hashcnt【cntparthash】


在这之后,请求方发送OP_STARTUPLOADREQ。被请求方要么用OP_ACCEPTUPLOADREQ回应(如果我们能开始正确的上传),要么用OP_QUEUERANKING回应,说明请求方的请求已经被插入到上传队列里了。


OP_STARTUPLOADREQ = 0x54, //!< may contain hash (emule)


OP_ACCEPTUPLOADREQ = 0x55, //!< Empty


OP_QUEUERANKING = 0x5c, //!< queueranking


4.3 上传文件数据


接收到OP_ACCEPTUPLOADREQ之后,下载方客户端将会继续请求chunks。在 eDonkey2000 网络,一个chunck的大小是180k。用OP_REQCHUNKS包请求chunks。


OP_REQCHUNKS = 0x47, //!< hash【3begin】【3end】


这个包包含了被请求的chunks的3个开始偏移和3个结束偏移。ED2K 数据 将结束偏移定义为是唯一的(exclusive),因此象(0, 0)这样的范围被认为是无效的范围。如果下载方客户断请求少于3个chunks,那么这个包可以包含象(0,0)的保留范围来指示。


接收到OP_REQCHUNKS后,上传方客户断开始发送数据。被请求的chunks 被分成最大10kb的blocks,每个blocks用OP_SENDINGCHUNK作为单独的数据包传送,


OP_SENDINGCHUNK = 0x46, //!< hashbeginend


当下载方客户端决定不再接收任何数据的时候,它可以发送OP_CANCELTRANSFER包给上传方客户端。


OP_CANCELTRANSFER = 0x56 //!< empty


5 低ID客户端


低ID客户端在ed2k网络被定义这样的客户端:


无法接收外部连接的客户断。这样的客户端只能自己主动创建外部连接。连接低ID客户端唯一的方法就是通过服务器的回调,只要这个客户端已经连接到服务器。只有连接到同样的服务器的客户端才能连接到低ID客户端。低ID客户端在网络中被分配小于0x00ffffff的ID。这也是很多地方我们把IP称为ID的原因,因为如果客户端的ID大于0x00ffffff,那么ID就是该客户端的IP,否则就是该客户端的回调ID,由服务器分配。


5.1 连接到低ID客户端


要想连接到低ID客户端,必须发送OP_REQCALLBACK包给当前连接的服务器,这个包含了我们要连接的客户端的ID。


OP_REQCALLBACK = 0x1c, //!< id


如果被要求连接的低ID客户端已经连接到服务器,那么服务器发送OP_CBREQUESTED包给它。


OP_CBREQUESTED = 0x35, //!< iptcpport


如果被要求连接的低ID客户端由于某些原因没有连接到这个服务器,那么服务器将会回应OP_CALLBACKFAIL.


OP_CALLBACKFAIL = 0x36 //!< empty

相关文章
|
5月前
|
存储 机器学习/深度学习 监控
【网络工程师】<软考中级>数据通信基础
【1月更文挑战第27天】【网络工程师】<软考中级>数据通信基础
|
5月前
|
XML 存储 安全
【揭秘SAML协议 — Java安全认证框架的核心基石】 从初识到精通,带你领略Saml协议的奥秘,告别SSO的迷茫与困惑
SAML(Security Assertion Markup Language)是由OASIS制定的基于XML的开放标准。它用于在身份提供者(IdP)和服务提供者(SP)之间交换身份验证和授权数据,从而支持跨域单点登录,提高身份认证和授权管理的安全性和效率。
419 2
【揭秘SAML协议 — Java安全认证框架的核心基石】 从初识到精通,带你领略Saml协议的奥秘,告别SSO的迷茫与困惑
|
5月前
|
网络协议 安全 算法
谷歌出品!读懂 QUIC 协议:更快、更高效的通信协议
谷歌出品!读懂 QUIC 协议:更快、更高效的通信协议
777 0
|
5月前
|
存储 监控 安全
金石推荐 | 【分布式技术专题】「单点登录技术架构」一文带领你好好认识以下Saml协议的运作机制和流程模式
金石推荐 | 【分布式技术专题】「单点登录技术架构」一文带领你好好认识以下Saml协议的运作机制和流程模式
114 1
|
5月前
|
网络协议 安全
【底层服务/编程功底系列】「网络通信体系」带你攻克网络技术之TCP协议的三次握手和四次链接的技术盲区
【底层服务/编程功底系列】「网络通信体系」带你攻克网络技术之TCP协议的三次握手和四次链接的技术盲区
51 0
|
5月前
|
JSON 安全 算法
【揭秘OIDC协议 — Java安全认证框架的核心基石】 从初识到精通,带你领略OIDC协议的奥秘,告别SSO的迷茫与困惑
【揭秘OIDC协议 — Java安全认证框架的核心基石】 从初识到精通,带你领略OIDC协议的奥秘,告别SSO的迷茫与困惑
207 0
|
5月前
|
存储 安全 Java
【揭秘OAuth协议 — Java安全认证框架的核心基石】 从初识到精通,带你领略OAuth协议的奥秘,告别SSO的迷茫与困惑
在现代的网站中,我们经常会遇到需要用户登录的情况。然而,直接要求用户注册可能会显得繁琐,导致用户的流失。为了解决这个问题,网站可以采用OAuth授权机制。通过与像GitHub或其他第三方网站的认证授权合作,网站可以获取用户的相关信息,避免了繁琐的注册过程。
80 0
【揭秘OAuth协议 — Java安全认证框架的核心基石】 从初识到精通,带你领略OAuth协议的奥秘,告别SSO的迷茫与困惑
|
存储 监控 安全
【分布式技术专题】「单点登录技术架构」一文带领你好好认识以下Saml协议的运作机制和流程模式
传统上,企业应用程序在公司网络中部署和运行。为了获取有关用户的信息,如用户配置文件和组信息,这些应用程序中的许多都是为与公司目录(如Microsoft Active Directory)集成而构建的。更重要的是,通常使用目录存储和验证用户的凭据。例如,如果您使用在本地运行的SharePoint和Exchange,则您的登录凭据就是您的Active Directory凭据。
325 1
【分布式技术专题】「单点登录技术架构」一文带领你好好认识以下Saml协议的运作机制和流程模式
|
缓存 网络协议 网络架构
408王道计算机网络强化——传输层和应用层(下)
408王道计算机网络强化——传输层和应用层
338 0
408王道计算机网络强化——传输层和应用层(下)