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 }