* Ban by IP

* Fix panic

* Fix error format

* Remove failed addresses

Co-authored-by: stasatdaglabs <39559713+stasatdaglabs@users.noreply.github.com>
This commit is contained in:
Ori Newman 2021-02-01 10:51:18 +02:00 committed by GitHub
parent 65e149b2bb
commit 669a9ab4c3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 85 additions and 44 deletions

View File

@ -22,7 +22,7 @@ func (*FlowContext) HandleError(err error, flowName string, isStopping *uint32,
panic(err) panic(err)
} }
log.Errorf("error from %s: %+v", flowName, err) log.Errorf("error from %s: %s", flowName, err)
} }
if atomic.AddUint32(isStopping, 1) == 1 { if atomic.AddUint32(isStopping, 1) == 1 {

View File

@ -60,7 +60,7 @@ func (flow *receiveVersionFlow) start() (*appmessage.NetAddress, error) {
} }
if !allowSelfConnections && flow.NetAdapter().ID().IsEqual(msgVersion.ID) { if !allowSelfConnections && flow.NetAdapter().ID().IsEqual(msgVersion.ID) {
return nil, protocolerrors.New(true, "connected to self") return nil, protocolerrors.New(false, "connected to self")
} }
// Disconnect and ban peers from a different network // Disconnect and ban peers from a different network

View File

@ -1421,7 +1421,7 @@ func TestHandleRelayInvs(t *testing.T) {
if !test.expectsIBDToFinish { if !test.expectsIBDToFinish {
t.Fatalf("IBD unexpecetedly finished") t.Fatalf("IBD unexpecetedly finished")
} }
case <-time.After(time.Second): case <-time.After(10 * time.Second):
if test.expectsIBDToFinish { if test.expectsIBDToFinish {
t.Fatalf("IBD didn't finished after %d", time.Second) t.Fatalf("IBD didn't finished after %d", time.Second)
} }
@ -1436,7 +1436,7 @@ func TestHandleRelayInvs(t *testing.T) {
if !errors.Is(err, router.ErrRouteClosed) { if !errors.Is(err, router.ErrRouteClosed) {
t.Fatalf("unexpected error %+v", err) t.Fatalf("unexpected error %+v", err)
} }
case <-time.After(time.Second): case <-time.After(10 * time.Second):
t.Fatalf("waiting for flow to finish timed out after %s", time.Second) t.Fatalf("waiting for flow to finish timed out after %s", time.Second)
} }
} }

View File

