专栏名称: 区块链技术学习
致力于区块链技术的学习和普及,对区块链技术和相关企业事件进行深度分析和研判,探索去中心化账本技术应用领域。
目录
相关文章推荐
购机帮你评  ·  关于公众号进行账号迁移的说明 ·  20 小时前  
视觉志  ·  贴吧,凉了? ·  2 天前  
媒哥媒体招聘  ·  影视头部宣传公司多岗招聘,带薪进组追星! ·  3 天前  
媒哥媒体招聘  ·  知名传媒公司一直娱招聘! ·  4 天前  
51好读  ›  专栏  ›  区块链技术学习

比特币节点识别的原理及实现方式

区块链技术学习  · 公众号  ·  · 2018-09-26 13:02

正文

来自:绿盟科技研究通讯(微信号:nsfocus_research)
内容编辑:物联网安全实验室 魏佩儒 张星  责任编辑:肖晴

第一章  概述

比特币(Bitcoin)的概念最初由中本聪在2009年提出,是一种P2P形式的数字货币,可以用来兑换成大多数国家的货币。

区块链诞生自中本聪的比特币,自2009年以来,出现了各种各样的类比特币的数字货币,都基于公有区块链。

由于以比特币为代表的数字货币具备兑现的能力,与数字货币相关的恶意事件(如勒索病毒、恶意浏览器脚本挖矿以及IoT僵尸网络挖矿等)逐渐增多。因此,对数字货币的节点进行识别,有助于提供威胁情报,减缓和预防相关恶意事件的影响。

本文将以比特币为例,就节点识别做相关的介绍。第一章为概述,介绍比特币的概念以及节点识别的思路。第二章以新节点加入比特币网络为例,介绍比特币网络的通信过程。第三章介绍比特币的通信协议。第四章介绍了本文所述方法的节点识别实现过程。第五章对节点识别的结果做了分析。第六章为小结。

1 什么是比特币?

比特币是一系列概念和技术,构成了数字货币生态系统的基础。它是一个分布式的点对点系统。因此,没有“中央”服务器或控制点。比特币是通过称为“挖矿”的过程创建的,这涉及到在处理比特币交易时竞争找到数学问题的解决方案。比特币网络中的任何参与者(即使用设备的任何人)都可以运行完整的比特币协议栈,利用其计算机的处理能力来验证和记录交易,这样的节点称之为“矿工”,而验证和记录交易的过程,称之为“挖矿”。平均每10分钟,比特币矿工能够验证过去10分钟的交易,作为奖励,将获得全新的比特币。从本质上讲,比特币采矿分散了中央银行的货币发行和结算功能,取代了对任何中央银行的需求。

2 比特币节点识别的方式

对于特有协议的识别,一般的思路为全网扫描协议相关端口,模拟协议的通信方式,如果目的节点响应的内容符合协议的格式,则认为识别出开放该协议的节点。在比特币协议中,比特币常用的端口为8333,因此,可以全网扫描8333端口,从而确定大部分的比特币节点。但这种方式存在一些问题:1)端口扫描比较耗费时间。2)存在一部分比特币节点,没有使用8333端口,端口扫描难以对这部分节点进行识别。

更进一步,比特币网络为P2P网络,比特币节点均具备发现其他节点的能力(比特币协议中的“getaddr”消息,具有返回该节点周围活跃节点的功能),因此,从一个已知的比特币节点出发,通过模拟比特币协议的节点发现过程,即可获取其相邻节点的地址,之后,对得到的节点,依次通过模拟节点发现过程递归遍历,最终即可遍历整个比特币网络。该方法的优势在于,仅对比特币网络中的节点进行遍历,扫描速度快。因此,本文将对这种方式进行介绍。


第二章  比特币网络的通信过程

比特币网络基于TCP连接,默认端口8333,在套接字之上直接将数据打包成二进制流进行传输。

若一个新的比特币节点,希望加入到比特币网络,总体上流程分为两步,1)获取到当前比特币网络中网络状况正常的节点列表(获取种子节点列表)。2)运行比特币的协议栈,与比特币网络中的其他节点通信。

本章将以获取一个节点周围的缓存节点为例,对比特币节点之间的通信过程做相应的说明。

1 获取种子节点列表

如图2.1所示,比特币的 Wiki [4] 上提供了8种发现种子节点IP列表的方式,本文采用了第三种方式(比特币网络中存在一部分节点使用IPv6的地址,因此,通过该方式获取种子节点列表时,会获取到一部分使用IPv6地址的节点,本文仅对使用IPv4地址的节点做相关说明),即通过DNS请求获取IP地址。

图2.1 获取种子节点IP列表的方式

