bind.go 2.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102
  1. package dialer
  2. import (
  3. "net"
  4. "net/netip"
  5. "strconv"
  6. "strings"
  7. "github.com/metacubex/mihomo/component/iface"
  8. )
  9. func LookupLocalAddrFromIfaceName(ifaceName string, network string, destination netip.Addr, port int) (net.Addr, error) {
  10. ifaceObj, err := iface.ResolveInterface(ifaceName)
  11. if err != nil {
  12. return nil, err
  13. }
  14. destination = destination.Unmap()
  15. var addr netip.Prefix
  16. switch network {
  17. case "udp4", "tcp4":
  18. addr, err = ifaceObj.PickIPv4Addr(destination)
  19. case "tcp6", "udp6":
  20. addr, err = ifaceObj.PickIPv6Addr(destination)
  21. default:
  22. if destination.IsValid() {
  23. if destination.Is4() {
  24. addr, err = ifaceObj.PickIPv4Addr(destination)
  25. } else {
  26. addr, err = ifaceObj.PickIPv6Addr(destination)
  27. }
  28. } else {
  29. addr, err = ifaceObj.PickIPv4Addr(destination)
  30. }
  31. }
  32. if err != nil {
  33. return nil, err
  34. }
  35. if strings.HasPrefix(network, "tcp") {
  36. return &net.TCPAddr{
  37. IP: addr.Addr().AsSlice(),
  38. Port: port,
  39. }, nil
  40. } else if strings.HasPrefix(network, "udp") {
  41. return &net.UDPAddr{
  42. IP: addr.Addr().AsSlice(),
  43. Port: port,
  44. }, nil
  45. }
  46. return nil, iface.ErrAddrNotFound
  47. }
  48. func fallbackBindIfaceToDialer(ifaceName string, dialer *net.Dialer, network string, destination netip.Addr) error {
  49. if !destination.IsGlobalUnicast() {
  50. return nil
  51. }
  52. local := uint64(0)
  53. if dialer.LocalAddr != nil {
  54. _, port, err := net.SplitHostPort(dialer.LocalAddr.String())
  55. if err == nil {
  56. local, _ = strconv.ParseUint(port, 10, 16)
  57. }
  58. }
  59. addr, err := LookupLocalAddrFromIfaceName(ifaceName, network, destination, int(local))
  60. if err != nil {
  61. return err
  62. }
  63. dialer.LocalAddr = addr
  64. return nil
  65. }
  66. func fallbackBindIfaceToListenConfig(ifaceName string, _ *net.ListenConfig, network, address string, rAddrPort netip.AddrPort) (string, error) {
  67. _, port, err := net.SplitHostPort(address)
  68. if err != nil {
  69. port = "0"
  70. }
  71. local, _ := strconv.ParseUint(port, 10, 16)
  72. addr, err := LookupLocalAddrFromIfaceName(ifaceName, network, netip.Addr{}, int(local))
  73. if err != nil {
  74. return "", err
  75. }
  76. return addr.String(), nil
  77. }
  78. func fallbackParseNetwork(network string, addr netip.Addr) string {
  79. // fix fallbackBindIfaceToListenConfig() force bind to an ipv4 address
  80. if !strings.HasSuffix(network, "4") &&
  81. !strings.HasSuffix(network, "6") &&
  82. addr.Unmap().Is6() {
  83. network += "6"
  84. }
  85. return network
  86. }