mirror of
https://github.com/fluencelabs/tendermint
synced 2025-04-25 06:42:16 +00:00
p2p: prevent connections from same ip
This commit is contained in:
parent
68a0b3f95b
commit
1fe41be929
@ -1,14 +1,32 @@
|
||||
package p2p
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
var (
|
||||
ErrSwitchDuplicatePeer = errors.New("Duplicate peer")
|
||||
ErrSwitchConnectToSelf = errors.New("Connect to self")
|
||||
)
|
||||
type ErrSwitchDuplicatePeerID struct {
|
||||
ID ID
|
||||
}
|
||||
|
||||
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 {
|
||||
Dialed *NetAddress
|
||||
|
10
p2p/peer.go
10
p2p/peer.go
@ -17,6 +17,7 @@ type Peer interface {
|
||||
cmn.Service
|
||||
|
||||
ID() ID // peer's cryptographic ID
|
||||
RemoteIP() string // remote IP of the connection
|
||||
IsOutbound() bool // did we dial the peer
|
||||
IsPersistent() bool // do we redial this peer when we disconnect
|
||||
NodeInfo() NodeInfo // peer's info
|
||||
@ -45,6 +46,15 @@ func (pc peerConn) ID() ID {
|
||||
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.
|
||||
//
|
||||
// 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.
|
||||
type IPeerSet interface {
|
||||
Has(key ID) bool
|
||||
HasIP(ip string) bool
|
||||
Get(key ID) Peer
|
||||
List() []Peer
|
||||
Size() int
|
||||
@ -17,9 +18,10 @@ type IPeerSet interface {
|
||||
// PeerSet is a special structure for keeping a table of peers.
|
||||
// Iteration over the peers is super fast and thread-safe.
|
||||
type PeerSet struct {
|
||||
mtx sync.Mutex
|
||||
lookup map[ID]*peerSetItem
|
||||
list []Peer
|
||||
mtx sync.Mutex
|
||||
lookup map[ID]*peerSetItem
|
||||
lookupIP map[string]struct{}
|
||||
list []Peer
|
||||
}
|
||||
|
||||
type peerSetItem struct {
|
||||
@ -30,8 +32,9 @@ type peerSetItem struct {
|
||||
// NewPeerSet creates a new peerSet with a list of initial capacity of 256 items.
|
||||
func NewPeerSet() *PeerSet {
|
||||
return &PeerSet{
|
||||
lookup: make(map[ID]*peerSetItem),
|
||||
list: make([]Peer, 0, 256),
|
||||
lookup: make(map[ID]*peerSetItem),
|
||||
lookupIP: make(map[string]struct{}),
|
||||
list: make([]Peer, 0, 256),
|
||||
}
|
||||
}
|
||||
|
||||
@ -41,7 +44,10 @@ func (ps *PeerSet) Add(peer Peer) error {
|
||||
ps.mtx.Lock()
|
||||
defer ps.mtx.Unlock()
|
||||
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)
|
||||
@ -49,6 +55,7 @@ func (ps *PeerSet) Add(peer Peer) error {
|
||||
// iterating over the ps.list slice.
|
||||
ps.list = append(ps.list, peer)
|
||||
ps.lookup[peer.ID()] = &peerSetItem{peer, index}
|
||||
ps.lookupIP[peer.RemoteIP()] = struct{}{}
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -61,6 +68,15 @@ func (ps *PeerSet) Has(peerKey ID) bool {
|
||||
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.
|
||||
func (ps *PeerSet) Get(peerKey ID) Peer {
|
||||
ps.mtx.Lock()
|
||||
@ -76,6 +92,7 @@ func (ps *PeerSet) Get(peerKey ID) Peer {
|
||||
func (ps *PeerSet) Remove(peer Peer) {
|
||||
ps.mtx.Lock()
|
||||
defer ps.mtx.Unlock()
|
||||
delete(ps.lookupIP[peer.RemoteIP()])
|
||||
item := ps.lookup[peer.ID()]
|
||||
if item == nil {
|
||||
return
|
||||
|
@ -403,7 +403,7 @@ func (sw *Switch) DialPeersAsync(addrBook AddrBook, peers []string, persistent b
|
||||
sw.randomSleep(0)
|
||||
err := sw.DialPeerWithAddress(addr, persistent)
|
||||
if err != nil {
|
||||
switch err {
|
||||
switch err.(type) {
|
||||
case ErrSwitchConnectToSelf, ErrSwitchDuplicatePeer:
|
||||
sw.Logger.Debug("Error dialing peer", "err", err)
|
||||
default:
|
||||
@ -534,6 +534,8 @@ func (sw *Switch) addPeer(pc peerConn) error {
|
||||
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.
|
||||
// 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.
|
||||
@ -564,20 +566,24 @@ func (sw *Switch) addPeer(pc peerConn) error {
|
||||
// Avoid self
|
||||
if sw.nodeKey.ID() == peerID {
|
||||
addr := peerNodeInfo.NetAddress()
|
||||
|
||||
// remove the given address from the address book if we added it earlier
|
||||
// remove the given address from the address book
|
||||
// and add to our addresses to avoid dialing again
|
||||
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)
|
||||
|
||||
return ErrSwitchConnectToSelf
|
||||
return ErrSwitchConnectToSelf{addr}
|
||||
}
|
||||
|
||||
// Avoid duplicate
|
||||
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
|
||||
|
Loading…
x
Reference in New Issue
Block a user