Spaces:
Paused
Paused
| package utils | |
| import ( | |
| "net" | |
| "strings" | |
| ) | |
| // ShouldForceRelay checks if the system is likely behind a restrictive VPN or CGNAT | |
| // and returns true if we should force TURN usage. | |
| func ShouldForceRelay() bool { | |
| interfaces, err := net.Interfaces() | |
| if err != nil { | |
| return false | |
| } | |
| // 1. Define the CGNAT range (100.64.0.0/10) | |
| // Cloudflare WARP, Tailscale, and Carrier Grade NATs use this. | |
| // If we are on one of these, direct P2P often fails or requires relay anyway. | |
| _, cgnatBlock, _ := net.ParseCIDR("100.64.0.0/10") | |
| for _, iface := range interfaces { | |
| // Ignore loopback and down interfaces | |
| if iface.Flags&net.FlagUp == 0 || iface.Flags&net.FlagLoopback != 0 { | |
| continue | |
| } | |
| // 2. Check Interface Name Heuristics | |
| name := strings.ToLower(iface.Name) | |
| if strings.Contains(name, "tun") || // Standard VPNs (OpenVPN, etc) | |
| strings.Contains(name, "tap") || // Virtual adapters | |
| strings.Contains(name, "wg") || // WireGuard | |
| strings.Contains(name, "ppp") || // Point-to-Point | |
| strings.Contains(name, "warp") { // Explicit WARP | |
| return true | |
| } | |
| // 3. Check IP Addresses for CGNAT | |
| addrs, err := iface.Addrs() | |
| if err != nil { | |
| continue | |
| } | |
| for _, addr := range addrs { | |
| var ip net.IP | |
| switch v := addr.(type) { | |
| case *net.IPNet: | |
| ip = v.IP | |
| case *net.IPAddr: | |
| ip = v.IP | |
| } | |
| // If we find an IP inside 100.64.0.0/10, we are likely behind WARP or CGNAT | |
| if cgnatBlock.Contains(ip) { | |
| return true | |
| } | |
| } | |
| } | |
| return false | |
| } | |