github.com/sagernet/sing@v0.4.0-beta.19.0.20240518125136-f67a0988a636/common/metadata/addr.go (about)

     1  package metadata
     2  
     3  import (
     4  	"net"
     5  	"net/netip"
     6  	"strconv"
     7  	"unsafe"
     8  
     9  	"github.com/sagernet/sing/common/debug"
    10  )
    11  
    12  type Socksaddr struct {
    13  	Addr netip.Addr
    14  	Port uint16
    15  	Fqdn string
    16  }
    17  
    18  func (ap Socksaddr) Network() string {
    19  	return "socks"
    20  }
    21  
    22  func (ap Socksaddr) IsIP() bool {
    23  	return ap.Addr.IsValid()
    24  }
    25  
    26  func (ap Socksaddr) IsIPv4() bool {
    27  	return ap.Addr.Is4()
    28  }
    29  
    30  func (ap Socksaddr) IsIPv6() bool {
    31  	return ap.Addr.Is6()
    32  }
    33  
    34  func (ap Socksaddr) Unwrap() Socksaddr {
    35  	if ap.Addr.Is4In6() {
    36  		return Socksaddr{
    37  			Addr: netip.AddrFrom4(ap.Addr.As4()),
    38  			Port: ap.Port,
    39  		}
    40  	}
    41  	return ap
    42  }
    43  
    44  func (ap Socksaddr) IsFqdn() bool {
    45  	return IsDomainName(ap.Fqdn)
    46  }
    47  
    48  func (ap Socksaddr) IsValid() bool {
    49  	return ap.IsIP() || ap.IsFqdn()
    50  }
    51  
    52  func (ap Socksaddr) AddrString() string {
    53  	if debug.Enabled {
    54  		ap.CheckBadAddr()
    55  	}
    56  	if ap.Addr.IsValid() {
    57  		return ap.Addr.String()
    58  	} else {
    59  		return ap.Fqdn
    60  	}
    61  }
    62  
    63  func (ap Socksaddr) IPAddr() *net.IPAddr {
    64  	if debug.Enabled {
    65  		ap.CheckBadAddr()
    66  	}
    67  	return &net.IPAddr{
    68  		IP:   ap.Addr.AsSlice(),
    69  		Zone: ap.Addr.Zone(),
    70  	}
    71  }
    72  
    73  func (ap Socksaddr) TCPAddr() *net.TCPAddr {
    74  	if debug.Enabled {
    75  		ap.CheckBadAddr()
    76  	}
    77  	return &net.TCPAddr{
    78  		IP:   ap.Addr.AsSlice(),
    79  		Port: int(ap.Port),
    80  		Zone: ap.Addr.Zone(),
    81  	}
    82  }
    83  
    84  func (ap Socksaddr) UDPAddr() *net.UDPAddr {
    85  	if debug.Enabled {
    86  		ap.CheckBadAddr()
    87  	}
    88  	return &net.UDPAddr{
    89  		IP:   ap.Addr.AsSlice(),
    90  		Port: int(ap.Port),
    91  		Zone: ap.Addr.Zone(),
    92  	}
    93  }
    94  
    95  func (ap Socksaddr) AddrPort() netip.AddrPort {
    96  	if debug.Enabled {
    97  		ap.CheckBadAddr()
    98  	}
    99  	return *(*netip.AddrPort)(unsafe.Pointer(&ap))
   100  }
   101  
   102  func (ap Socksaddr) String() string {
   103  	if debug.Enabled {
   104  		ap.CheckBadAddr()
   105  	}
   106  	return net.JoinHostPort(ap.AddrString(), strconv.Itoa(int(ap.Port)))
   107  }
   108  
   109  func (ap Socksaddr) CheckBadAddr() {
   110  	if ap.Addr.Is4In6() || ap.Addr.IsValid() && ap.Fqdn != "" {
   111  		panic("bad socksaddr")
   112  	}
   113  }
   114  
   115  func AddrPortFrom(ip net.IP, port uint16) netip.AddrPort {
   116  	return netip.AddrPortFrom(AddrFromIP(ip), port)
   117  }
   118  
   119  func SocksaddrFrom(addr netip.Addr, port uint16) Socksaddr {
   120  	return SocksaddrFromNetIP(netip.AddrPortFrom(addr, port))
   121  }
   122  
   123  func SocksaddrFromNetIP(ap netip.AddrPort) Socksaddr {
   124  	return Socksaddr{
   125  		Addr: ap.Addr(),
   126  		Port: ap.Port(),
   127  	}
   128  }
   129  
   130  func SocksaddrFromNet(ap net.Addr) Socksaddr {
   131  	if ap == nil {
   132  		return Socksaddr{}
   133  	}
   134  	if socksAddr, ok := ap.(Socksaddr); ok {
   135  		return socksAddr
   136  	}
   137  	addr := SocksaddrFromNetIP(AddrPortFromNet(ap))
   138  	if addr.IsValid() {
   139  		return addr
   140  	}
   141  	return ParseSocksaddr(ap.String())
   142  }
   143  
   144  func AddrFromNet(netAddr net.Addr) netip.Addr {
   145  	if addr := AddrPortFromNet(netAddr); addr.Addr().IsValid() {
   146  		return addr.Addr()
   147  	}
   148  	switch addr := netAddr.(type) {
   149  	case Socksaddr:
   150  		return addr.Addr
   151  	case *net.IPAddr:
   152  		return AddrFromIP(addr.IP)
   153  	case *net.IPNet:
   154  		return AddrFromIP(addr.IP)
   155  	default:
   156  		return netip.Addr{}
   157  	}
   158  }
   159  
   160  func PrefixFromNet(netAddr net.Addr) netip.Prefix {
   161  	switch addr := netAddr.(type) {
   162  	case *net.IPNet:
   163  		bits, _ := addr.Mask.Size()
   164  		return netip.PrefixFrom(AddrFromIP(addr.IP), bits)
   165  	default:
   166  		return netip.Prefix{}
   167  	}
   168  }
   169  
   170  func AddrPortFromNet(netAddr net.Addr) netip.AddrPort {
   171  	var ip net.IP
   172  	var port uint16
   173  	switch addr := netAddr.(type) {
   174  	case Socksaddr:
   175  		return addr.AddrPort()
   176  	case *net.TCPAddr:
   177  		ip = addr.IP
   178  		port = uint16(addr.Port)
   179  	case *net.UDPAddr:
   180  		ip = addr.IP
   181  		port = uint16(addr.Port)
   182  	case *net.IPAddr:
   183  		ip = addr.IP
   184  	}
   185  	return netip.AddrPortFrom(AddrFromIP(ip), port)
   186  }
   187  
   188  func AddrFromIP(ip net.IP) netip.Addr {
   189  	addr, _ := netip.AddrFromSlice(ip)
   190  	return addr
   191  }
   192  
   193  func ParseAddr(address string) netip.Addr {
   194  	addr, _ := netip.ParseAddr(unwrapIPv6Address(address))
   195  	return addr
   196  }
   197  
   198  func ParseSocksaddr(address string) Socksaddr {
   199  	host, port, err := net.SplitHostPort(address)
   200  	if err != nil {
   201  		return ParseSocksaddrHostPort(address, 0)
   202  	}
   203  	return ParseSocksaddrHostPortStr(host, port)
   204  }
   205  
   206  func ParseSocksaddrHostPort(host string, port uint16) Socksaddr {
   207  	netAddr, err := netip.ParseAddr(unwrapIPv6Address(host))
   208  	if err != nil {
   209  		return Socksaddr{
   210  			Fqdn: host,
   211  			Port: port,
   212  		}
   213  	} else {
   214  		return Socksaddr{
   215  			Addr: netAddr,
   216  			Port: port,
   217  		}
   218  	}
   219  }
   220  
   221  func ParseSocksaddrHostPortStr(host string, portStr string) Socksaddr {
   222  	port, _ := strconv.Atoi(portStr)
   223  	netAddr, err := netip.ParseAddr(unwrapIPv6Address(host))
   224  	if err != nil {
   225  		return Socksaddr{
   226  			Fqdn: host,
   227  			Port: uint16(port),
   228  		}
   229  	} else {
   230  		return Socksaddr{
   231  			Addr: netAddr,
   232  			Port: uint16(port),
   233  		}
   234  	}
   235  }
   236  
   237  func unwrapIPv6Address(address string) string {
   238  	if len(address) > 2 && address[0] == '[' && address[len(address)-1] == ']' {
   239  		return address[1 : len(address)-1]
   240  	}
   241  	return address
   242  }