github.com/nxtrace/NTrace-core@v1.3.1-0.20240513132635-39169291e8c9/util/util.go (about)

     1  package util
     2  
     3  import (
     4  	"context"
     5  	"errors"
     6  	"fmt"
     7  	"github.com/nxtrace/NTrace-core/config"
     8  	"log"
     9  	"net"
    10  	"net/url"
    11  	"os"
    12  	"runtime"
    13  	"strings"
    14  	"sync"
    15  
    16  	"github.com/fatih/color"
    17  )
    18  
    19  var Uninterrupted = GetenvDefault("NEXTTRACE_UNINTERRUPTED", "")
    20  var EnvToken = GetenvDefault("NEXTTRACE_TOKEN", "")
    21  var UserAgent = fmt.Sprintf("NextTrace %s/%s/%s", config.Version, runtime.GOOS, runtime.GOARCH)
    22  var RdnsCache sync.Map
    23  var PowProviderParam = ""
    24  var DisableMPLS = GetenvDefault("NEXTTRACE_DISABLEMPLS", "")
    25  var EnableHidDstIP = GetenvDefault("NEXTTRACE_ENABLEHIDDENDSTIP", "")
    26  var DestIP string
    27  
    28  func LookupAddr(addr string) ([]string, error) {
    29  	// 如果在缓存中找到,直接返回
    30  	if hostname, ok := RdnsCache.Load(addr); ok {
    31  		//fmt.Println("hit RdnsCache for", addr, hostname)
    32  		return []string{hostname.(string)}, nil
    33  	}
    34  	// 如果缓存中未找到,进行 DNS 查询
    35  	names, err := net.LookupAddr(addr)
    36  	if err != nil {
    37  		return nil, err
    38  	}
    39  	// 将查询结果存入缓存
    40  	if len(names) > 0 {
    41  		RdnsCache.Store(addr, names[0])
    42  	}
    43  	return names, nil
    44  }
    45  
    46  // LocalIPPort get the local ip and port based on our destination ip
    47  func LocalIPPort(dstip net.IP) (net.IP, int) {
    48  	serverAddr, err := net.ResolveUDPAddr("udp", dstip.String()+":12345")
    49  	if err != nil {
    50  		log.Fatal(err)
    51  	}
    52  
    53  	// We don't actually connect to anything, but we can determine
    54  	// based on our destination ip what source ip we should use.
    55  	if con, err := net.DialUDP("udp", nil, serverAddr); err == nil {
    56  		defer con.Close()
    57  		if udpaddr, ok := con.LocalAddr().(*net.UDPAddr); ok {
    58  			return udpaddr.IP, udpaddr.Port
    59  		}
    60  	}
    61  	return nil, -1
    62  }
    63  
    64  func LocalIPPortv6(dstip net.IP) (net.IP, int) {
    65  	serverAddr, err := net.ResolveUDPAddr("udp", "["+dstip.String()+"]:12345")
    66  	if err != nil {
    67  		log.Fatal(err)
    68  	}
    69  
    70  	// We don't actually connect to anything, but we can determine
    71  	// based on our destination ip what source ip we should use.
    72  	if con, err := net.DialUDP("udp", nil, serverAddr); err == nil {
    73  		defer con.Close()
    74  		if udpaddr, ok := con.LocalAddr().(*net.UDPAddr); ok {
    75  			return udpaddr.IP, udpaddr.Port
    76  		}
    77  	}
    78  	return nil, -1
    79  }
    80  
    81  func DomainLookUp(host string, ipVersion string, dotServer string, disableOutput bool) (net.IP, error) {
    82  	// ipVersion: 4, 6, all
    83  	var (
    84  		r   *net.Resolver
    85  		ips []net.IP
    86  	)
    87  
    88  	switch dotServer {
    89  	case "dnssb":
    90  		r = DNSSB()
    91  	case "aliyun":
    92  		r = Aliyun()
    93  	case "dnspod":
    94  		r = Dnspod()
    95  	case "google":
    96  		r = Google()
    97  	case "cloudflare":
    98  		r = Cloudflare()
    99  	default:
   100  		r = newUDPResolver()
   101  	}
   102  	ipsStr, err := r.LookupHost(context.Background(), host)
   103  	for _, v := range ipsStr {
   104  		ips = append(ips, net.ParseIP(v))
   105  	}
   106  	if err != nil {
   107  		return nil, errors.New("DNS lookup failed")
   108  	}
   109  
   110  	//var ipv6Flag = false
   111  	//TODO: 此处代码暂无意义
   112  	//if ipv6Flag {
   113  	//	fmt.Println("[Info] IPv6 UDP Traceroute is not supported right now.")
   114  	//	if len(ips) == 0 {
   115  	//		os.Exit(0)
   116  	//	}
   117  	//}
   118  
   119  	// Filter by IPv4/IPv6
   120  	if ipVersion != "all" {
   121  		var filteredIPs []net.IP
   122  		for _, ip := range ips {
   123  			if ipVersion == "4" && ip.To4() != nil {
   124  				filteredIPs = []net.IP{ip}
   125  				break
   126  			} else if ipVersion == "6" && strings.Contains(ip.String(), ":") {
   127  				filteredIPs = []net.IP{ip}
   128  				break
   129  			}
   130  		}
   131  		ips = filteredIPs
   132  	}
   133  
   134  	if (len(ips) == 1) || (disableOutput) {
   135  		return ips[0], nil
   136  	} else {
   137  		fmt.Println("Please Choose the IP You Want To TraceRoute")
   138  		for i, ip := range ips {
   139  			fmt.Fprintf(color.Output, "%s %s\n",
   140  				color.New(color.FgHiYellow, color.Bold).Sprintf("%d.", i),
   141  				color.New(color.FgWhite, color.Bold).Sprintf("%s", ip),
   142  			)
   143  		}
   144  		var index int
   145  		fmt.Printf("Your Option: ")
   146  		_, err := fmt.Scanln(&index)
   147  		if err != nil {
   148  			index = 0
   149  		}
   150  		if index >= len(ips) || index < 0 {
   151  			fmt.Println("Your Option is invalid")
   152  			os.Exit(3)
   153  		}
   154  		return ips[index], nil
   155  	}
   156  }
   157  
   158  func GetenvDefault(key, defVal string) string {
   159  	val, ok := os.LookupEnv(key)
   160  	if ok {
   161  		_, ok := os.LookupEnv("NEXTTRACE_DEBUG")
   162  		if ok {
   163  			fmt.Println("ENV", key, "detected as", val)
   164  		}
   165  		return val
   166  	}
   167  	return defVal
   168  }
   169  
   170  func GetHostAndPort() (host string, port string) {
   171  	var hostP = GetenvDefault("NEXTTRACE_HOSTPORT", "origin-fallback.nxtrace.org")
   172  	// 解析域名
   173  	hostArr := strings.Split(hostP, ":")
   174  	// 判断是否有指定端口
   175  	if len(hostArr) > 1 {
   176  		// 判断是否为 IPv6
   177  		if strings.HasPrefix(hostP, "[") {
   178  			tmp := strings.Split(hostP, "]")
   179  			host = tmp[0]
   180  			host = host[1:]
   181  			if port = tmp[1]; port != "" {
   182  				port = port[1:]
   183  			}
   184  		} else {
   185  			host, port = hostArr[0], hostArr[1]
   186  		}
   187  	} else {
   188  		host = hostP
   189  	}
   190  	if port == "" {
   191  		// 默认端口
   192  		port = "443"
   193  	}
   194  	return
   195  }
   196  
   197  func GetProxy() *url.URL {
   198  	proxyURLStr := GetenvDefault("NEXTTRACE_PROXY", "")
   199  	if proxyURLStr == "" {
   200  		return nil
   201  	}
   202  	proxyURL, err := url.Parse(proxyURLStr)
   203  	if err != nil {
   204  		log.Println("Failed to parse proxy URL:", err)
   205  		return nil
   206  	}
   207  	return proxyURL
   208  }
   209  
   210  func GetPowProvider() string {
   211  	var powProvider string
   212  	if PowProviderParam == "" {
   213  		powProvider = GetenvDefault("NEXTTRACE_POWPROVIDER", "api.nxtrace.org")
   214  	} else {
   215  		powProvider = PowProviderParam
   216  	}
   217  	if powProvider == "sakura" {
   218  		return "pow.nexttrace.owo.13a.com"
   219  	}
   220  	return ""
   221  }
   222  
   223  func StringInSlice(val string, list []string) bool {
   224  	for _, v := range list {
   225  		if v == val {
   226  			return true
   227  		}
   228  	}
   229  	return false
   230  }
   231  
   232  func HideIPPart(ip string) string {
   233  	parsedIP := net.ParseIP(ip)
   234  	if parsedIP == nil {
   235  		return ""
   236  	}
   237  
   238  	if parsedIP.To4() != nil {
   239  		// IPv4: 隐藏后16位
   240  		return strings.Join(strings.Split(ip, ".")[:2], ".") + ".0.0/16"
   241  	}
   242  	// IPv6: 隐藏后96位
   243  	return parsedIP.Mask(net.CIDRMask(32, 128)).String() + "/32"
   244  }