截至2017年12月,比特币源码的 chainparams.cpp [5] 文件中,一共包含了6个DNS域名(见表2.1),可以用于新节点加入比特币网络时获取种子节点列表。

表2.1 比特币获取种子节点IP的DNS域名

seed.bitcoin.sipa.be

dnsseed.bluematt.me

dnsseed.bitcoin.dashjr.org

seed.bitcoinstats.com

seed.bitcoin.jonasschnelli.ch

seed.btc.petertodd.org

2 比特币节点的通信流程

在完成2.2节的步骤后,正常情况下,可以获取到140个左右比特币节点的地址(IPv4),之后即可通过比特币协议进行通信,比特币节点的通信流程如图2.2所示。

图2.2 比特币节点的通信过程

节点A做为通信的发起者,首先与节点B完成握手的过程。需要着重说明的是,节点之间进行握手时,若一方发送的握手包有问题,则另一方节点不做任何回应。握手无误后,节点B将向节点A发送大量的数据包,如获取节点A的头、区块信息等数据包。

若节点A希望获取到节点B的信息(以获取节点B周围的缓存节点为例),则发送相应的消息即可(图2.2中,节点A发送了一个getaddr消息以获取节点B周围的缓存节点),节点B收到后,将继续向节点A发送消息,以获取自己希望获取到的信息,一段时候后,回应节点A发送消息的结果(图2.2中即为最后的addr消息)。

2.2.1 握手过程

比特币节点之间的握手过程,建立在已经完成TCP连接的基础上。握手的发起者会向目标节点发起TCP连接,默认为8333端口(部分节点不使用8333端口),连接建立成功后,双方需要根据比特币协议的规定,完成握手的过程,主要是确认双方版本、IP地址、端口等信息。

如图2.3所示,节点A为握手的发起者,希望与节点B进行握手,首先向B节点发送一个version消息(含有自己的协议版本等),节点B收到节点A的version消息后,会对数据包进行验证,若验证无误,则会向A回应自己的version消息,否则,节点B将忽略掉节点A的消息。节点B在回应了自己的version消息之后,会再回应一个version ack的消息。节点A在收到B节点的version ack消息后,向节点B回应一个version ack,握手过程即正常结束。

图2.3比特币节点握手过程


握手期间,version消息包含的内容如图2.4所示。有协议的版本号、提供的服务、时间戳、双方的IP地址、客户端描述以及自身当前区块的高度。

图2.4 握手包含有的数据(部分)

2.2.2 获取节点周围缓存节点

完成正常的握手后,节点识别的关键,即为获取对方节点周围活跃的节点地址。比特币协议中规定了用于获取一个节点周围活跃的节点getaddr消息,在完成握手后,通过向对方节点发送getaddr消息,即可获取其周围活跃节点,通信过程如图2.5所示。

图2.5getaddr过程时序


第三章  通信协议

比特币的协议是在TCP层之上,直接封装了自己的协议,因此,通信时,直接通过套接字,将协议转为二进制数据流进行传输。比特币网络中,连接均使用TCP的方式。本章将对比特币的通信协议做简单的描述,第四章识别的实现,是在本章的基础上完成的,对比特币节点的识别,需要实际上是对通信数据包的过滤和解析,第四章的实现中,对数据包进行处理,实际上是根据协议中规定的数据包的长度以及特定的字段,进行过滤和打包。

1 数据包结构

比特币协议中,数据包的结构如表3.1所示(payload长度可变,用“?”表示),由magic、command、length、checksum以及payload组成。

表3.1 比特币节点数据包格式

Field  Size

Description

Data  type

Comments

4

magic

uint32_t

Magic value indicating  message origin network, and used to seek to next message when stream state is  unknown

12

command

char[12]

ASCII string identifying  the packet content, NULL padded (non-NULL padding results in packet rejected)

4

length

uint32_t

Length of  payload in number of bytes

4

checksum

uint32_t

First 4  bytes of sha256(sha256(payload))

?(variable)

payload

uchar[]

The actual  data

比特币的网络有主网络,也有用于测试的网络,通过magic即可区分各个网络,如表3.2所示

表3.2 比特币主网络与测试网络的magic

Network

Magic  value

Sent  over wire as

main

0xD9B4BEF9

F9  BE B4 D9

testnet

0xDAB5BFFA

FA  BF B5 DA

testnet3

0x0709110B

0B  11 09 07

namecoin

0xFEB4BEF9

F9  BE B4 FE

如表3.3所示(payload值可变,用“?”表示),为一个比特币的主网络中的数据包结构。

表3.3 比特币主网络中数据包的示例

f9beb4d9

-magic

76657273696f6e0000000000

-command  “version”

55000000

--  lenth. Payload lenth is 85

0d0fe5c6

--  checksum

