ZeroNet 网络协议

  • 所有信息都用 MessagePack进行编码
  • 每一个request都有三个参数:
    • cmd: request的命令
    • req_id: request的标识ID (简单地说,一个一次性数值), 客户端在回应命令的时候需要包括它
    • params: request带的参数
  • 示例request: {"cmd": "getFile", "req_id": 1, "params:" {"site": "1EU...", "inner_path": "content.json", "location": 0}}
  • 示例response: {"cmd": "response", "to": 1, "body": "content.json content", "location": 1132, "size": 1132}
  • 示例error response: {"cmd": "response", "to": 1, "error": "Unknown site"}

握手

每个连接都从发送一个到目标网络地址的request——也就是握手请求——开始:

参数 描述
crypt 空,或者为None, 只在response中用到
crypt_supported 连接可用的加密方法的数列,列出了客户端支持的加密方法
fileserver_port 客户端的文件服务端口
onion (只在Tor上使用) 客户端的onion地址
protocol 客户端使用的协议版本 (v1 或者 v2)
port_opened 客户端的端口打开状态
peer_id (不在Tor上使用) 客户端的peer_id
rev 客户端的版本修订号
version 客户端的版本号
target_ip 客户端的IP地址

目标接着通过crypt_supported来在socket上初始化加密,返回:

返回值 描述
crypt 使用的加密方法
crypt_supported 连接可用的加密方法的数列,列出了服务端支持的加密方法
fileserver_port 服务端的文件服务端口
onion (只在Tor上使用) 服务端的onion地址
protocol 服务端使用的协议版本 (v1 或者 v2)
port_opened 服务端的端口打开状态
peer_id (不在Tor上使用) 服务端的peer_id
rev 服务端的版本修订号
version 服务端的版本号
target_ip 服务端的IP地址

注意: .onion连接不会使用任何加密算法,因为Tor网络默认自带了传输加密。 注意: 假如你确定远程客户端也支持的话,可以在握手前启用SSL连接来保证安全性。

例子:

发送请求:

{
  "cmd": "handshake",
  "req_id": 0,
  "params": {
    "crypt": None,
    "crypt_supported": ["tls-rsa"],
    "fileserver_port": 15441,
    "onion": "zp2ynpztyxj2kw7x",
    "protocol": "v2",
    "port_opened": True,
    "peer_id": "-ZN0056-DMK3XX30mOrw",
    "rev": 2122,
    "target_ip": "192.168.1.13",
    "version": "0.5.6"
  }
}

返回:

{
 "protocol": "v2",
 "onion": "boot3rdez4rzn36x",
 "to": 0,
 "crypt": None,
 "cmd": "response",
 "rev": 2092,
 "crypt_supported": [],
 "target_ip": "zp2ynpztyxj2kw7x.onion",
 "version": "0.5.5",
 "fileserver_port": 15441,
 "port_opened": False,
 "peer_id": ""
}

用户请求

getFile site, inner_path, location, [file_size]

从客户端请求文件

参数 描述
site 站点地址 (例如: 1EU1tbG9oC1A8jz2ouVwGZyQ5asrNsE4Vr)
inner_path 用站点相对路径引用的文件位置
location 要求从某个字节位置开始传输文件 (一个请求最多发送 512 字节,所以你需要多次request来获得大文件s)
file_size 所需文件的总大小(可选参数)

返回:

返回值 描述
body 对方所需的文件数据
location 发出去的这些数据的最后一位字节在文件中的位置
size 发送出的数据大小

ping

看看客户端是否仍然在线

返回:

返回值 描述
body Pong

pex site, peers, need

和客户端交换用户 用户标识按照6字节来打包(4字节的 IP 地址——使用inet_ntoa ;再加上2字节端口号)

参数 描述
site 网站地址 (例如:1EU1tbG9oC1A8jz2ouVwGZyQ5asrNsE4Vr)
peers 请求者拥有的用户列表 (打包后)
need 请求者需要的用户数

Return:

返回值 描述
peers 回应者拥有的用户列表 (打包后)

update site, inner_path, body

更新站点文件

参数 描述
site 网站地址 (例如:1EU1tbG9oC1A8jz2ouVwGZyQ5asrNsE4Vr)
inner_path 用站点相对路径引用的文件位置
body 被上传文件的完整内容

Return:

返回值 描述
ok 成功更新文件的感谢信息

listModified site, since

列出 content.json files 自从给定时间以来的的变动。这个命令一般用来获得该站点用户提交带来的内容更新。

参数 描述
site 网站地址 (例如:1EU1tbG9oC1A8jz2ouVwGZyQ5asrNsE4Vr)
since 自从这个时间戳之后的 content.json文件(变动).

Return:

返回值 描述
modified_files (json数据)键: content.json inner_path
值: 上一次修改时间

例如:

