cloudflare/cloudflared
Publicmirrored from https://github.com/cloudflare/cloudflaredAvailable
origin/discovery.go
82lines · modecode
| 1 | package origin |
| 2 | |
| 3 | import ( |
| 4 | "fmt" |
| 5 | "net" |
| 6 | ) |
| 7 | |
| 8 | const ( |
| 9 | // Used to discover HA Warp servers |
| 10 | srvService = "warp" |
| 11 | srvProto = "tcp" |
| 12 | srvName = "cloudflarewarp.com" |
| 13 | ) |
| 14 | |
| 15 | func ResolveEdgeIPs(addresses []string) ([]*net.TCPAddr, error) { |
| 16 | if len(addresses) > 0 { |
| 17 | var tcpAddrs []*net.TCPAddr |
| 18 | for _, address := range addresses { |
| 19 | // Addresses specified (for testing, usually) |
| 20 | tcpAddr, err := net.ResolveTCPAddr("tcp", address) |
| 21 | if err != nil { |
| 22 | return nil, err |
| 23 | } |
| 24 | tcpAddrs = append(tcpAddrs, tcpAddr) |
| 25 | } |
| 26 | return tcpAddrs, nil |
| 27 | } |
| 28 | // HA service discovery lookup |
| 29 | _, addrs, err := net.LookupSRV(srvService, srvProto, srvName) |
| 30 | if err != nil { |
| 31 | return nil, err |
| 32 | } |
| 33 | var resolvedIPsPerCNAME [][]*net.TCPAddr |
| 34 | var lookupErr error |
| 35 | for _, addr := range addrs { |
| 36 | ips, err := ResolveSRVToTCP(addr) |
| 37 | if err != nil || len(ips) == 0 { |
| 38 | // don't return early, we might be able to resolve other addresses |
| 39 | lookupErr = err |
| 40 | continue |
| 41 | } |
| 42 | resolvedIPsPerCNAME = append(resolvedIPsPerCNAME, ips) |
| 43 | } |
| 44 | ips := FlattenServiceIPs(resolvedIPsPerCNAME) |
| 45 | if lookupErr == nil && len(ips) == 0 { |
| 46 | return nil, fmt.Errorf("Unknown service discovery error") |
| 47 | } |
| 48 | return ips, lookupErr |
| 49 | } |
| 50 | |
| 51 | func ResolveSRVToTCP(srv *net.SRV) ([]*net.TCPAddr, error) { |
| 52 | ips, err := net.LookupIP(srv.Target) |
| 53 | if err != nil { |
| 54 | return nil, err |
| 55 | } |
| 56 | addrs := make([]*net.TCPAddr, len(ips)) |
| 57 | for i, ip := range ips { |
| 58 | addrs[i] = &net.TCPAddr{IP: ip, Port: int(srv.Port)} |
| 59 | } |
| 60 | return addrs, nil |
| 61 | } |
| 62 | |
| 63 | // FlattenServiceIPs transposes and flattens the input slices such that the |
| 64 | // first element of the n inner slices are the first n elements of the result. |
| 65 | func FlattenServiceIPs(ipsByService [][]*net.TCPAddr) []*net.TCPAddr { |
| 66 | var result []*net.TCPAddr |
| 67 | for len(ipsByService) > 0 { |
| 68 | filtered := ipsByService[:0] |
| 69 | for _, ips := range ipsByService { |
| 70 | if len(ips) == 0 { |
| 71 | // sanity check |
| 72 | continue |
| 73 | } |
| 74 | result = append(result, ips[0]) |
| 75 | if len(ips) > 1 { |
| 76 | filtered = append(filtered, ips[1:]) |
| 77 | } |
| 78 | } |
| 79 | ipsByService = filtered |
| 80 | } |
| 81 | return result |
| 82 | } |
| 83 | |