@ -78,11 +78,7 @@ func (m *Manager) handleError(err error, netConnection *netadapter.NetConnection
if !m.context.Config().DisableBanning && protocolErr.ShouldBan { if !m.context.Config().DisableBanning && protocolErr.ShouldBan {
log.Warnf("Banning %s (reason: %s)", netConnection, protocolErr.Cause) log.Warnf("Banning %s (reason: %s)", netConnection, protocolErr.Cause)
err := m.context.ConnectionManager().Ban(netConnection) m.context.ConnectionManager().Ban(netConnection)
if err != nil && !errors.Is(err, addressmanager.ErrAddressNotFound) {
panic(err)
}
err = outgoingRoute.Enqueue(appmessage.NewMsgReject(protocolErr.Error())) err = outgoingRoute.Enqueue(appmessage.NewMsgReject(protocolErr.Error()))
if err != nil && !errors.Is(err, routerpkg.ErrRouteClosed) { if err != nil && !errors.Is(err, routerpkg.ErrRouteClosed) {
panic(err) panic(err)

View File

@ -232,12 +232,12 @@ func TestBoundedMergeDepth(t *testing.T) {
} }
factory := NewFactory() factory := NewFactory()
consensusBuild, teardownFunc1, err := factory.NewTestConsensus(params, false, "BoundedMergeTestBuild") consensusBuild, teardownFunc1, err := factory.NewTestConsensus(params, false, "TestBoundedMergeTestBuild")
if err != nil { if err != nil {
t.Fatalf("TestBoundedMergeDepth: Error setting up consensus: %+v", err) t.Fatalf("TestBoundedMergeDepth: Error setting up consensus: %+v", err)
} }
consensusReal, teardownFunc2, err := factory.NewTestConsensus(params, false, "BoundedMergeTestReal") consensusReal, teardownFunc2, err := factory.NewTestConsensus(params, false, "TestBoundedMergeTestReal")
if err != nil { if err != nil {
t.Fatalf("TestBoundedMergeDepth: Error setting up consensus: %+v", err) t.Fatalf("TestBoundedMergeDepth: Error setting up consensus: %+v", err)
} }

View File

@ -1,6 +1,8 @@
package blockvalidator package blockvalidator
import ( import (
"fmt"
"github.com/kaspanet/kaspad/domain/consensus/model"
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi" "github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
"github.com/kaspanet/kaspad/domain/consensus/ruleerrors" "github.com/kaspanet/kaspad/domain/consensus/ruleerrors"
"github.com/kaspanet/kaspad/domain/consensus/utils/consensushashing" "github.com/kaspanet/kaspad/domain/consensus/utils/consensushashing"
@ -29,6 +31,21 @@ func (v *blockValidator) ValidateHeaderInContext(blockHash *externalapi.DomainHa
if err != nil { if err != nil {
return err return err
} }
var logErr error
log.Debug(logger.NewLogClosure(func() string {
var ghostdagData *model.BlockGHOSTDAGData
ghostdagData, logErr = v.ghostdagDataStore.Get(v.databaseContext, blockHash)
if err != nil {
return ""
}
return fmt.Sprintf("block %s blue score is %d", blockHash, ghostdagData.BlueScore())
}))
if logErr != nil {
return logErr
}
} }
err = v.validateMedianTime(header) err = v.validateMedianTime(header)

View File

@ -12,16 +12,22 @@ import (
"github.com/pkg/errors" "github.com/pkg/errors"
) )
// AddressRandomizer is the interface for the randomizer needed for the AddressManager. // addressRandomizer is the interface for the randomizer needed for the AddressManager.
type AddressRandomizer interface { type addressRandomizer interface {
RandomAddress(addresses []*appmessage.NetAddress) *appmessage.NetAddress RandomAddress(addresses []*appmessage.NetAddress) *appmessage.NetAddress
RandomAddresses(addresses []*appmessage.NetAddress, count int) []*appmessage.NetAddress RandomAddresses(addresses []*appmessage.NetAddress, count int) []*appmessage.NetAddress
} }
// AddressKey represents a pair of IP and port, the IP is always in V6 representation // addressKey represents a pair of IP and port, the IP is always in V6 representation
type AddressKey struct { type addressKey struct {
port uint16 port uint16
address [net.IPv6len]byte address ipv6
}
type ipv6 [net.IPv6len]byte
func (i ipv6) equal(other ipv6) bool {
return i == other
} }
// ErrAddressNotFound is an error returned from some functions when a // ErrAddressNotFound is an error returned from some functions when a
@ -29,16 +35,16 @@ type AddressKey struct {
var ErrAddressNotFound = errors.New("address not found") var ErrAddressNotFound = errors.New("address not found")
// NetAddressKey returns a key of the ip address to use it in maps. // NetAddressKey returns a key of the ip address to use it in maps.
func netAddressKey(netAddress *appmessage.NetAddress) AddressKey { func netAddressKey(netAddress *appmessage.NetAddress) addressKey {
key := AddressKey{port: netAddress.Port} key := addressKey{port: netAddress.Port}
// all IPv4 can be represented as IPv6. // all IPv4 can be represented as IPv6.
copy(key.address[:], netAddress.IP.To16()) copy(key.address[:], netAddress.IP.To16())
return key return key
} }
// netAddressKeys returns a key of the ip address to use it in maps. // netAddressKeys returns a key of the ip address to use it in maps.
func netAddressesKeys(netAddresses []*appmessage.NetAddress) map[AddressKey]bool { func netAddressesKeys(netAddresses []*appmessage.NetAddress) map[addressKey]bool {
result := make(map[AddressKey]bool, len(netAddresses)) result := make(map[addressKey]bool, len(netAddresses))
for _, netAddress := range netAddresses { for _, netAddress := range netAddresses {
key := netAddressKey(netAddress) key := netAddressKey(netAddress)
result[key] = true result[key] = true
@ -50,12 +56,12 @@ func netAddressesKeys(netAddresses []*appmessage.NetAddress) map[AddressKey]bool
// AddressManager provides a concurrency safe address manager for caching potential // AddressManager provides a concurrency safe address manager for caching potential
// peers on the Kaspa network. // peers on the Kaspa network.
type AddressManager struct { type AddressManager struct {
addresses map[AddressKey]*appmessage.NetAddress addresses map[addressKey]*appmessage.NetAddress
bannedAddresses map[AddressKey]*appmessage.NetAddress bannedAddresses map[ipv6]*appmessage.NetAddress
localAddresses *localAddressManager localAddresses *localAddressManager
mutex sync.Mutex mutex sync.Mutex
cfg *Config cfg *Config
random AddressRandomizer random addressRandomizer
} }
// New returns a new Kaspa address manager. // New returns a new Kaspa address manager.
@ -66,8 +72,8 @@ func New(cfg *Config) (*AddressManager, error) {
} }
return &AddressManager{ return &AddressManager{
addresses: map[AddressKey]*appmessage.NetAddress{}, addresses: map[addressKey]*appmessage.NetAddress{},
bannedAddresses: map[AddressKey]*appmessage.NetAddress{}, bannedAddresses: map[ipv6]*appmessage.NetAddress{},
localAddresses: localAddresses, localAddresses: localAddresses,
random: NewAddressRandomize(), random: NewAddressRandomize(),
cfg: cfg, cfg: cfg,
@ -111,7 +117,6 @@ func (am *AddressManager) RemoveAddress(address *appmessage.NetAddress) {
key := netAddressKey(address) key := netAddressKey(address)
delete(am.addresses, key) delete(am.addresses, key)
delete(am.bannedAddresses, key)
} }
// Addresses returns all addresses // Addresses returns all addresses
@ -175,21 +180,23 @@ func (am *AddressManager) BestLocalAddress(remoteAddress *appmessage.NetAddress)
} }
// Ban marks the given address as banned // Ban marks the given address as banned
func (am *AddressManager) Ban(address *appmessage.NetAddress) error { func (am *AddressManager) Ban(addressToBan *appmessage.NetAddress) {
am.mutex.Lock() am.mutex.Lock()
defer am.mutex.Unlock() defer am.mutex.Unlock()
keyToBan := netAddressKey(addressToBan)
keysToDelete := make([]addressKey, 0)
for _, address := range am.addresses {
key := netAddressKey(address) key := netAddressKey(address)
addressToBan, ok := am.addresses[key] if key.address.equal(keyToBan.address) {
if !ok { keysToDelete = append(keysToDelete, key)
return errors.Wrapf(ErrAddressNotFound, "address %s "+ }
"is not registered with the address manager", address.TCPAddress()) }
for _, key := range keysToDelete {
delete(am.addresses, key)
} }
delete(am.addresses, key) am.bannedAddresses[keyToBan.address] = addressToBan
am.bannedAddresses[key] = addressToBan
return nil
} }
// Unban unmarks the given address as banned // Unban unmarks the given address as banned
@ -198,13 +205,13 @@ func (am *AddressManager) Unban(address *appmessage.NetAddress) error {
defer am.mutex.Unlock() defer am.mutex.Unlock()
key := netAddressKey(address) key := netAddressKey(address)
bannedAddress, ok := am.bannedAddresses[key] bannedAddress, ok := am.bannedAddresses[key.address]
if !ok { if !ok {
return errors.Wrapf(ErrAddressNotFound, "address %s "+ return errors.Wrapf(ErrAddressNotFound, "address %s "+
"is not registered with the address manager as banned", address.TCPAddress()) "is not registered with the address manager as banned", address.TCPAddress())
} }
delete(am.bannedAddresses, key) delete(am.bannedAddresses, key.address)
am.addresses[key] = bannedAddress am.addresses[key] = bannedAddress
return nil return nil
} }
@ -215,7 +222,7 @@ func (am *AddressManager) IsBanned(address *appmessage.NetAddress) (bool, error)
defer am.mutex.Unlock() defer am.mutex.Unlock()
key := netAddressKey(address) key := netAddressKey(address)
if _, ok := am.bannedAddresses[key]; !ok { if _, ok := am.bannedAddresses[key.address]; !ok {
if _, ok = am.addresses[key]; !ok { if _, ok = am.addresses[key]; !ok {
return false, errors.Wrapf(ErrAddressNotFound, "address %s "+ return false, errors.Wrapf(ErrAddressNotFound, "address %s "+
"is not registered with the address manager", address.TCPAddress()) "is not registered with the address manager", address.TCPAddress())

View File

@ -7,7 +7,7 @@ import (
"github.com/kaspanet/kaspad/app/appmessage" "github.com/kaspanet/kaspad/app/appmessage"
) )
// AddressRandomize implement AddressRandomizer interface // AddressRandomize implement addressRandomizer interface
type AddressRandomize struct { type AddressRandomize struct {
random *rand.Rand random *rand.Rand
} }

View File

@ -38,7 +38,7 @@ type localAddress struct {
} }
type localAddressManager struct { type localAddressManager struct {
localAddresses map[AddressKey]*localAddress localAddresses map[addressKey]*localAddress
lookupFunc func(string) ([]net.IP, error) lookupFunc func(string) ([]net.IP, error)
cfg *Config cfg *Config
mutex sync.Mutex mutex sync.Mutex
@ -46,7 +46,7 @@ type localAddressManager struct {
func newLocalAddressManager(cfg *Config) (*localAddressManager, error) { func newLocalAddressManager(cfg *Config) (*localAddressManager, error) {
localAddressManager := localAddressManager{ localAddressManager := localAddressManager{
localAddresses: map[AddressKey]*localAddress{}, localAddresses: map[addressKey]*localAddress{},
cfg: cfg, cfg: cfg,
lookupFunc: cfg.Lookup, lookupFunc: cfg.Lookup,
} }

View File

@ -126,12 +126,21 @@ func (c *ConnectionManager) ConnectionCount() int {
} }
// Ban marks the given netConnection as banned // Ban marks the given netConnection as banned
func (c *ConnectionManager) Ban(netConnection *netadapter.NetConnection) error { func (c *ConnectionManager) Ban(netConnection *netadapter.NetConnection) {
return c.addressManager.Ban(netConnection.NetAddress()) if c.isPermanent(netConnection.Address()) {
log.Infof("Cannot ban %s because it's a permanent connection", netConnection.Address())
return
}
c.addressManager.Ban(netConnection.NetAddress())
} }
// IsBanned returns whether the given netConnection is banned // IsBanned returns whether the given netConnection is banned
func (c *ConnectionManager) IsBanned(netConnection *netadapter.NetConnection) (bool, error) { func (c *ConnectionManager) IsBanned(netConnection *netadapter.NetConnection) (bool, error) {
if c.isPermanent(netConnection.Address()) {
return false, nil
}
return c.addressManager.IsBanned(netConnection.NetAddress()) return c.addressManager.IsBanned(netConnection.NetAddress())
} }
@ -159,3 +168,15 @@ func (c *ConnectionManager) connectionExists(addressString string) bool {
return false return false
} }
func (c *ConnectionManager) isPermanent(addressString string) bool {
if conn, ok := c.activeRequested[addressString]; ok {
return conn.isPermanent
}
if conn, ok := c.pendingRequested[addressString]; ok {
return conn.isPermanent
}
return false
}