> zeronet.py --silent peerCmd 127.0.0.1 15441 listModified "{'site': '1BLogC9LN4oPDcruNz3qo1ysa133E9AGg8', 'since': 1497507030}"
{
  "to": 1,
  "cmd": "response",
  "modified_files": {
    "data/users/1NM9k7VJfrb1UWw5agAvyRfSn3ws1wTJ5U/content.json": 1497579272,
    "data/users/1QEfmMwKVxgR4rkREbdJYjgUmF3Zy8pwHt/content.json": 1497565986,
    "data/users/16NS3rBdW9zpLmLSQoD8nLTtNVsRFtVBhd/content.json": 1497575039,
    "data/users/1CjXarXgvcNeCJ2nMQxUi4DRFWp3GEur2W/content.json": 1497513808,
    "data/users/1L5rGDgTs4W2V7gekSvJNhKa7XaHkVwotD/content.json": 1497615798,
    "data/users/1LWuc6JBhUGrKEAh1aPrPU85dEMcKmg3pS/content.json": 1497594716,
    "data/users/1KdnTJVBGzEZrJppFZtzfG9chukuMv8xSb/content.json": 1497584640,
    "data/users/1GMNmr2bDPbT4c8yVnyCoDHke52CNCdqAa/content.json": 1497614188,
    "data/users/1GRm9rED83Tkfi3iWS9m3LWHiRpPZehWLd/content.json": 1497827772,
    "data/users/12Ugp53jiMdvj1Kxa1w7c2LcXUBdGPs1oK/content.json": 1497692901,
    "data/users/1F6BMqittjWUStzUbRXm2kG2GQ3RdBLqFQ/content.json": 1497571485,
    "data/users/1GgNo3CmxPd7n2pMSF3uyqf1XHvgtTUqCe/content.json": 1497560829,
    "data/users/16nArdxrSaNThNp83kL8E6NLL9WD98iUne/content.json": 1497627929,
    "data/users/16CAJkbfNRxNJq4aKdrZ2MSYFfFGvQ8JPi/content.json": 1497664899,
    "data/users/1DrBS2sTD3BX5BBxG8eqYsxXSvGt9kc5HE/content.json": 1497632000,
    "data/users/19sggoAZ4hcorrrfWoFWP9rwfpVsL29cnZ/content.json": 1497928134,
    "data/users/1NYpJupegoTXL4cFpkNdLNJ4XaAhTNhPe1/content.json": 1497535771,
    "data/users/1R67TfYzNkCnh89EFfGmXn5LMb4hXaMRQ/content.json": 1497691787,
    "data/users/1C9HXUYFSVafLxanwkaFPZRcRgCEGsj2Cn/content.json": 1497572833,
    "data/users/1LgoHzNGWeijeZbJ8a1YgGjMCnjaM4BWG/content.json": 1497620232,
    "content.json": 1497623639
  }
}

getHashfield site

获得客户端下载的 所选文件ID.

参数 描述
site 站点地址 (例如:1EU1tbG9oC1A8jz2ouVwGZyQ5asrNsE4Vr)

Return:

返回值 描述
hashfield_raw 可选的文件ID。已经被编码过,编码方法是 array.array("H", [1000, 1001..]).tostring()

举例:

> zeronet.py --silent peerCmd 192.168.1.13 15441 getHashfield "{'site': '1Gif7PqWTzVWDQ42Mo7np3zXmGAo3DXc7h'}
{
  'to': 1,
  'hashfield_raw': 'iG\xde\x02\xc6o\r;...',
  'cmd': 'response'
}

setHashfield site, hashfield_raw

设置请求方具有的 可选文件ID 列表

参数 描述
site Site address (例如:1EU1tbG9oC1A8jz2ouVwGZyQ5asrNsE4Vr)
hashfield_raw Optional file ids encoded using array.array("H", [1000, 1001..]).tostring()

Return:

返回值 描述
ok Updated

findHashIds site, hash_ids

询问客户端是否知道某个用户拥有所需的文件的hash_ids

参数 描述
site 站点地址 (例如:1EU1tbG9oC1A8jz2ouVwGZyQ5asrNsE4Vr)
hash_ids 由需要客户端查找的、所选文件id组成的数组。

Return:

返回值 描述
peers (json形式)键: 所选文件id
值: ipv4 用户列表,已经被编码,编码方法为 socket.inet_aton(ip) + struct.pack("H", port)
peers_onion (json形式)键: 所选文件id
值: onion 用户列表,已经被编码,编码方法为 base64.b32decode(onion.replace(".onion", "").upper()) + struct.pack("H", port)

举例:

> zeronet.py --silent peerCmd 192.168.1.13 15441 findHashIds "{'site': '1Gif7PqWTzVWDQ42Mo7np3zXmGAo3DXc7h', 'hash_ids': [59948, 29811]}"
{
  'to': 1,
  'peers': {
    29811: [
      'S&9\xd3Q<',
      '>f\x94\x98N\xa4',
      'gIB\x90Q<',
      '\xb4\xady\xf7Q<'
    ],
    59948: [
      'x\xcc>\xf6Q<',
      'S\xa1\xddkQ<',
      '\x05\xac\xe8\x8dQ<',
      '\x05\xc4\xe1\x93Q<',
      'Q\x02\xed\nQ<'
    ]
  },
  'cmd': 'response',
  'peers_onion': {
    29811: ['\xc7;A\xce\xbc\xd9O\xe2w<Q<'],
    59948: ['\xc7;A\xce\xbc\xd9O\xe2w<Q<']
  }
}

可选文件ID

文件hash值的前四位的整型值

>>> int("ea2c2acb30bd5e1249021976536574dd3f0fd83340e023bb4e78d0d818adf30a"[0:4], 16)
59948