nebula/iputil/util.go

94 lines
1.9 KiB
Go

package iputil
import (
"encoding/binary"
"fmt"
"net"
"net/netip"
)
type VpnIp uint32
const maxIPv4StringLen = len("255.255.255.255")
func (ip VpnIp) String() string {
b := make([]byte, maxIPv4StringLen)
n := ubtoa(b, 0, byte(ip>>24))
b[n] = '.'
n++
n += ubtoa(b, n, byte(ip>>16&255))
b[n] = '.'
n++
n += ubtoa(b, n, byte(ip>>8&255))
b[n] = '.'
n++
n += ubtoa(b, n, byte(ip&255))
return string(b[:n])
}
func (ip VpnIp) MarshalJSON() ([]byte, error) {
return []byte(fmt.Sprintf("\"%s\"", ip.String())), nil
}
func (ip VpnIp) ToIP() net.IP {
nip := make(net.IP, 4)
binary.BigEndian.PutUint32(nip, uint32(ip))
return nip
}
func (ip VpnIp) ToNetIpAddr() netip.Addr {
var nip [4]byte
binary.BigEndian.PutUint32(nip[:], uint32(ip))
return netip.AddrFrom4(nip)
}
func Ip2VpnIp(ip []byte) VpnIp {
if len(ip) == 16 {
return VpnIp(binary.BigEndian.Uint32(ip[12:16]))
}
return VpnIp(binary.BigEndian.Uint32(ip))
}
func ToNetIpAddr(ip net.IP) (netip.Addr, error) {
addr, ok := netip.AddrFromSlice(ip)
if !ok {
return netip.Addr{}, fmt.Errorf("invalid net.IP: %v", ip)
}
return addr, nil
}
func ToNetIpPrefix(ipNet net.IPNet) (netip.Prefix, error) {
addr, err := ToNetIpAddr(ipNet.IP)
if err != nil {
return netip.Prefix{}, err
}
ones, bits := ipNet.Mask.Size()
if ones == 0 && bits == 0 {
return netip.Prefix{}, fmt.Errorf("invalid net.IP: %v", ipNet)
}
return netip.PrefixFrom(addr, ones), nil
}
// ubtoa encodes the string form of the integer v to dst[start:] and
// returns the number of bytes written to dst. The caller must ensure
// that dst has sufficient length.
func ubtoa(dst []byte, start int, v byte) int {
if v < 10 {
dst[start] = v + '0'
return 1
} else if v < 100 {
dst[start+1] = v%10 + '0'
dst[start] = v/10 + '0'
return 2
}
dst[start+2] = v%10 + '0'
dst[start+1] = (v/10)%10 + '0'
dst[start] = v/100 + '0'
return 3
}