github.com/linapex/ethereum-go-chinese@v0.0.0-20190316121929-f8b7a73c3fa1/p2p/netutil/net.go (about) 1 2 //<developer> 3 // <name>linapex 曹一峰</name> 4 // <email>linapex@163.com</email> 5 // <wx>superexc</wx> 6 // <qqgroup>128148617</qqgroup> 7 // <url>https://jsq.ink</url> 8 // <role>pku engineer</role> 9 // <date>2019-03-16 19:16:41</date> 10 //</624450105394597888> 11 12 13 //包netutil包含对网络包的扩展。 14 package netutil 15 16 import ( 17 "bytes" 18 "errors" 19 "fmt" 20 "net" 21 "sort" 22 "strings" 23 ) 24 25 var lan4, lan6, special4, special6 Netlist 26 27 func init() { 28 //来自RFC 5735、RFC 5156的列表, 29 //https://www.iana.org/assignments/iana-ipv4-special-registry/ 30 lan4.Add("0.0.0.0/8") //“这个”网络 31 lan4.Add("10.0.0.0/8") //私人使用 32 lan4.Add("172.16.0.0/12") //私人使用 33 lan4.Add("192.168.0.0/16") //私人使用 34 lan6.Add("fe80::/10") //链路本地 35 lan6.Add("fc00::/7") //独特的地方 36 special4.Add("192.0.0.0/29") //IPv4服务连续性 37 special4.Add("192.0.0.9/32") //PCP选播 38 special4.Add("192.0.0.170/32") //NAT64/DNS64发现 39 special4.Add("192.0.0.171/32") //NAT64/DNS64发现 40 special4.Add("192.0.2.0/24") //测试网络-1 41 special4.Add("192.31.196.0/24") //AS112 42 special4.Add("192.52.193.0/24") //AMT 43 special4.Add("192.88.99.0/24") //6to4继电器选播 44 special4.Add("192.175.48.0/24") //AS112 45 special4.Add("198.18.0.0/15") //设备基准测试 46 special4.Add("198.51.100.0/24") //测试网NET-2 47 special4.Add("203.0.113.0/24") //测试网-3 48 special4.Add("255.255.255.255/32") //有限广播 49 50 //http://www.iana.org/assignments/iana-ipv6-special-registry/ 51 special6.Add("100::/64") 52 special6.Add("2001::/32") 53 special6.Add("2001:1::1/128") 54 special6.Add("2001:2::/48") 55 special6.Add("2001:3::/32") 56 special6.Add("2001:4:112::/48") 57 special6.Add("2001:5::/32") 58 special6.Add("2001:10::/28") 59 special6.Add("2001:20::/28") 60 special6.Add("2001:db8::/32") 61 special6.Add("2002::/16") 62 } 63 64 //netlist是IP网络的列表。 65 type Netlist []net.IPNet 66 67 //ParseNetList解析CIDR掩码的逗号分隔列表。 68 //空白和多余的逗号将被忽略。 69 func ParseNetlist(s string) (*Netlist, error) { 70 ws := strings.NewReplacer(" ", "", "\n", "", "\t", "") 71 masks := strings.Split(ws.Replace(s), ",") 72 l := make(Netlist, 0) 73 for _, mask := range masks { 74 if mask == "" { 75 continue 76 } 77 _, n, err := net.ParseCIDR(mask) 78 if err != nil { 79 return nil, err 80 } 81 l = append(l, *n) 82 } 83 return &l, nil 84 } 85 86 //marshaltoml实现toml.marshalerrec。 87 func (l Netlist) MarshalTOML() interface{} { 88 list := make([]string, 0, len(l)) 89 for _, net := range l { 90 list = append(list, net.String()) 91 } 92 return list 93 } 94 95 //unmarshaltoml实现toml.unmarshalerrec。 96 func (l *Netlist) UnmarshalTOML(fn func(interface{}) error) error { 97 var masks []string 98 if err := fn(&masks); err != nil { 99 return err 100 } 101 for _, mask := range masks { 102 _, n, err := net.ParseCIDR(mask) 103 if err != nil { 104 return err 105 } 106 *l = append(*l, *n) 107 } 108 return nil 109 } 110 111 //添加分析CIDR掩码并将其附加到列表中。它对无效的掩码感到恐慌,并且 112 //用于设置静态列表。 113 func (l *Netlist) Add(cidr string) { 114 _, n, err := net.ParseCIDR(cidr) 115 if err != nil { 116 panic(err) 117 } 118 *l = append(*l, *n) 119 } 120 121 //包含报告给定IP是否包含在列表中。 122 func (l *Netlist) Contains(ip net.IP) bool { 123 if l == nil { 124 return false 125 } 126 for _, net := range *l { 127 if net.Contains(ip) { 128 return true 129 } 130 } 131 return false 132 } 133 134 //islan报告IP是否为本地网络地址。 135 func IsLAN(ip net.IP) bool { 136 if ip.IsLoopback() { 137 return true 138 } 139 if v4 := ip.To4(); v4 != nil { 140 return lan4.Contains(v4) 141 } 142 return lan6.Contains(ip) 143 } 144 145 //IsSpecialNetwork报告IP是否位于专用网络范围内 146 //这包括广播、多播和文档地址。 147 func IsSpecialNetwork(ip net.IP) bool { 148 if ip.IsMulticast() { 149 return true 150 } 151 if v4 := ip.To4(); v4 != nil { 152 return special4.Contains(v4) 153 } 154 return special6.Contains(ip) 155 } 156 157 var ( 158 errInvalid = errors.New("invalid IP") 159 errUnspecified = errors.New("zero address") 160 errSpecial = errors.New("special network") 161 errLoopback = errors.New("loopback address from non-loopback host") 162 errLAN = errors.New("LAN address from WAN host") 163 ) 164 165 //checkrelayip报告是否从给定的发送方IP中继IP 166 //是有效的连接目标。 167 // 168 //有四条规则: 169 //-特殊网络地址永远无效。 170 //-如果由回送主机中继,则回送地址正常。 171 //-如果由LAN主机中继,则LAN地址正常。 172 //-所有其他地址始终可以接受。 173 func CheckRelayIP(sender, addr net.IP) error { 174 if len(addr) != net.IPv4len && len(addr) != net.IPv6len { 175 return errInvalid 176 } 177 if addr.IsUnspecified() { 178 return errUnspecified 179 } 180 if IsSpecialNetwork(addr) { 181 return errSpecial 182 } 183 if addr.IsLoopback() && !sender.IsLoopback() { 184 return errLoopback 185 } 186 if IsLAN(addr) && !IsLAN(sender) { 187 return errLAN 188 } 189 return nil 190 } 191 192 //Samenet报告两个IP地址是否具有相同的给定位长度前缀。 193 func SameNet(bits uint, ip, other net.IP) bool { 194 ip4, other4 := ip.To4(), other.To4() 195 switch { 196 case (ip4 == nil) != (other4 == nil): 197 return false 198 case ip4 != nil: 199 return sameNet(bits, ip4, other4) 200 default: 201 return sameNet(bits, ip.To16(), other.To16()) 202 } 203 } 204 205 func sameNet(bits uint, ip, other net.IP) bool { 206 nb := int(bits / 8) 207 mask := ^byte(0xFF >> (bits % 8)) 208 if mask != 0 && nb < len(ip) && ip[nb]&mask != other[nb]&mask { 209 return false 210 } 211 return nb <= len(ip) && bytes.Equal(ip[:nb], other[:nb]) 212 } 213 214 //DistinctNetset跟踪IP,确保最多N个IP 215 //属于同一网络范围。 216 type DistinctNetSet struct { 217 Subnet uint //公共前缀位数 218 Limit uint //每个子网中的最大IP数 219 220 members map[string]uint 221 buf net.IP 222 } 223 224 //添加将IP地址添加到集合中。如果 225 //定义范围内的现有IP数超过限制。 226 func (s *DistinctNetSet) Add(ip net.IP) bool { 227 key := s.key(ip) 228 n := s.members[string(key)] 229 if n < s.Limit { 230 s.members[string(key)] = n + 1 231 return true 232 } 233 return false 234 } 235 236 //移除从集合中移除IP。 237 func (s *DistinctNetSet) Remove(ip net.IP) { 238 key := s.key(ip) 239 if n, ok := s.members[string(key)]; ok { 240 if n == 1 { 241 delete(s.members, string(key)) 242 } else { 243 s.members[string(key)] = n - 1 244 } 245 } 246 } 247 248 //包含给定IP是否包含在集合中。 249 func (s DistinctNetSet) Contains(ip net.IP) bool { 250 key := s.key(ip) 251 _, ok := s.members[string(key)] 252 return ok 253 } 254 255 //len返回跟踪的IP数。 256 func (s DistinctNetSet) Len() int { 257 n := uint(0) 258 for _, i := range s.members { 259 n += i 260 } 261 return int(n) 262 } 263 264 //键将地址的映射键编码到临时缓冲区中。 265 // 266 //密钥的第一个字节是“4”或“6”,用于区分IPv4/IPv6地址类型。 267 //密钥的其余部分是IP,截断为位数。 268 func (s *DistinctNetSet) key(ip net.IP) net.IP { 269 //延迟初始化存储。 270 if s.members == nil { 271 s.members = make(map[string]uint) 272 s.buf = make(net.IP, 17) 273 } 274 //将IP和位规范化。 275 typ := byte('6') 276 if ip4 := ip.To4(); ip4 != nil { 277 typ, ip = '4', ip4 278 } 279 bits := s.Subnet 280 if bits > uint(len(ip)*8) { 281 bits = uint(len(ip) * 8) 282 } 283 //将前缀编码为s.buf。 284 nb := int(bits / 8) 285 mask := ^byte(0xFF >> (bits % 8)) 286 s.buf[0] = typ 287 buf := append(s.buf[:1], ip[:nb]...) 288 if nb < len(ip) && mask != 0 { 289 buf = append(buf, ip[nb]&mask) 290 } 291 return buf 292 } 293 294 //字符串实现fmt.stringer 295 func (s DistinctNetSet) String() string { 296 var buf bytes.Buffer 297 buf.WriteString("{") 298 keys := make([]string, 0, len(s.members)) 299 for k := range s.members { 300 keys = append(keys, k) 301 } 302 sort.Strings(keys) 303 for i, k := range keys { 304 var ip net.IP 305 if k[0] == '4' { 306 ip = make(net.IP, 4) 307 } else { 308 ip = make(net.IP, 16) 309 } 310 copy(ip, k[1:]) 311 fmt.Fprintf(&buf, "%v×%d", ip, s.members[k]) 312 if i != len(keys)-1 { 313 buf.WriteString(" ") 314 } 315 } 316 buf.WriteString("}") 317 return buf.String() 318 } 319