http://www.7klian.com

以太坊日蚀进攻(eclipse attack)的办理方案

}
if p.Inbound() {
...
p := newPeer(c, srv.Protocols)
for {
}
...
return DiscSelf
}
}
case !c.is(trustedConn) && c.is(inboundConn) && inboundCount >= srv.maxInboundConns():

cmd/geth/main.go init要领-> geth -> startNode() -> utils.StartNode() -> stack.Start() -> running.Start()
running:


以太坊的节点发明机制基于Kademlia,但其目标却差异,,Kademlia旨在成为在漫衍式对等网络中存储和查找内容的手段,而以太坊仅用于发明新的节点。由于以太坊的节点是由其公钥暗示的,而且不受IP限制,因此在一个呆板上可以同时存在许多节点。进攻者在很少的处事器上建造出许多的节点,并努力的ping受害者的处事器。通过Kademlia协议,进攻者的节点信息将存储并填充在受害者节点列表中。下一步就是让受害者重启呆板,手段包罗断电、ddos进攻等等。重启后,进攻者再不断的ping被害者的节点以成立tcp毗连,一旦被害者所有的tcp毗连都是进攻者制造的,那么就到达了把被害者与正常的网络断绝的目标,虽然最大的目标应该照旧为了双花。有一篇论文是专门先容日蚀进攻的,各人可以找来看看。
}
以太坊是如何防备日蚀进攻的
}

// At this point the connection is past the protocol handshake.
select {

...
func (srv *Server) Start() (err error) {
// to the peer
}
go srv.runPeer(p)

return DiscAlreadyConnected

case pd := <-srv.delpeer:
}
switch {
if srv.EnableMsgEvents {
case peers[c.id] != nil:
......
...



if srv.NoDiscovery || srv.NoDial {
func (srv *Server) run(dialstate dialer) {
r := srv.DialRatio
srv.running = true
网上有许多关于日蚀进攻的具体先容,在这里不做赘述。
// Ensure that the trusted flag is set before checking against MaxPeers.
scheduleTasks()
inboundConn暗示毗连范例为主动毗连过来。
inboundCount--
在适才提到的论文中,提到了以太坊的geth1.8.0办理了日蚀进攻,于是作者拿1.8.0和1.7.3做比拟,理清了以太坊办理这个问题的做法。
以太坊启动时加载p2p网络的流程如下,
}
上面的go srv.run(dialer)毗连池打点协程,认真维护TCP毗连的列表,监听各类信号,处理惩罚peer的增删改
p.events = &srv.peerFeed
// Servers can not be re-used after stopping.
if r == 0 {
peers[c.id] = p

}
if err == nil {
return srv.MaxPeers - srv.maxDialedConns()
留意加粗的代码,有一个针对inboundCount的操纵,当有posthandshake、addpeer动静的时候,会先去check,假如add或del了一个peer,则有对应的inboundCount++可能inboundCount--。看看到底check了什么:

// Start starts running the server.
case c := <-srv.posthandshake:

if pd.Inbound() {
}

return DiscTooManyPeers
return DiscTooManyPeers
pd.log.Debug("Removing p2p peer", "duration", d, "peers", len(peers)-1, "req", pd.requested, "err", pd.err)

func (srv *Server) maxInboundConns() int {

直接看代码。
c.flags |= trustedConn
}
这个running.Start()挪用的等于p2p/server.go中的Start()要领,看看这个要领做了什么:
// TODO: track in-progress inbound node IDs (pre-Peer) to avoid dialing them.
select {



可以看出来,以太坊是通过限制主动毗连过来的数量来阻止日蚀进攻的。我们顺便看下这个数量是几多:
case <-srv.quit:
看加粗的这段逻辑:假如该毗连是信任的,且是主动毗连过来的,且主动毗连过来的节点数量大于srv.maxInboundConns()时,则拒绝此毗连。
inboundCount++
}
}
case c.cont <- srv.encHandshakeChecks(peers, inboundCount, c):

func (srv *Server) encHandshakeChecks(peers map[discover.NodeID]*Peer, inboundCount int, c *conn) error {
case c := <-srv.addpeer:

什么是日蚀进攻
default:

d := common.PrettyDuration(mclock.Now() - pd.created)
// A peer disconnected.
return nil
if trusted[c.id] {
MaxPeers默认是25,defaultDialRatio暗示可以或许接管主动毗连的比例,默认是3,所以最多答允传入的tcp毗连数量就是25/3 = 8个

r = defaultDialRatio
}

srv.log.Debug("Adding p2p peer", "name", name, "addr", c.fd.RemoteAddr(), "peers", len(peers)+1)
case c.id == srv.Self().ID:


首先简朴先容一下日蚀进攻
// The handshakes are done and it passed all checks.
case !c.is(trustedConn|staticDialedConn) && len(peers) >= srv.MaxPeers:
// Its capabilities are known and the remote identity is verified.
break running
err := srv.protoHandshakeChecks(peers, inboundCount, c)
}
delete(peers, pd.ID())
srv.loopWG.Add(1)
这篇文章主要存眷办理日蚀进攻相关代码,其他的不做先容。
name := truncateName(c.name)
func (srv *Server) maxDialedConns() int {
return srv.MaxPeers / r
// A connection has passed the encryption handshake so
protoHandshakeChecks最终也是挪用encHandshakeChecks:
return 0
return nil
// If message events are enabled, pass the peerFeed
go srv.run(dialer)
// the remote identity is known (but hasn't been verified yet).

郑重声明:本文版权归原作者所有,转载文章仅为传播更多信息之目的,如作者信息标记有误,请第一时间联系我们修改或删除,多谢。

相关文章阅读