diff options
Diffstat (limited to 'internal/netutil')
-rw-r--r-- | internal/netutil/netutil.go | 64 | ||||
-rw-r--r-- | internal/netutil/netutil_test.go | 36 |
2 files changed, 100 insertions, 0 deletions
diff --git a/internal/netutil/netutil.go b/internal/netutil/netutil.go new file mode 100644 index 00000000..e3b3b8cc --- /dev/null +++ b/internal/netutil/netutil.go @@ -0,0 +1,64 @@ +// Copyright 2022 The Gogs Authors. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. + +package netutil + +import ( + "fmt" + "net" +) + +var localCIDRs []*net.IPNet + +func init() { + // Parsing hardcoded CIDR strings should never fail, if in case it does, let's + // fail it at start. + rawCIDRs := []string{ + // https://datatracker.ietf.org/doc/html/rfc5735: + "127.0.0.0/8", // Loopback + "0.0.0.0/8", // "This" network + "100.64.0.0/10", // Shared address space + "169.254.0.0/16", // Link local + "172.16.0.0/12", // Private-use networks + "192.0.0.0/24", // IETF Protocol assignments + "192.0.2.0/24", // TEST-NET-1 + "192.88.99.0/24", // 6to4 Relay anycast + "192.168.0.0/16", // Private-use networks + "198.18.0.0/15", // Network interconnect + "198.51.100.0/24", // TEST-NET-2 + "203.0.113.0/24", // TEST-NET-3 + "255.255.255.255/32", // Limited broadcast + + // https://datatracker.ietf.org/doc/html/rfc1918: + "10.0.0.0/8", // Private-use networks + + // https://datatracker.ietf.org/doc/html/rfc6890: + "::1/128", // Loopback + "FC00::/7", // Unique local address + "FE80::/10", // Multicast address + } + for _, raw := range rawCIDRs { + _, cidr, err := net.ParseCIDR(raw) + if err != nil { + panic(fmt.Sprintf("parse CIDR %q: %v", raw, err)) + } + localCIDRs = append(localCIDRs, cidr) + } +} + +// IsLocalHostname returns true if given hostname is a known local address. +func IsLocalHostname(hostname string) bool { + ips, err := net.LookupIP(hostname) + if err != nil { + return true + } + for _, ip := range ips { + for _, cidr := range localCIDRs { + if cidr.Contains(ip) { + return true + } + } + } + return false +} diff --git a/internal/netutil/netutil_test.go b/internal/netutil/netutil_test.go new file mode 100644 index 00000000..47be4e74 --- /dev/null +++ b/internal/netutil/netutil_test.go @@ -0,0 +1,36 @@ +// Copyright 2022 The Gogs Authors. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. + +package netutil + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestIsLocalHostname(t *testing.T) { + tests := []struct { + hostname string + want bool + }{ + {hostname: "localhost", want: true}, + {hostname: "127.0.0.1", want: true}, + {hostname: "::1", want: true}, + {hostname: "0:0:0:0:0:0:0:1", want: true}, + {hostname: "fuf.me", want: true}, + {hostname: "127.0.0.95", want: true}, + {hostname: "0.0.0.0", want: true}, + {hostname: "192.168.123.45", want: true}, + + {hostname: "gogs.io", want: false}, + {hostname: "google.com", want: false}, + {hostname: "165.232.140.255", want: false}, + } + for _, test := range tests { + t.Run("", func(t *testing.T) { + assert.Equal(t, test.want, IsLocalHostname(test.hostname)) + }) + } +} |