mirror of
https://github.com/fluencelabs/tendermint
synced 2025-04-25 14:52:17 +00:00
p2p: prevent connections from same ip
This commit is contained in:
parent
68a0b3f95b
commit
1fe41be929
@ -1,14 +1,32 @@
|
|||||||
package p2p
|
package p2p
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
type ErrSwitchDuplicatePeerID struct {
|
||||||
ErrSwitchDuplicatePeer = errors.New("Duplicate peer")
|
ID ID
|
||||||
ErrSwitchConnectToSelf = errors.New("Connect to self")
|
}
|
||||||
)
|
|
||||||
|
func (e ErrSwitchDuplicatePeerID) Error() string {
|
||||||
|
return fmt.Errorf("Duplicate peer ID %v", e.ID)
|
||||||
|
}
|
||||||
|
|
||||||
|
type ErrSwitchDuplicatePeerIP struct {
|
||||||
|
Addr string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e ErrSwitchDuplicatePeerIP) Error() string {
|
||||||
|
return fmt.Errorf("Duplicate peer IP %v", e.Addr)
|
||||||
|
}
|
||||||
|
|
||||||
|
type ErrSwitchConnectToSelf struct {
|
||||||
|
Addr *NetAddress
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e ErrSwitchConnectToSelf) Error() string {
|
||||||
|
return fmt.Errorf("Connect to self: %v", e.Addr)
|
||||||
|
}
|
||||||
|
|
||||||
type ErrSwitchAuthenticationFailure struct {
|
type ErrSwitchAuthenticationFailure struct {
|
||||||
Dialed *NetAddress
|
Dialed *NetAddress
|
||||||
|
10
p2p/peer.go
10
p2p/peer.go
@ -17,6 +17,7 @@ type Peer interface {
|
|||||||
cmn.Service
|
cmn.Service
|
||||||
|
|
||||||
ID() ID // peer's cryptographic ID
|
ID() ID // peer's cryptographic ID
|
||||||
|
RemoteIP() string // remote IP of the connection
|
||||||
IsOutbound() bool // did we dial the peer
|
IsOutbound() bool // did we dial the peer
|
||||||
IsPersistent() bool // do we redial this peer when we disconnect
|
IsPersistent() bool // do we redial this peer when we disconnect
|
||||||
NodeInfo() NodeInfo // peer's info
|
NodeInfo() NodeInfo // peer's info
|
||||||
@ -45,6 +46,15 @@ func (pc peerConn) ID() ID {
|
|||||||
return PubKeyToID(pc.conn.(*tmconn.SecretConnection).RemotePubKey())
|
return PubKeyToID(pc.conn.(*tmconn.SecretConnection).RemotePubKey())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Return the IP from the connection RemoteAddr
|
||||||
|
func (pc peerConn) RemoteIP() string {
|
||||||
|
host, _, err := net.SplitHostPort(pc.conn.RemoteAddr().String())
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
return host
|
||||||
|
}
|
||||||
|
|
||||||
// peer implements Peer.
|
// peer implements Peer.
|
||||||
//
|
//
|
||||||
// Before using a peer, you will need to perform a handshake on connection.
|
// Before using a peer, you will need to perform a handshake on connection.
|
||||||
|
@ -7,6 +7,7 @@ import (
|
|||||||
// IPeerSet has a (immutable) subset of the methods of PeerSet.
|
// IPeerSet has a (immutable) subset of the methods of PeerSet.
|
||||||
type IPeerSet interface {
|
type IPeerSet interface {
|
||||||
Has(key ID) bool
|
Has(key ID) bool
|
||||||
|
HasIP(ip string) bool
|
||||||
Get(key ID) Peer
|
Get(key ID) Peer
|
||||||
List() []Peer
|
List() []Peer
|
||||||
Size() int
|
Size() int
|
||||||
@ -17,9 +18,10 @@ type IPeerSet interface {
|
|||||||
// PeerSet is a special structure for keeping a table of peers.
|
// PeerSet is a special structure for keeping a table of peers.
|
||||||
// Iteration over the peers is super fast and thread-safe.
|
// Iteration over the peers is super fast and thread-safe.
|
||||||
type PeerSet struct {
|
type PeerSet struct {
|
||||||
mtx sync.Mutex
|
mtx sync.Mutex
|
||||||
lookup map[ID]*peerSetItem
|
lookup map[ID]*peerSetItem
|
||||||
list []Peer
|
lookupIP map[string]struct{}
|
||||||
|
list []Peer
|
||||||
}
|
}
|
||||||
|
|
||||||
type peerSetItem struct {
|
type peerSetItem struct {
|
||||||
@ -30,8 +32,9 @@ type peerSetItem struct {
|
|||||||
// NewPeerSet creates a new peerSet with a list of initial capacity of 256 items.
|
// NewPeerSet creates a new peerSet with a list of initial capacity of 256 items.
|
||||||
func NewPeerSet() *PeerSet {
|
func NewPeerSet() *PeerSet {
|
||||||
return &PeerSet{
|
return &PeerSet{
|
||||||
lookup: make(map[ID]*peerSetItem),
|
lookup: make(map[ID]*peerSetItem),
|
||||||
list: make([]Peer, 0, 256),
|
lookupIP: make(map[string]struct{}),
|
||||||
|
list: make([]Peer, 0, 256),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -41,7 +44,10 @@ func (ps *PeerSet) Add(peer Peer) error {
|
|||||||
ps.mtx.Lock()
|
ps.mtx.Lock()
|
||||||
defer ps.mtx.Unlock()
|
defer ps.mtx.Unlock()
|
||||||
if ps.lookup[peer.ID()] != nil {
|
if ps.lookup[peer.ID()] != nil {
|
||||||
return ErrSwitchDuplicatePeer
|
return ErrSwitchDuplicatePeerID{peer.ID()}
|
||||||
|
}
|
||||||
|
if _, ok := ps.lookupIP[peer.RemoteIP()]; ok {
|
||||||
|
return ErrSwitchDuplicatePeerIP{peer.RemoteIP()}
|
||||||
}
|
}
|
||||||
|
|
||||||
index := len(ps.list)
|
index := len(ps.list)
|
||||||
@ -49,6 +55,7 @@ func (ps *PeerSet) Add(peer Peer) error {
|
|||||||
// iterating over the ps.list slice.
|
// iterating over the ps.list slice.
|
||||||
ps.list = append(ps.list, peer)
|
ps.list = append(ps.list, peer)
|
||||||
ps.lookup[peer.ID()] = &peerSetItem{peer, index}
|
ps.lookup[peer.ID()] = &peerSetItem{peer, index}
|
||||||
|
ps.lookupIP[peer.RemoteIP()] = struct{}{}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -61,6 +68,15 @@ func (ps *PeerSet) Has(peerKey ID) bool {
|
|||||||
return ok
|
return ok
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// HasIP returns true iff the PeerSet contains
|
||||||
|
// the peer referred to by this IP address.
|
||||||
|
func (ps *PeerSet) HasIP(peerIP string) bool {
|
||||||
|
ps.mtx.Lock()
|
||||||
|
_, ok := ps.lookupIP[peerIP]
|
||||||
|
ps.mtx.Unlock()
|
||||||
|
return ok
|
||||||
|
}
|
||||||
|
|
||||||
// Get looks up a peer by the provided peerKey.
|
// Get looks up a peer by the provided peerKey.
|
||||||
func (ps *PeerSet) Get(peerKey ID) Peer {
|
func (ps *PeerSet) Get(peerKey ID) Peer {
|
||||||
ps.mtx.Lock()
|
ps.mtx.Lock()
|
||||||
@ -76,6 +92,7 @@ func (ps *PeerSet) Get(peerKey ID) Peer {
|
|||||||
func (ps *PeerSet) Remove(peer Peer) {
|
func (ps *PeerSet) Remove(peer Peer) {
|
||||||
ps.mtx.Lock()
|
ps.mtx.Lock()
|
||||||
defer ps.mtx.Unlock()
|
defer ps.mtx.Unlock()
|
||||||
|
delete(ps.lookupIP[peer.RemoteIP()])
|
||||||
item := ps.lookup[peer.ID()]
|
item := ps.lookup[peer.ID()]
|
||||||
if item == nil {
|
if item == nil {
|
||||||
return
|
return
|
||||||
|
@ -403,7 +403,7 @@ func (sw *Switch) DialPeersAsync(addrBook AddrBook, peers []string, persistent b
|
|||||||
sw.randomSleep(0)
|
sw.randomSleep(0)
|
||||||
err := sw.DialPeerWithAddress(addr, persistent)
|
err := sw.DialPeerWithAddress(addr, persistent)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
switch err {
|
switch err.(type) {
|
||||||
case ErrSwitchConnectToSelf, ErrSwitchDuplicatePeer:
|
case ErrSwitchConnectToSelf, ErrSwitchDuplicatePeer:
|
||||||
sw.Logger.Debug("Error dialing peer", "err", err)
|
sw.Logger.Debug("Error dialing peer", "err", err)
|
||||||
default:
|
default:
|
||||||
@ -534,6 +534,8 @@ func (sw *Switch) addPeer(pc peerConn) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// dont connect to multiple peers on the same IP
|
||||||
|
|
||||||
// NOTE: if AuthEnc==false, we don't have a peerID until after the handshake.
|
// NOTE: if AuthEnc==false, we don't have a peerID until after the handshake.
|
||||||
// If AuthEnc==true then we already know the ID and could do the checks first before the handshake,
|
// If AuthEnc==true then we already know the ID and could do the checks first before the handshake,
|
||||||
// but it's simple to just deal with both cases the same after the handshake.
|
// but it's simple to just deal with both cases the same after the handshake.
|
||||||
@ -564,20 +566,24 @@ func (sw *Switch) addPeer(pc peerConn) error {
|
|||||||
// Avoid self
|
// Avoid self
|
||||||
if sw.nodeKey.ID() == peerID {
|
if sw.nodeKey.ID() == peerID {
|
||||||
addr := peerNodeInfo.NetAddress()
|
addr := peerNodeInfo.NetAddress()
|
||||||
|
// remove the given address from the address book
|
||||||
// remove the given address from the address book if we added it earlier
|
// and add to our addresses to avoid dialing again
|
||||||
sw.addrBook.RemoveAddress(addr)
|
sw.addrBook.RemoveAddress(addr)
|
||||||
|
|
||||||
// add the given address to the address book to avoid dialing ourselves
|
|
||||||
// again this is our public address
|
|
||||||
sw.addrBook.AddOurAddress(addr)
|
sw.addrBook.AddOurAddress(addr)
|
||||||
|
return ErrSwitchConnectToSelf{addr}
|
||||||
return ErrSwitchConnectToSelf
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Avoid duplicate
|
// Avoid duplicate
|
||||||
if sw.peers.Has(peerID) {
|
if sw.peers.Has(peerID) {
|
||||||
return ErrSwitchDuplicatePeer
|
return ErrSwitchDuplicatePeerID{peerID}
|
||||||
|
}
|
||||||
|
|
||||||
|
// check ips for both the connection addr and the self reported addr
|
||||||
|
if sw.peers.HasIP(addr) {
|
||||||
|
return ErrSwitchDuplicatePeerIP{addr}
|
||||||
|
}
|
||||||
|
if sw.peers.HasIP(peerNodeInfo.ListenAddr) {
|
||||||
|
return ErrSwitchDuplicatePeerIP{peerNodeInfo.ListenAddr}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Filter peer against ID white list
|
// Filter peer against ID white list
|
||||||
|
Loading…
x
Reference in New Issue
Block a user