mirror of
https://github.com/zerotier/ZeroTierOne.git
synced 2025-04-26 17:03:43 +02:00
224 lines
5.9 KiB
Go
224 lines
5.9 KiB
Go
/*
|
|
* Copyright (c)2013-2020 ZeroTier, Inc.
|
|
*
|
|
* Use of this software is governed by the Business Source License included
|
|
* in the LICENSE.TXT file in the project's root directory.
|
|
*
|
|
* Change Date: 2024-01-01
|
|
*
|
|
* On the date above, in accordance with the Business Source License, use
|
|
* of this software will be governed by version 2.0 of the Apache License.
|
|
*/
|
|
/****/
|
|
|
|
package zerotier
|
|
|
|
//#include "../../native/GoGlue.h"
|
|
import "C"
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/binary"
|
|
"encoding/json"
|
|
"errors"
|
|
"net"
|
|
"strconv"
|
|
"strings"
|
|
"syscall"
|
|
"unsafe"
|
|
)
|
|
|
|
func sockaddrStorageToIPNet(ss *C.struct_sockaddr_storage) *net.IPNet {
|
|
var a net.IPNet
|
|
switch ss.ss_family {
|
|
case syscall.AF_INET:
|
|
sa4 := (*C.struct_sockaddr_in)(unsafe.Pointer(ss))
|
|
var ip4 [4]byte
|
|
copy(ip4[:], (*[4]byte)(unsafe.Pointer(&sa4.sin_addr))[:])
|
|
a.IP = ip4[:]
|
|
a.Mask = net.CIDRMask(int(binary.BigEndian.Uint16(((*[2]byte)(unsafe.Pointer(&sa4.sin_port)))[:])), 32)
|
|
return &a
|
|
case syscall.AF_INET6:
|
|
sa6 := (*C.struct_sockaddr_in6)(unsafe.Pointer(ss))
|
|
var ip6 [16]byte
|
|
copy(ip6[:], (*[16]byte)(unsafe.Pointer(&sa6.sin6_addr))[:])
|
|
a.IP = ip6[:]
|
|
a.Mask = net.CIDRMask(int(binary.BigEndian.Uint16(((*[2]byte)(unsafe.Pointer(&sa6.sin6_port)))[:])), 128)
|
|
return &a
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func sockaddrStorageToUDPAddr(ss *C.struct_sockaddr_storage) *net.UDPAddr {
|
|
var a net.UDPAddr
|
|
switch ss.ss_family {
|
|
case syscall.AF_INET:
|
|
sa4 := (*C.struct_sockaddr_in)(unsafe.Pointer(ss))
|
|
var ip4 [4]byte
|
|
copy(ip4[:], (*[4]byte)(unsafe.Pointer(&sa4.sin_addr))[:])
|
|
a.IP = ip4[:]
|
|
a.Port = int(binary.BigEndian.Uint16(((*[2]byte)(unsafe.Pointer(&sa4.sin_port)))[:]))
|
|
return &a
|
|
case syscall.AF_INET6:
|
|
sa6 := (*C.struct_sockaddr_in6)(unsafe.Pointer(ss))
|
|
var ip6 [16]byte
|
|
copy(ip6[:], (*[16]byte)(unsafe.Pointer(&sa6.sin6_addr))[:])
|
|
a.IP = ip6[:]
|
|
a.Port = int(binary.BigEndian.Uint16(((*[2]byte)(unsafe.Pointer(&sa6.sin6_port)))[:]))
|
|
return &a
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func sockaddrStorageToUDPAddr2(ss unsafe.Pointer) *net.UDPAddr {
|
|
return sockaddrStorageToUDPAddr((*C.struct_sockaddr_storage)(ss))
|
|
}
|
|
|
|
func makeSockaddrStorage(ip net.IP, port int, ss *C.struct_sockaddr_storage) bool {
|
|
C.memset(unsafe.Pointer(ss), 0, C.sizeof_struct_sockaddr_storage)
|
|
if len(ip) == 4 {
|
|
sa4 := (*C.struct_sockaddr_in)(unsafe.Pointer(ss))
|
|
sa4.sin_family = syscall.AF_INET
|
|
copy(((*[4]byte)(unsafe.Pointer(&sa4.sin_addr)))[:], ip)
|
|
binary.BigEndian.PutUint16(((*[2]byte)(unsafe.Pointer(&sa4.sin_port)))[:], uint16(port))
|
|
return true
|
|
}
|
|
if len(ip) == 16 {
|
|
sa6 := (*C.struct_sockaddr_in6)(unsafe.Pointer(ss))
|
|
sa6.sin6_family = syscall.AF_INET6
|
|
copy(((*[16]byte)(unsafe.Pointer(&sa6.sin6_addr)))[:], ip)
|
|
binary.BigEndian.PutUint16(((*[2]byte)(unsafe.Pointer(&sa6.sin6_port)))[:], uint16(port))
|
|
return true
|
|
}
|
|
return false
|
|
}
|
|
|
|
var ErrInvalidInetAddress = errors.New("invalid marshaled InetAddress object")
|
|
|
|
// InetAddress implements net.Addr but has a ZeroTier-like string representation
|
|
type InetAddress struct {
|
|
IP net.IP
|
|
Port int
|
|
}
|
|
|
|
// Less returns true if this IP/port is lexicographically less than another
|
|
func (ina *InetAddress) Less(i2 *InetAddress) bool {
|
|
c := bytes.Compare(ina.IP, i2.IP)
|
|
if c < 0 {
|
|
return true
|
|
}
|
|
if c == 0 {
|
|
return ina.Port < i2.Port
|
|
}
|
|
return false
|
|
}
|
|
|
|
// NewInetAddressFromString parses an IP[/port] format address
|
|
func NewInetAddressFromString(s string) *InetAddress {
|
|
i := new(InetAddress)
|
|
ss := strings.Split(strings.TrimSpace(s), "/")
|
|
if len(ss) > 0 {
|
|
i.IP = net.ParseIP(ss[0])
|
|
i4 := i.IP.To4()
|
|
if len(i4) == 4 { // down-convert IPv4-in-6 IPs to native IPv4 as this is what all our code expects
|
|
i.IP = i4
|
|
}
|
|
if len(ss) > 1 {
|
|
p64, _ := strconv.ParseUint(ss[1], 10, 64)
|
|
i.Port = int(p64 & 0xffff)
|
|
}
|
|
}
|
|
return i
|
|
}
|
|
|
|
// NewInetAddressFromSockaddr parses a sockaddr_in or sockaddr_in6 C structure (may crash if given something other than these!)
|
|
// This is a convenience wrapper around the CGO functions in node.go.
|
|
func NewInetAddressFromSockaddr(sa unsafe.Pointer) *InetAddress {
|
|
i := new(InetAddress)
|
|
if uintptr(sa) != 0 {
|
|
ua := sockaddrStorageToUDPAddr2(sa)
|
|
if ua != nil {
|
|
i.IP = ua.IP
|
|
i.Port = ua.Port
|
|
}
|
|
}
|
|
return i
|
|
}
|
|
|
|
// Network returns "udp" to implement net.Addr
|
|
func (ina *InetAddress) Network() string {
|
|
return "udp"
|
|
}
|
|
|
|
// String returns this address in ZeroTier-canonical IP/port format
|
|
func (ina *InetAddress) String() string {
|
|
return ina.IP.String() + "/" + strconv.FormatInt(int64(ina.Port), 10)
|
|
}
|
|
|
|
// Family returns the address family (AFInet etc.) or 0 if none
|
|
func (ina *InetAddress) Family() int {
|
|
switch len(ina.IP) {
|
|
case 4:
|
|
return syscall.AF_INET
|
|
case 16:
|
|
return syscall.AF_INET6
|
|
}
|
|
return 0
|
|
}
|
|
|
|
// Valid returns true if both the IP and port have valid values
|
|
func (ina *InetAddress) Valid() bool {
|
|
return (len(ina.IP) == 4 || len(ina.IP) == 16) && (ina.Port > 0 && ina.Port < 65536)
|
|
}
|
|
|
|
// MarshalJSON marshals this MAC as a string
|
|
func (ina *InetAddress) MarshalJSON() ([]byte, error) {
|
|
s := ina.String()
|
|
return json.Marshal(&s)
|
|
}
|
|
|
|
// UnmarshalJSON unmarshals this MAC from a string
|
|
func (ina *InetAddress) UnmarshalJSON(j []byte) error {
|
|
var s string
|
|
err := json.Unmarshal(j, &s)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
*ina = *NewInetAddressFromString(s)
|
|
return nil
|
|
}
|
|
|
|
func (ina *InetAddress) unmarshalZT(b []byte) (int, error) {
|
|
if len(b) <= 0 {
|
|
return 0, ErrInvalidInetAddress
|
|
}
|
|
switch b[0] {
|
|
case 0:
|
|
ina.IP = nil
|
|
ina.Port = 0
|
|
return 1, nil
|
|
case 4:
|
|
if len(b) != 7 {
|
|
return 0, ErrInvalidInetAddress
|
|
}
|
|
ina.IP = []byte{b[1], b[2], b[3], b[4]}
|
|
ina.Port = int(binary.BigEndian.Uint16(b[5:7]))
|
|
return 7, nil
|
|
case 6:
|
|
if len(b) != 19 {
|
|
return 0, ErrInvalidInetAddress
|
|
}
|
|
ina.IP = append(make([]byte, 0, 16), b[1:17]...)
|
|
ina.Port = int(binary.BigEndian.Uint16(b[17:19]))
|
|
return 19, nil
|
|
default:
|
|
return 0, ErrInvalidInetAddress
|
|
}
|
|
}
|
|
|
|
// key returns a short array suitable for use as a map[] key for this IP
|
|
func (ina *InetAddress) key() (k [3]uint64) {
|
|
copy(((*[16]byte)(unsafe.Pointer(&k[0])))[:], ina.IP)
|
|
k[2] = uint64(ina.Port)
|
|
return
|
|
}
|