mirror of
https://github.com/zerotier/ZeroTierOne.git
synced 2025-02-11 13:35:17 +00:00
124 lines
2.9 KiB
Go
124 lines
2.9 KiB
Go
/*
|
|
* Copyright (c)2019 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: 2023-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
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/json"
|
|
"net"
|
|
"strconv"
|
|
"strings"
|
|
"unsafe"
|
|
)
|
|
|
|
// 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 (i *InetAddress) Less(i2 *InetAddress) bool {
|
|
c := bytes.Compare(i.IP, i2.IP)
|
|
if c < 0 {
|
|
return true
|
|
}
|
|
if c == 0 {
|
|
return i.Port < i2.Port
|
|
}
|
|
return false
|
|
}
|
|
|
|
// NewInetAddressFromString parses an IP[/port] format address
|
|
func NewInetAddressFromString(s string) *InetAddress {
|
|
i := new(InetAddress)
|
|
ss := strings.Split(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(s, 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 (i *InetAddress) Network() string {
|
|
return "udp"
|
|
}
|
|
|
|
// String returns this address in ZeroTier-canonical IP/port format
|
|
func (i *InetAddress) String() string {
|
|
return i.IP.String() + "/" + strconv.FormatInt(int64(i.Port), 10)
|
|
}
|
|
|
|
// Family returns the address family (AFInet etc.) or 0 if none
|
|
func (i *InetAddress) Family() int {
|
|
switch len(i.IP) {
|
|
case 4:
|
|
return AFInet
|
|
case 16:
|
|
return AFInet6
|
|
}
|
|
return 0
|
|
}
|
|
|
|
// Valid returns true if both the IP and port have valid values
|
|
func (i *InetAddress) Valid() bool {
|
|
return (len(i.IP) == 4 || len(i.IP) == 16) && (i.Port > 0 && i.Port < 65536)
|
|
}
|
|
|
|
// MarshalJSON marshals this MAC as a string
|
|
func (i *InetAddress) MarshalJSON() ([]byte, error) {
|
|
s := i.String()
|
|
return json.Marshal(&s)
|
|
}
|
|
|
|
// UnmarshalJSON unmarshals this MAC from a string
|
|
func (i *InetAddress) UnmarshalJSON(j []byte) error {
|
|
var s string
|
|
err := json.Unmarshal(j, &s)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
*i = *NewInetAddressFromString(s)
|
|
return nil
|
|
}
|
|
|
|
// key returns a short array suitable for use as a map[] key for this IP
|
|
func (i *InetAddress) key() (k [3]uint64) {
|
|
copy(((*[16]byte)(unsafe.Pointer(&k[0])))[:], i.IP)
|
|
k[2] = uint64(i.Port)
|
|
return
|
|
}
|