sing/common/metadata/addr.go
2024-06-06 22:18:20 +08:00

242 lines
4.5 KiB
Go

package metadata
import (
"net"
"net/netip"
"strconv"
"unsafe"
"github.com/sagernet/sing/common/debug"
)
type Socksaddr struct {
Addr netip.Addr
Port uint16
Fqdn string
}
func (ap Socksaddr) Network() string {
return "socks"
}
func (ap Socksaddr) IsIP() bool {
return ap.Addr.IsValid()
}
func (ap Socksaddr) IsIPv4() bool {
return ap.Addr.Is4()
}
func (ap Socksaddr) IsIPv6() bool {
return ap.Addr.Is6()
}
func (ap Socksaddr) Unwrap() Socksaddr {
if ap.Addr.Is4In6() {
return Socksaddr{
Addr: netip.AddrFrom4(ap.Addr.As4()),
Port: ap.Port,
}
}
return ap
}
func (ap Socksaddr) IsFqdn() bool {
return IsDomainName(ap.Fqdn)
}
func (ap Socksaddr) IsValid() bool {
return ap.IsIP() || ap.IsFqdn()
}
func (ap Socksaddr) AddrString() string {
if debug.Enabled {
ap.CheckBadAddr()
}
if ap.Addr.IsValid() {
return ap.Addr.String()
} else {
return ap.Fqdn
}
}
func (ap Socksaddr) IPAddr() *net.IPAddr {
if debug.Enabled {
ap.CheckBadAddr()
}
return &net.IPAddr{
IP: ap.Addr.AsSlice(),
Zone: ap.Addr.Zone(),
}
}
func (ap Socksaddr) TCPAddr() *net.TCPAddr {
if debug.Enabled {
ap.CheckBadAddr()
}
return &net.TCPAddr{
IP: ap.Addr.AsSlice(),
Port: int(ap.Port),
Zone: ap.Addr.Zone(),
}
}
func (ap Socksaddr) UDPAddr() *net.UDPAddr {
if debug.Enabled {
ap.CheckBadAddr()
}
return &net.UDPAddr{
IP: ap.Addr.AsSlice(),
Port: int(ap.Port),
Zone: ap.Addr.Zone(),
}
}
func (ap Socksaddr) AddrPort() netip.AddrPort {
if debug.Enabled {
ap.CheckBadAddr()
}
return *(*netip.AddrPort)(unsafe.Pointer(&ap))
}
func (ap Socksaddr) String() string {
if debug.Enabled {
ap.CheckBadAddr()
}
return net.JoinHostPort(ap.AddrString(), strconv.Itoa(int(ap.Port)))
}
func (ap Socksaddr) CheckBadAddr() {
if ap.Addr.Is4In6() || ap.Addr.IsValid() && ap.Fqdn != "" {
panic("bad socksaddr")
}
}
func AddrPortFrom(ip net.IP, port uint16) netip.AddrPort {
return netip.AddrPortFrom(AddrFromIP(ip), port)
}
func SocksaddrFrom(addr netip.Addr, port uint16) Socksaddr {
return SocksaddrFromNetIP(netip.AddrPortFrom(addr, port))
}
func SocksaddrFromNetIP(ap netip.AddrPort) Socksaddr {
return Socksaddr{
Addr: ap.Addr(),
Port: ap.Port(),
}
}
func SocksaddrFromNet(ap net.Addr) Socksaddr {
if ap == nil {
return Socksaddr{}
}
if socksAddr, ok := ap.(Socksaddr); ok {
return socksAddr
}
addr := SocksaddrFromNetIP(AddrPortFromNet(ap))
if addr.IsValid() {
return addr
}
return ParseSocksaddr(ap.String())
}
func AddrFromNet(netAddr net.Addr) netip.Addr {
if addr := AddrPortFromNet(netAddr); addr.Addr().IsValid() {
return addr.Addr()
}
switch addr := netAddr.(type) {
case Socksaddr:
return addr.Addr
case *net.IPAddr:
return AddrFromIP(addr.IP)
case *net.IPNet:
return AddrFromIP(addr.IP)
default:
return netip.Addr{}
}
}
func PrefixFromNet(netAddr net.Addr) netip.Prefix {
switch addr := netAddr.(type) {
case *net.IPNet:
bits, _ := addr.Mask.Size()
return netip.PrefixFrom(AddrFromIP(addr.IP).Unmap(), bits)
default:
return netip.Prefix{}
}
}
func AddrPortFromNet(netAddr net.Addr) netip.AddrPort {
var ip net.IP
var port uint16
switch addr := netAddr.(type) {
case Socksaddr:
return addr.AddrPort()
case *net.TCPAddr:
ip = addr.IP
port = uint16(addr.Port)
case *net.UDPAddr:
ip = addr.IP
port = uint16(addr.Port)
case *net.IPAddr:
ip = addr.IP
}
return netip.AddrPortFrom(AddrFromIP(ip), port)
}
func AddrFromIP(ip net.IP) netip.Addr {
addr, _ := netip.AddrFromSlice(ip)
return addr
}
func ParseAddr(address string) netip.Addr {
addr, _ := netip.ParseAddr(unwrapIPv6Address(address))
return addr
}
func ParseSocksaddr(address string) Socksaddr {
host, port, err := net.SplitHostPort(address)
if err != nil {
return ParseSocksaddrHostPort(address, 0)
}
return ParseSocksaddrHostPortStr(host, port)
}
func ParseSocksaddrHostPort(host string, port uint16) Socksaddr {
netAddr, err := netip.ParseAddr(unwrapIPv6Address(host))
if err != nil {
return Socksaddr{
Fqdn: host,
Port: port,
}
} else {
return Socksaddr{
Addr: netAddr,
Port: port,
}
}
}
func ParseSocksaddrHostPortStr(host string, portStr string) Socksaddr {
port, _ := strconv.Atoi(portStr)
netAddr, err := netip.ParseAddr(unwrapIPv6Address(host))
if err != nil {
return Socksaddr{
Fqdn: host,
Port: uint16(port),
}
} else {
return Socksaddr{
Addr: netAddr,
Port: uint16(port),
}
}
}
func unwrapIPv6Address(address string) string {
if len(address) > 2 && address[0] == '[' && address[len(address)-1] == ']' {
return address[1 : len(address)-1]
}
return address
}