github.com/prysmaticlabs/prysm@v1.4.4/beacon-chain/p2p/connection_gater.go (about)

     1  package p2p
     2  
     3  import (
     4  	"net"
     5  	"runtime"
     6  
     7  	"github.com/libp2p/go-libp2p-core/control"
     8  	"github.com/libp2p/go-libp2p-core/network"
     9  	"github.com/libp2p/go-libp2p-core/peer"
    10  	"github.com/multiformats/go-multiaddr"
    11  	manet "github.com/multiformats/go-multiaddr/net"
    12  	"github.com/sirupsen/logrus"
    13  )
    14  
    15  const (
    16  	// Limit for rate limiter when processing new inbound dials.
    17  	ipLimit = 4
    18  
    19  	// Burst limit for inbound dials.
    20  	ipBurst = 8
    21  
    22  	// High watermark buffer signifies the buffer till which
    23  	// we will handle inbound requests.
    24  	highWatermarkBuffer = 10
    25  )
    26  
    27  // InterceptPeerDial tests whether we're permitted to Dial the specified peer.
    28  func (s *Service) InterceptPeerDial(_ peer.ID) (allow bool) {
    29  	return true
    30  }
    31  
    32  // InterceptAddrDial tests whether we're permitted to dial the specified
    33  // multiaddr for the given peer.
    34  func (s *Service) InterceptAddrDial(pid peer.ID, m multiaddr.Multiaddr) (allow bool) {
    35  	// Disallow bad peers from dialing in.
    36  	if s.peers.IsBad(pid) {
    37  		return false
    38  	}
    39  	return filterConnections(s.addrFilter, m)
    40  }
    41  
    42  // InterceptAccept checks whether the incidental inbound connection is allowed.
    43  func (s *Service) InterceptAccept(n network.ConnMultiaddrs) (allow bool) {
    44  	if !s.validateDial(n.RemoteMultiaddr()) {
    45  		// Allow other go-routines to run in the event
    46  		// we receive a large amount of junk connections.
    47  		runtime.Gosched()
    48  		log.WithFields(logrus.Fields{"peer": n.RemoteMultiaddr(),
    49  			"reason": "exceeded dial limit"}).Trace("Not accepting inbound dial from ip address")
    50  		return false
    51  	}
    52  	if s.isPeerAtLimit(true /* inbound */) {
    53  		log.WithFields(logrus.Fields{"peer": n.RemoteMultiaddr(),
    54  			"reason": "at peer limit"}).Trace("Not accepting inbound dial")
    55  		return false
    56  	}
    57  	return filterConnections(s.addrFilter, n.RemoteMultiaddr())
    58  }
    59  
    60  // InterceptSecured tests whether a given connection, now authenticated,
    61  // is allowed.
    62  func (s *Service) InterceptSecured(_ network.Direction, _ peer.ID, _ network.ConnMultiaddrs) (allow bool) {
    63  	return true
    64  }
    65  
    66  // InterceptUpgraded tests whether a fully capable connection is allowed.
    67  func (s *Service) InterceptUpgraded(_ network.Conn) (allow bool, reason control.DisconnectReason) {
    68  	return true, 0
    69  }
    70  
    71  func (s *Service) validateDial(addr multiaddr.Multiaddr) bool {
    72  	ip, err := manet.ToIP(addr)
    73  	if err != nil {
    74  		return false
    75  	}
    76  	remaining := s.ipLimiter.Remaining(ip.String())
    77  	if remaining <= 0 {
    78  		return false
    79  	}
    80  	s.ipLimiter.Add(ip.String(), 1)
    81  	return true
    82  }
    83  
    84  var privateCIDRList = []string{
    85  	// Private ip addresses specified by rfc-1918.
    86  	// See: https://tools.ietf.org/html/rfc1918
    87  	"10.0.0.0/8",
    88  	"172.16.0.0/12",
    89  	"192.168.0.0/16",
    90  	// Reserved address space for CGN devices, specified by rfc-6598
    91  	// See: https://tools.ietf.org/html/rfc6598
    92  	"100.64.0.0/10",
    93  	// IPv4 Link-Local addresses, specified by rfc-3926
    94  	// See: https://tools.ietf.org/html/rfc3927
    95  	"169.254.0.0/16",
    96  }
    97  
    98  // configureFilter looks at the provided allow lists and
    99  // deny lists to appropriately create a filter.
   100  func configureFilter(cfg *Config) (*multiaddr.Filters, error) {
   101  	addrFilter := multiaddr.NewFilters()
   102  	var privErr error
   103  	switch {
   104  	case cfg.AllowListCIDR == "public":
   105  		cfg.DenyListCIDR = append(cfg.DenyListCIDR, privateCIDRList...)
   106  	case cfg.AllowListCIDR == "private":
   107  		addrFilter, privErr = privateCIDRFilter(addrFilter, multiaddr.ActionAccept)
   108  		if privErr != nil {
   109  			return nil, privErr
   110  		}
   111  	case cfg.AllowListCIDR != "":
   112  		_, ipnet, err := net.ParseCIDR(cfg.AllowListCIDR)
   113  		if err != nil {
   114  			return nil, err
   115  		}
   116  		addrFilter.AddFilter(*ipnet, multiaddr.ActionAccept)
   117  	}
   118  
   119  	// Configure from provided deny list in the config.
   120  	if len(cfg.DenyListCIDR) > 0 {
   121  		for _, cidr := range cfg.DenyListCIDR {
   122  			// If an entry in the deny list is "private", we iterate through the
   123  			// private addresses and add them to the filter. Likewise, if the deny
   124  			// list is "public", then we add all private address to the accept filter,
   125  			switch {
   126  			case cidr == "private":
   127  				addrFilter, privErr = privateCIDRFilter(addrFilter, multiaddr.ActionDeny)
   128  				if privErr != nil {
   129  					return nil, privErr
   130  				}
   131  				continue
   132  			case cidr == "public":
   133  				addrFilter, privErr = privateCIDRFilter(addrFilter, multiaddr.ActionAccept)
   134  				if privErr != nil {
   135  					return nil, privErr
   136  				}
   137  				continue
   138  			}
   139  			_, ipnet, err := net.ParseCIDR(cidr)
   140  			if err != nil {
   141  				return nil, err
   142  			}
   143  			// Check if the address already has an action associated with it
   144  			// If this address was previously accepted, log a warning before placing
   145  			// it in the deny filter
   146  			action, _ := addrFilter.ActionForFilter(*ipnet)
   147  			if action == multiaddr.ActionAccept {
   148  				log.Warnf("Address %s is in conflict with previous rule.", ipnet.String())
   149  			}
   150  			addrFilter.AddFilter(*ipnet, multiaddr.ActionDeny)
   151  		}
   152  	}
   153  	return addrFilter, nil
   154  }
   155  
   156  //helper function to either accept or deny all private addresses
   157  //if a new rule for a private address is in conflict with a previous one, log a warning
   158  func privateCIDRFilter(addrFilter *multiaddr.Filters, action multiaddr.Action) (*multiaddr.Filters, error) {
   159  	for _, privCidr := range privateCIDRList {
   160  		_, ipnet, err := net.ParseCIDR(privCidr)
   161  		if err != nil {
   162  			return nil, err
   163  		}
   164  		// Get the current filter action for the address
   165  		// If it conflicts with the action given by the function call,
   166  		// log a warning
   167  		curAction, _ := addrFilter.ActionForFilter(*ipnet)
   168  		switch {
   169  		case action == multiaddr.ActionAccept:
   170  			if curAction == multiaddr.ActionDeny {
   171  				log.Warnf("Address %s is in conflict with previous rule.", ipnet.String())
   172  			}
   173  		case action == multiaddr.ActionDeny:
   174  			if curAction == multiaddr.ActionAccept {
   175  				log.Warnf("Address %s is in conflict with previous rule.", ipnet.String())
   176  			}
   177  		}
   178  		addrFilter.AddFilter(*ipnet, action)
   179  	}
   180  	return addrFilter, nil
   181  }
   182  
   183  // filterConnections checks the appropriate ip subnets from our
   184  // filter and decides what to do with them. By default libp2p
   185  // accepts all incoming dials, so if we have an allow list
   186  // we will reject all inbound dials except for those in the
   187  // appropriate ip subnets.
   188  func filterConnections(f *multiaddr.Filters, a multiaddr.Multiaddr) bool {
   189  	acceptedNets := f.FiltersForAction(multiaddr.ActionAccept)
   190  	restrictConns := len(acceptedNets) != 0
   191  
   192  	// If we have an allow list added in, we by default reject all
   193  	// connection attempts except for those coming in from the
   194  	// appropriate ip subnets.
   195  	if restrictConns {
   196  		ip, err := manet.ToIP(a)
   197  		if err != nil {
   198  			log.Tracef("Multiaddress has invalid ip: %v", err)
   199  			return false
   200  		}
   201  		found := false
   202  		for _, ipnet := range acceptedNets {
   203  			if ipnet.Contains(ip) {
   204  				found = true
   205  				break
   206  			}
   207  		}
   208  		return found
   209  	}
   210  	return !f.AddrBlocked(a)
   211  }