This repository has been archived by the owner on Mar 19, 2023. It is now read-only.
/
bogon.go
198 lines (180 loc) · 6.88 KB
/
bogon.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
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
package netxlite
//
// Bogon
//
// This file helps us to decide if an IPAddr is a bogon as well as
// a way to create a resolver that fails when resolving bogons.
//
import (
"context"
"net"
"github.com/bassosimone/oonidsl/internal/model"
"github.com/bassosimone/oonidsl/internal/runtimex"
)
// MaybeWrapWithBogonResolver wraps the given resolver with a BogonResolver
// iff the provided boolean flag is true. Otherwise, this factory just returns
// the provided resolver to the caller without any wrapping.
//
// The returned resolver returns a wrapped ErrDNSBogon if there's a bogon error.
//
// BUG: This resolver currently only implements LookupHost. All the other
// lookup methods will always return ErrNoDNSTransport.
func MaybeWrapWithBogonResolver(enabled bool, reso model.Resolver) model.Resolver {
if enabled {
reso = &bogonResolver{Resolver: reso}
}
return reso
}
// bogonResolver is a bogon aware resolver. When a bogon is encountered in
// a reply, this resolver will return ErrDNSBogon.
type bogonResolver struct {
Resolver model.Resolver
}
var _ model.Resolver = &bogonResolver{}
// LookupHost implements Resolver.LookupHost
func (r *bogonResolver) LookupHost(ctx context.Context, hostname string) ([]string, error) {
addrs, err := r.Resolver.LookupHost(ctx, hostname)
if err != nil {
return nil, err // not our responsibility to wrap this error
}
for _, addr := range addrs {
if IsBogon(addr) {
// wrap ErrDNSBogon as documented
return nil, NewErrWrapper(ClassifyResolverError, ResolveOperation, ErrDNSBogon)
}
}
return addrs, nil
}
// LookupHTTPS implements Resolver.LookupHTTPS
func (r *bogonResolver) LookupHTTPS(ctx context.Context, hostname string) (*model.HTTPSSvc, error) {
// TODO(bassosimone): decide whether we want to implement this method or not
return nil, ErrNoDNSTransport
}
// LookupNS implements Resolver.LookupNS
func (r *bogonResolver) LookupNS(ctx context.Context, hostname string) ([]*net.NS, error) {
// TODO(bassosimone): decide whether we want to implement this method or not
return nil, ErrNoDNSTransport
}
// Network implements Resolver.Network
func (r *bogonResolver) Network() string {
return r.Resolver.Network()
}
// Address implements Resolver.Address
func (r *bogonResolver) Address() string {
return r.Resolver.Address()
}
// CloseIdleConnections implements Resolver.CloseIdleConnections
func (r *bogonResolver) CloseIdleConnections() {
r.Resolver.CloseIdleConnections()
}
// IsBogon returns whether an IP address is bogon. Passing to this
// function a non-IP address causes it to return true.
func IsBogon(address string) bool {
ip := net.ParseIP(address)
return ip == nil || isBogon(address, ip)
}
// IsLoopback returns whether an IP address is loopback. Passing to this
// function a non-IP address causes it to return true.
func IsLoopback(address string) bool {
ip := net.ParseIP(address)
return ip == nil || ip.IsLoopback()
}
var (
bogons4 []*net.IPNet
bogons6 []*net.IPNet
)
func expandBogons(cidrs []string) (out []*net.IPNet) {
for _, cidr := range cidrs {
_, block, err := net.ParseCIDR(cidr)
runtimex.PanicOnError(err, "net.ParseCIDR failed")
out = append(out, block)
}
return
}
func init() {
bogons4 = append(bogons4, expandBogons([]string{
//
// List extracted from https://ipinfo.io/bogon
//
"0.0.0.0/8", // "This" network
"10.0.0.0/8", // Private-use networks
"100.64.0.0/10", // Carrier-grade NAT
"127.0.0.0/8", // Loopback
"127.0.53.53/32", // Name collision occurrence
"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.168.0.0/16", // Private-use networks
"198.18.0.0/15", // Network interconnect device benchmark testing
"198.51.100.0/24", // TEST-NET-2
"203.0.113.0/24", // TEST-NET-3
"224.0.0.0/4", // Multicast
"240.0.0.0/4", // Reserved for future use
"255.255.255.255/32", // Limited broadcast
})...)
bogons6 = append(bogons6, expandBogons([]string{
//
// List extracted from https://ipinfo.io/bogon
//
"::/128", // Node-scope unicast unspecified address
"::1/128", // Node-scope unicast loopback address
"::ffff:0:0/96", // IPv4-mapped addresses
"::/96", // IPv4-compatible addresses
"100::/64", // Remotely triggered black hole addresses
"2001:10::/28", // Overlay routable cryptographic hash identifiers (ORCHID)
"2001:db8::/32", // Documentation prefix
"fc00::/7", // Unique local addresses (ULA)
"fe80::/10", // Link-local unicast
"fec0::/10", // Site-local unicast (deprecated)
"ff00::/8", // Multicast (Note: ff0e:/16 is global scope and may appear on the global internet.)
"2002::/24", // 6to4 bogon (0.0.0.0/8)
"2002:a00::/24", // 6to4 bogon (10.0.0.0/8)
"2002:7f00::/24", // 6to4 bogon (127.0.0.0/8)
"2002:a9fe::/32", // 6to4 bogon (169.254.0.0/16)
"2002:ac10::/28", // 6to4 bogon (172.16.0.0/12)
"2002:c000::/40", // 6to4 bogon (192.0.0.0/24)
"2002:c000:200::/40", // 6to4 bogon (192.0.2.0/24)
"2002:c0a8::/32", // 6to4 bogon (192.168.0.0/16)
"2002:c612::/31", // 6to4 bogon (198.18.0.0/15)
"2002:c633:6400::/40", // 6to4 bogon (198.51.100.0/24)
"2002:cb00:7100::/40", // 6to4 bogon (203.0.113.0/24)
"2002:e000::/20", // 6to4 bogon (224.0.0.0/4)
"2002:f000::/20", // 6to4 bogon (240.0.0.0/4)
"2002:ffff:ffff::/48", // 6to4 bogon (255.255.255.255/32)
"2001::/40", // Teredo bogon (0.0.0.0/8)
"2001:0:a00::/40", // Teredo bogon (10.0.0.0/8)
"2001:0:7f00::/40", // Teredo bogon (127.0.0.0/8)
"2001:0:a9fe::/48", // Teredo bogon (169.254.0.0/16)
"2001:0:ac10::/44", // Teredo bogon (172.16.0.0/12)
"2001:0:c000::/56", // Teredo bogon (192.0.0.0/24)
"2001:0:c000:200::/56", // Teredo bogon (192.0.2.0/24)
"2001:0:c0a8::/48", // Teredo bogon (192.168.0.0/16)
"2001:0:c612::/47", // Teredo bogon (198.18.0.0/15)
"2001:0:c633:6400::/56", // Teredo bogon (198.51.100.0/24)
"2001:0:cb00:7100::/56", // Teredo bogon (203.0.113.0/24)
"2001:0:e000::/36", // Teredo bogon (224.0.0.0/4)
"2001:0:f000::/36", // Teredo bogon (240.0.0.0/4)
"2001:0:ffff:ffff::/64", // Teredo bogon (255.255.255.255/32)
})...)
}
// isBogon implements IsBogon
func isBogon(address string, ip net.IP) bool {
// TODO(bassosimone): the following check is probably redundant given that these
// three checks are already included into the list of bogons.
if ip.IsLoopback() || ip.IsLinkLocalUnicast() || ip.IsLinkLocalMulticast() {
return true
}
var bogons []*net.IPNet
if isIPv6(address) {
bogons = bogons6
} else {
bogons = bogons4
}
for _, block := range bogons {
if block.Contains(ip) {
return true
}
}
return false
}