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