diff --git a/private.go b/private.go new file mode 100644 index 0000000..e048dd5 --- /dev/null +++ b/private.go @@ -0,0 +1,73 @@ +package manet + +import ( + "net" + + ma "github.com/multiformats/go-multiaddr" +) + +// Private4 and Private6 are well-known private networks +// These are exported to allow overriding for testing +var Private4, Private6 []*net.IPNet +var privateCIDR4 = []string{ + // localhost + "127.0.0.0/8", + // private networks + "10.0.0.0/8", + "100.64.0.0/10", + "172.16.0.0/12", + "192.168.0.0/16", + // link local + "169.254.0.0/16", +} +var privateCIDR6 = []string{ + // localhost + "::1/128", + // ULA reserved + "fc00::/7", + // link local + "fe80::/10", +} + +func init() { + Private4 = parsePrivateCIDR(privateCIDR4) + Private6 = parsePrivateCIDR(privateCIDR6) +} + +func parsePrivateCIDR(cidrs []string) []*net.IPNet { + ipnets := make([]*net.IPNet, len(cidrs)) + for i, cidr := range cidrs { + _, ipnet, err := net.ParseCIDR(cidr) + if err != nil { + panic(err) + } + ipnets[i] = ipnet + } + return ipnets +} + +// IsPublicAddr retruns true if the IP part of the multiaddr is not in a private network +func IsPublicAddr(a ma.Multiaddr) bool { + ip, err := a.ValueForProtocol(ma.P_IP4) + if err == nil { + return !inAddrRange(ip, Private4) + } + + ip, err = a.ValueForProtocol(ma.P_IP6) + if err == nil { + return !inAddrRange(ip, Private6) + } + + return false +} + +func inAddrRange(s string, ipnets []*net.IPNet) bool { + ip := net.ParseIP(s) + for _, ipnet := range ipnets { + if ipnet.Contains(ip) { + return true + } + } + + return false +}