Skip to content

Commit

Permalink
feat: add ipblocker package (pactus-project#1323)
Browse files Browse the repository at this point in the history
  • Loading branch information
Ja7ad authored and themantre committed Jun 9, 2024
1 parent 0c6b91d commit 1e92b24
Show file tree
Hide file tree
Showing 12 changed files with 353 additions and 65 deletions.
File renamed without changes.
6 changes: 3 additions & 3 deletions config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,8 @@ var (
//go:embed bootstrap.json
bootstrapInfoBytes []byte

//go:embed banned.json
bannedBytes []byte
//go:embed banned_addrs.json
bannedAddrBytes []byte
)

type Config struct {
Expand Down Expand Up @@ -122,7 +122,7 @@ func DefaultConfigMainnet() *Config {
// The address is: "pc1p8slveave2zm9tgj7q260fgrdfu2ph8n7ezxhtt"
// The associated private key: "SECRET1PP8SYQAH8JH8QLGEEX7L7T8WTU69K6T9AVSNMVCZ8DP6PPLWVYE3SVTHFR8"
bannedList := make([]string, 0)
if err := json.Unmarshal(bannedBytes, &bannedList); err != nil {
if err := json.Unmarshal(bannedAddrBytes, &bannedList); err != nil {
panic(err)
}

Expand Down
6 changes: 3 additions & 3 deletions config/example_config.toml
Original file line number Diff line number Diff line change
Expand Up @@ -93,9 +93,9 @@

# `sync.firewall` contains configuration options for the sync firewall.
[sync.firewall]
# `enable` indicates whether the firewall should be enabled or not.
# Default is `false`.
enable = false
# `banned_nets` contains the list of IPs and subnets that should be banned.
# Any incoming and outgoing connections to banned addresses will be terminated.
banned_nets = []

# `tx_pool` contains configuration options for the transaction pool module.
[tx_pool]
Expand Down
4 changes: 2 additions & 2 deletions sync/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,8 @@ func DefaultConfig() *Config {
}

// BasicCheck performs basic checks on the configuration.
func (*Config) BasicCheck() error {
return nil
func (conf *Config) BasicCheck() error {
return conf.Firewall.BasicCheck()
}

func (conf *Config) CacheSize() int {
Expand Down
17 changes: 14 additions & 3 deletions sync/firewall/config.go
Original file line number Diff line number Diff line change
@@ -1,16 +1,27 @@
package firewall

import (
"net"
)

type Config struct {
Enabled bool `toml:"enable"`
BannedNets []string `toml:"banned_nets"`
}

func DefaultConfig() *Config {
return &Config{
Enabled: false,
BannedNets: make([]string, 0),
}
}

// BasicCheck performs basic checks on the configuration.
func (*Config) BasicCheck() error {
func (conf *Config) BasicCheck() error {
for _, address := range conf.BannedNets {
_, _, err := net.ParseCIDR(address)
if err != nil {
return err
}
}

return nil
}
75 changes: 56 additions & 19 deletions sync/firewall/firewall.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,35 +4,44 @@ import (
"bytes"
"io"

"github.com/multiformats/go-multiaddr"
"github.com/pactus-project/pactus/genesis"
"github.com/pactus-project/pactus/network"
"github.com/pactus-project/pactus/state"
"github.com/pactus-project/pactus/sync/bundle"
"github.com/pactus-project/pactus/sync/peerset"
"github.com/pactus-project/pactus/sync/peerset/peer"
"github.com/pactus-project/pactus/util/errors"
"github.com/pactus-project/pactus/util/ipblocker"
"github.com/pactus-project/pactus/util/logger"
)

// Firewall check packets before passing them to sync module.
type Firewall struct {
config *Config
network network.Network
peerSet *peerset.PeerSet
state state.Facade
logger *logger.SubLogger
config *Config
network network.Network
peerSet *peerset.PeerSet
state state.Facade
ipBlocker *ipblocker.IPBlocker
logger *logger.SubLogger
}

func NewFirewall(conf *Config, net network.Network, peerSet *peerset.PeerSet, st state.Facade,
log *logger.SubLogger,
) *Firewall {
return &Firewall{
config: conf,
network: net,
peerSet: peerSet,
state: st,
logger: log,
) (*Firewall, error) {
blocker, err := ipblocker.New(conf.BannedNets)
if err != nil {
return nil, err
}

return &Firewall{
config: conf,
network: net,
peerSet: peerSet,
state: st,
ipBlocker: blocker,
logger: log,
}, nil
}

func (f *Firewall) OpenGossipBundle(data []byte, from peer.ID) *bundle.Bundle {
Expand All @@ -50,6 +59,18 @@ func (f *Firewall) OpenGossipBundle(data []byte, from peer.ID) *bundle.Bundle {
return bdl
}

// IsBannedAddress checks if the remote IP address is banned.
func (f *Firewall) IsBannedAddress(remoteAddr string) bool {
ip, err := f.getIPFromMultiAddress(remoteAddr)
if err != nil {
f.logger.Warn("firewall: unable to parse remote address", "err", err, "addr", remoteAddr)

return false
}

return f.ipBlocker.IsBanned(ip)
}

func (f *Firewall) OpenStreamBundle(r io.Reader, from peer.ID) *bundle.Bundle {
bdl, err := f.openBundle(r, from)
if err != nil {
Expand Down Expand Up @@ -131,19 +152,35 @@ func (f *Firewall) checkBundle(bdl *bundle.Bundle) error {
}

func (f *Firewall) isPeerBanned(pid peer.ID) bool {
if !f.config.Enabled {
return false
}

p := f.peerSet.GetPeer(pid)

return p.Status.IsBanned()
}

func (f *Firewall) closeConnection(pid peer.ID) {
if !f.config.Enabled {
return
f.network.CloseConnection(pid)
}

func (*Firewall) getIPFromMultiAddress(address string) (string, error) {
addr, err := multiaddr.NewMultiaddr(address)
if err != nil {
return "", err
}

f.network.CloseConnection(pid)
components := addr.Protocols()

var ip string
for _, comp := range components {
switch comp.Name {
// TODO: can parse dns address and find ip??
case "ip4", "ip6":
ipComponent, err := addr.ValueForProtocol(comp.Code)
if err != nil {
return "", err
}
ip = ipComponent
}
}

return ip, nil
}
Loading

0 comments on commit 1e92b24

Please sign in to comment.