39803cef66
Signed-off-by: Lucas Servén Marín <lserven@gmail.com>
114 lines
2.5 KiB
Go
114 lines
2.5 KiB
Go
// Copyright 2019 the Kilo authors
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
package mesh
|
|
|
|
import (
|
|
"net"
|
|
"sort"
|
|
)
|
|
|
|
// sortIPs sorts IPs so the result is stable.
|
|
// It will first sort IPs by type, to prefer selecting
|
|
// IPs of the same type, and then by value.
|
|
func sortIPs(ips []*net.IPNet) {
|
|
sort.Slice(ips, func(i, j int) bool {
|
|
i4, j4 := ips[i].IP.To4(), ips[j].IP.To4()
|
|
if i4 != nil && j4 == nil {
|
|
return true
|
|
}
|
|
if j4 != nil && i4 == nil {
|
|
return false
|
|
}
|
|
return ips[i].String() < ips[j].String()
|
|
})
|
|
}
|
|
|
|
func isLocal(ip net.IP) bool {
|
|
return ip.IsLoopback() || ip.IsLinkLocalMulticast() || ip.IsLinkLocalUnicast()
|
|
}
|
|
|
|
func isPublic(ip net.IP) bool {
|
|
// Check RFC 1918 addresses.
|
|
if ip4 := ip.To4(); ip4 != nil {
|
|
switch {
|
|
// Check for 10.0.0.0/8.
|
|
case ip4[0] == 10:
|
|
return false
|
|
// Check for 172.16.0.0/12.
|
|
case ip4[0] == 172 && ip4[1]&0xf0 == 0x10:
|
|
return false
|
|
// Check for 192.168.0.0/16.
|
|
case ip4[0] == 192 && ip4[1] == 168:
|
|
return false
|
|
default:
|
|
return true
|
|
}
|
|
}
|
|
// Check RFC 4193 addresses.
|
|
if len(ip) == net.IPv6len {
|
|
switch {
|
|
// Check for fd00::/8.
|
|
case ip[0] == 0xfd && ip[1] == 0x00:
|
|
return false
|
|
default:
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
type allocator struct {
|
|
bits int
|
|
ones int
|
|
cidr *net.IPNet
|
|
current net.IP
|
|
}
|
|
|
|
func newAllocator(cidr net.IPNet) *allocator {
|
|
ones, bits := cidr.Mask.Size()
|
|
current := make(net.IP, len(cidr.IP))
|
|
copy(current, cidr.IP)
|
|
if ip4 := current.To4(); ip4 != nil {
|
|
current = ip4
|
|
}
|
|
|
|
return &allocator{
|
|
bits: bits,
|
|
ones: ones,
|
|
cidr: &cidr,
|
|
current: current,
|
|
}
|
|
}
|
|
|
|
func (a *allocator) next() *net.IPNet {
|
|
if a.current == nil {
|
|
return nil
|
|
}
|
|
for i := len(a.current) - 1; i >= 0; i-- {
|
|
a.current[i]++
|
|
// if we haven't overflowed, then we can exit.
|
|
if a.current[i] != 0 {
|
|
break
|
|
}
|
|
}
|
|
if !a.cidr.Contains(a.current) {
|
|
a.current = nil
|
|
}
|
|
ip := make(net.IP, len(a.current))
|
|
copy(ip, a.current)
|
|
|
|
return &net.IPNet{IP: ip, Mask: net.CIDRMask(a.ones, a.bits)}
|
|
}
|