-
Notifications
You must be signed in to change notification settings - Fork 2
/
safe_url.go
90 lines (77 loc) · 2.58 KB
/
safe_url.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
/*
* Written in 2019 by Andrew Ayer
*
* To the extent possible under law, the author(s) have dedicated all
* copyright and related and neighboring rights to this software to the
* public domain worldwide. This software is distributed without any
* warranty.
*
* You should have received a copy of the CC0 Public
* Domain Dedication along with this software. If not, see
* <https://creativecommons.org/publicdomain/zero/1.0/>.
*/
package welcomer
import (
"fmt"
"net"
"syscall"
)
func ipv4Net(a, b, c, d byte, subnetPrefixLen int) net.IPNet {
return net.IPNet{net.IPv4(a, b, c, d), net.CIDRMask(96+subnetPrefixLen, 128)}
}
var reservedIPv4Nets = []net.IPNet{
ipv4Net(0, 0, 0, 0, 8), // Current network
ipv4Net(10, 0, 0, 0, 8), // Private
ipv4Net(100, 64, 0, 0, 10), // RFC6598
ipv4Net(127, 0, 0, 0, 8), // Loopback
ipv4Net(169, 254, 0, 0, 16), // Link-local
ipv4Net(172, 16, 0, 0, 12), // Private
ipv4Net(192, 0, 0, 0, 24), // RFC6890
ipv4Net(192, 0, 2, 0, 24), // Test, doc, examples
ipv4Net(192, 88, 99, 0, 24), // IPv6 to IPv4 relay
ipv4Net(192, 168, 0, 0, 16), // Private
ipv4Net(198, 18, 0, 0, 15), // Benchmarking tests
ipv4Net(198, 51, 100, 0, 24), // Test, doc, examples
ipv4Net(203, 0, 113, 0, 24), // Test, doc, examples
ipv4Net(224, 0, 0, 0, 4), // Multicast
ipv4Net(240, 0, 0, 0, 4), // Reserved (includes broadcast / 255.255.255.255)
}
var globalUnicastIPv6Net = net.IPNet{net.IP{0x20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, net.CIDRMask(3, 128)}
func isIPv6GlobalUnicast(address net.IP) bool {
return globalUnicastIPv6Net.Contains(address)
}
func isIPv4Reserved(address net.IP) bool {
for _, reservedNet := range reservedIPv4Nets {
if reservedNet.Contains(address) {
return true
}
}
return false
}
func isPublicIPAddress(address net.IP) bool {
if address.To4() != nil {
return !isIPv4Reserved(address)
} else {
return isIPv6GlobalUnicast(address)
}
}
func safeSocketControl(network string, address string, conn syscall.RawConn) error {
if !(network == "tcp4" || network == "tcp6") {
return fmt.Errorf("%s is not a safe network type", network)
}
host, port, err := net.SplitHostPort(address)
if err != nil {
return fmt.Errorf("%s is not a valid host/port pair: %s", address, err)
}
ipaddress := net.ParseIP(host)
if ipaddress == nil {
return fmt.Errorf("%s is not a valid IP address", host)
}
if !isPublicIPAddress(ipaddress) {
return fmt.Errorf("%s is not a public IP address", ipaddress)
}
if !(port == "80" || port == "443") {
return fmt.Errorf("%s is not a safe port number", port)
}
return nil
}