Skip to content

Commit e2957c5

Browse files
committed
Add private IP connection gater
1 parent cd885f8 commit e2957c5

File tree

1 file changed

+57
-9
lines changed

1 file changed

+57
-9
lines changed

client.go

Lines changed: 57 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ import (
2828
"github.com/libp2p/go-libp2p/core/peer"
2929
"github.com/libp2p/go-libp2p/p2p/discovery/mdns"
3030
drouting "github.com/libp2p/go-libp2p/p2p/discovery/routing"
31+
"github.com/libp2p/go-libp2p/p2p/net/conngater"
3132
"github.com/multiformats/go-multiaddr"
3233
manet "github.com/multiformats/go-multiaddr/net"
3334

@@ -163,9 +164,61 @@ func getLogger(configLogger logger) logger {
163164
return configLogger
164165
}
165166

167+
// createPrivateIPConnectionGater creates a ConnectionGater that blocks private IP ranges.
168+
// Returns a configured BasicConnectionGater that prevents connections to/from:
169+
// - RFC1918 private networks (10.x, 172.16-31.x, 192.168.x)
170+
// - Link-local addresses (169.254.x, fe80::)
171+
// - Loopback addresses (127.x, ::1)
172+
// - Shared address space (100.64.x)
173+
// - IPv6 unique local addresses (fc00::)
174+
func createPrivateIPConnectionGater(log logger, cancel context.CancelFunc) (*conngater.BasicConnectionGater, error) {
175+
ipFilter, err := conngater.NewBasicConnectionGater(nil)
176+
if err != nil {
177+
cancel()
178+
return nil, fmt.Errorf("failed to create connection gater: %w", err)
179+
}
180+
181+
// Standard private IP ranges to block
182+
privateRanges := []string{
183+
"10.0.0.0/8", // RFC1918 private network
184+
"172.16.0.0/12", // RFC1918 private network
185+
"192.168.0.0/16", // RFC1918 private network
186+
"127.0.0.0/8", // Loopback
187+
"169.254.0.0/16", // Link-local
188+
"100.64.0.0/10", // Shared Address Space (RFC6598)
189+
"fc00::/7", // IPv6 Unique Local Addresses
190+
"fe80::/10", // IPv6 Link-Local Addresses
191+
"::1/128", // IPv6 Loopback
192+
}
193+
194+
for _, cidr := range privateRanges {
195+
_, ipnet, err := net.ParseCIDR(cidr)
196+
if err != nil {
197+
cancel()
198+
return nil, fmt.Errorf("failed to parse CIDR %s: %w", cidr, err)
199+
}
200+
if err := ipFilter.BlockSubnet(ipnet); err != nil {
201+
log.Warnf("Failed to block subnet %s: %v", cidr, err)
202+
}
203+
}
204+
205+
return ipFilter, nil
206+
}
207+
166208
func buildHostOptions(config Config, log logger, cancel context.CancelFunc) ([]libp2p.Option, error) {
167209
hostOpts := []libp2p.Option{libp2p.Identity(config.PrivateKey)}
168210

211+
// Add connection gater to block private IPs if AllowPrivateIPs is false (default)
212+
if !config.AllowPrivateIPs {
213+
ipFilter, err := createPrivateIPConnectionGater(log, cancel)
214+
if err != nil {
215+
return nil, err
216+
}
217+
218+
hostOpts = append(hostOpts, libp2p.ConnectionGater(ipFilter))
219+
log.Infof("Private IP connection gater enabled (blocking RFC1918 and local addresses)")
220+
}
221+
169222
// Configure announce addresses if provided (useful for K8s)
170223
if len(config.AnnounceAddrs) > 0 {
171224
announceAddrs := make([]multiaddr.Multiaddr, 0, len(config.AnnounceAddrs))
@@ -316,6 +369,7 @@ func connectToBootstrapPeers(ctx context.Context, h host.Host, peers []peer.Addr
316369
if connectErr := h.Connect(ctx, pi); connectErr == nil {
317370
log.Infof("Connected to bootstrap peer: %s", pi.ID.String())
318371
}
372+
// Note: ConnectionGater silently blocks private IPs, no error logged here
319373
}(peerInfo)
320374
}
321375
}
@@ -332,6 +386,7 @@ func connectToRelayPeers(ctx context.Context, h host.Host, peers []peer.AddrInfo
332386
} else {
333387
log.Warnf("Failed to connect to relay peer %s: %v", pi.ID.String(), connectErr)
334388
}
389+
// Note: ConnectionGater silently blocks private IPs
335390
}(relayPeer)
336391
}
337392
}
@@ -630,15 +685,7 @@ func (c *client) connectToDiscoveredPeer(ctx context.Context, peerInfo peer.Addr
630685
return
631686
}
632687

633-
// Filter private IPs unless explicitly allowed (default: filter for production safety)
634-
if !c.config.AllowPrivateIPs {
635-
peerInfo.Addrs = filterPrivateAddrs(peerInfo.Addrs)
636-
if len(peerInfo.Addrs) == 0 {
637-
// All addresses were private, skip this peer
638-
return
639-
}
640-
}
641-
688+
// ConnectionGater handles private IP filtering, so just try to connect
642689
if err := c.host.Connect(ctx, peerInfo); err != nil {
643690
if c.shouldLogConnectionError(err) {
644691
c.logger.Debugf("Failed to connect to discovered peer %s: %v", peerInfo.ID.String(), err)
@@ -891,6 +938,7 @@ func connectToCachedPeers(ctx context.Context, h host.Host, cachedPeers []cached
891938
} else {
892939
logger.Warnf("Failed to reconnect to cached peer %s [%s]: %v", name, ai.ID.String(), err)
893940
}
941+
// Note: ConnectionGater silently blocks private IPs
894942
}(addrInfo, cp.Name)
895943
}
896944
}

0 commit comments

Comments
 (0)