?(variable)

Payload

2 version包

如图3.1所示,为比特币节点在通信的握手过互发的一个version消息数据包

图3.1 version包

version数据包由数据包的头和payload两部分组成。数据包的头包含magic、command、payloadlength和checksum,如表3.4所示。

表3.4 version包的头

F9 BE B4 D9

Main  network magic bytes

76 65 72 73 69 6F 6E 00 00 00 00 00

"version" command

64 00 00 00

Payload is  100 bytes long

3B 64 8D 5A

payload  checksum

version数据包的payload如表3.5所示,主要包含了协议的版本号、节点提供的服务、时间戳,接收者的地址、发送者的地址、随机生成的id(用于区分不同的连接)、客户端软件的描述以及该节点当前最新的块。

表3.5 version包的payload

62 EA 00 00

- 60002 (protocol  version 60002)

01 00 00 00 00 00 00 00

- 1 (NODE_NETWORK  services)

01 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00 00 00 FF FF 00 00 00 00 00 00

- Tue Dec 18 10:12:33  PST 2012

01 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00 00 00 FF FF 00 00 00 00 00 00

- Recipient address  info - see Network Address

01 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00 00 00 FF FF 00 00 00 00 00 00

- Sender address info -  see Network Address

3B 2E B3 5D 8C E6 17 65

- Node ID

0F 2F 53 61 74 6F 73 68  69 3A 30 2E 37 2E 32 2F

-  "/Satoshi:0.7.2/" sub-version string (string is 15 bytes long)

C0 3E 03 00

- Last block sending  node has is block #212672

version包payload中不同字段的类型和长度非常重要,对于比特币节点的识别,均是根据数据包字段的类型和长度进行过滤,类型和长度如表3.6所示(user_agent为客户端的描述,长度可变,用“?”表示)。

表3.6 version包不同字段的类型和长度

Field  Size

Description

Data  type

Comments

4

version

int32_t

Identifies protocol  version being used by the node

8

services

uint64_t

bitfield of features  to be enabled for this connection

8

timestamp

int64_t

standard UNIX  timestamp in seconds

26

addr_recv

net_addr

The network address of  the node receiving this message

Fields  below require version ≥ 106

26

addr_from

net_addr

The network  address of the node emitting this message

8

nonce

uint64_t

Node random nonce,  randomly generated every time a version packet is sent. This nonce is used to  detect connections to self.

user_agent

var_str

User Agent  (0x00 if string is 0 bytes long)

4

start_height

int32_t

The last  block received by the emitting node

Fields  below require version ≥ 70001

1

relay

bool

Whether the  remote peer should announce relayed transactions or not

verison包中包含的节点提供的服务,如表3.7所示。

表3.7 节点提供的服务

Value

Name

Description

1

NODE_NETWORK

This node can be asked  for full blocks instead of just headers.

2

NODE_GETUTXO

See BIP 0064 [6]

4

NODE_BLOOM

See BIP 0111 [7]

8

NODE_WITNESS

See BIP 0144 [8]

1024

NODE_NETWORK_LIMITED

See BIP 0159 [9]


3 version ack包

version ack的包相对简单,仅有数据包的头,没有payload,如图3.3所示。

图3.3 version ack包

4 getaddr包

getaddr消息向节点发送请求,询问一个节点周围缓存的活跃节点情况,以帮助查找网络中的潜在节点。getaddr消息的响应是响应节点发送一个或多个addr消息(上限为1000)。典型的假设是,如果节点在过去三小时内发送消息,则该节点可能处于活动状态。此消息与version ack包一样,没有payload。

5 addr包

addr包用于节点之间传输地址信息。非广播节点,通常在三小时后被丢弃。

payload结构如表3.8所示(addr_list长度可变,用“?”表示),count表示该数据包中含有多少条地址,数值在1-1000之间。addr_list为一个地址列表,单条地址的长度为30。

表3.8 addr包payload结构

Field Size

Description

Data type

Comments

1+

count

var_int

Number  of address entries (max: 1000)

30*?

addr_list

(uint32_t + net_addr )[]

Address  of other nodes on the network. version < 209 will only read the first one.  The uint32_t is a timestamp (see note below).


第四章  实现方式

1 总体思路

文本所描述的对比特币节点识别的实现,使用了python 3.6.6。整体思路如下:

1)从DNS种子获取IP种子列表。

2)与IP种子列表中的所有节点建立TCP连接,完成握手。

3)获取种子节点周围的缓存节点,存储到缓存节点列表中。

4)与缓存节点列表中的每一个节点通信,获得新的缓存节点,添加到当前缓存节点列表中并去重。

5)重复第四步,直到处理完所有的缓存节点列表。







请到「今天看啥」查看全文