Skip to content

Commit 5f6e867

Browse files
TUN-4602: Added UDP resolves to Edge discovery
1 parent 78a9454 commit 5f6e867

File tree

11 files changed

+223
-144
lines changed

11 files changed

+223
-144
lines changed

edgediscovery/allregions/discovery.go

Lines changed: 31 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,12 @@ var (
3030
netLookupIP = net.LookupIP
3131
)
3232

33+
// EdgeAddr is a representation of possible ways to refer an edge location.
34+
type EdgeAddr struct {
35+
TCP *net.TCPAddr
36+
UDP *net.UDPAddr
37+
}
38+
3339
// If the call to net.LookupSRV fails, try to fall back to DoT from Cloudflare directly.
3440
//
3541
// Note: Instead of DoT, we could also have used DoH. Either of these:
@@ -53,7 +59,7 @@ var friendlyDNSErrorLines = []string{
5359
}
5460

5561
// EdgeDiscovery implements HA service discovery lookup.
56-
func edgeDiscovery(log *zerolog.Logger) ([][]*net.TCPAddr, error) {
62+
func edgeDiscovery(log *zerolog.Logger) ([][]*EdgeAddr, error) {
5763
_, addrs, err := netLookupSRV(srvService, srvProto, srvName)
5864
if err != nil {
5965
_, fallbackAddrs, fallbackErr := fallbackLookupSRV(srvService, srvProto, srvName)
@@ -69,16 +75,16 @@ func edgeDiscovery(log *zerolog.Logger) ([][]*net.TCPAddr, error) {
6975
addrs = fallbackAddrs
7076
}
7177

72-
var resolvedIPsPerCNAME [][]*net.TCPAddr
78+
var resolvedAddrPerCNAME [][]*EdgeAddr
7379
for _, addr := range addrs {
74-
ips, err := resolveSRVToTCP(addr)
80+
edgeAddrs, err := resolveSRV(addr)
7581
if err != nil {
7682
return nil, err
7783
}
78-
resolvedIPsPerCNAME = append(resolvedIPsPerCNAME, ips)
84+
resolvedAddrPerCNAME = append(resolvedAddrPerCNAME, edgeAddrs)
7985
}
8086

81-
return resolvedIPsPerCNAME, nil
87+
return resolvedAddrPerCNAME, nil
8288
}
8389

8490
func lookupSRVWithDOT(service, proto, name string) (cname string, addrs []*net.SRV, err error) {
@@ -100,31 +106,44 @@ func lookupSRVWithDOT(service, proto, name string) (cname string, addrs []*net.S
100106
return r.LookupSRV(ctx, srvService, srvProto, srvName)
101107
}
102108

103-
func resolveSRVToTCP(srv *net.SRV) ([]*net.TCPAddr, error) {
109+
func resolveSRV(srv *net.SRV) ([]*EdgeAddr, error) {
104110
ips, err := netLookupIP(srv.Target)
105111
if err != nil {
106112
return nil, errors.Wrapf(err, "Couldn't resolve SRV record %v", srv)
107113
}
108114
if len(ips) == 0 {
109115
return nil, fmt.Errorf("SRV record %v had no IPs", srv)
110116
}
111-
addrs := make([]*net.TCPAddr, len(ips))
117+
addrs := make([]*EdgeAddr, len(ips))
112118
for i, ip := range ips {
113-
addrs[i] = &net.TCPAddr{IP: ip, Port: int(srv.Port)}
119+
addrs[i] = &EdgeAddr{
120+
TCP: &net.TCPAddr{IP: ip, Port: int(srv.Port)},
121+
UDP: &net.UDPAddr{IP: ip, Port: int(srv.Port)},
122+
}
114123
}
115124
return addrs, nil
116125
}
117126

118127
// ResolveAddrs resolves TCP address given a list of addresses. Address can be a hostname, however, it will return at most one
119128
// of the hostname's IP addresses.
120-
func ResolveAddrs(addrs []string, log *zerolog.Logger) (resolved []*net.TCPAddr) {
129+
func ResolveAddrs(addrs []string, log *zerolog.Logger) (resolved []*EdgeAddr) {
121130
for _, addr := range addrs {
122131
tcpAddr, err := net.ResolveTCPAddr("tcp", addr)
123132
if err != nil {
124-
log.Err(err).Msgf("Failed to resolve %s", addr)
125-
} else {
126-
resolved = append(resolved, tcpAddr)
133+
log.Error().Msgf("Failed to resolve %s to TCP address, err: %v", addr, err)
134+
continue
127135
}
136+
137+
udpAddr, err := net.ResolveUDPAddr("udp", addr)
138+
if err != nil {
139+
log.Error().Msgf("Failed to resolve %s to UDP address, err: %v", addr, err)
140+
continue
141+
}
142+
resolved = append(resolved, &EdgeAddr{
143+
TCP: tcpAddr,
144+
UDP: udpAddr,
145+
})
146+
128147
}
129148
return
130149
}

edgediscovery/allregions/discovery_test.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,17 @@
11
package allregions
22

33
import (
4+
"fmt"
45
"testing"
56

67
"github.com/rs/zerolog"
78
"github.com/stretchr/testify/assert"
89
)
910

11+
func (ea *EdgeAddr) String() string {
12+
return fmt.Sprintf("%s-%s", ea.TCP, ea.UDP)
13+
}
14+
1015
func TestEdgeDiscovery(t *testing.T) {
1116
mockAddrs := newMockAddrs(19, 2, 5)
1217
netLookupSRV = mockNetLookupSRV(mockAddrs)

edgediscovery/allregions/mocks_for_test.go

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -11,27 +11,32 @@ import (
1111

1212
type mockAddrs struct {
1313
// a set of synthetic SRV records
14-
addrMap map[net.SRV][]*net.TCPAddr
14+
addrMap map[net.SRV][]*EdgeAddr
1515
// the total number of addresses, aggregated across addrMap.
1616
// For the convenience of test code that would otherwise have to compute
1717
// this by hand every time.
1818
numAddrs int
1919
}
2020

2121
func newMockAddrs(port uint16, numRegions uint8, numAddrsPerRegion uint8) mockAddrs {
22-
addrMap := make(map[net.SRV][]*net.TCPAddr)
22+
addrMap := make(map[net.SRV][]*EdgeAddr)
2323
numAddrs := 0
2424

2525
for r := uint8(0); r < numRegions; r++ {
2626
var (
2727
srv = net.SRV{Target: fmt.Sprintf("test-region-%v.example.com", r), Port: port}
28-
addrs []*net.TCPAddr
28+
addrs []*EdgeAddr
2929
)
3030
for a := uint8(0); a < numAddrsPerRegion; a++ {
31-
addrs = append(addrs, &net.TCPAddr{
31+
tcpAddr := &net.TCPAddr{
3232
IP: net.ParseIP(fmt.Sprintf("10.0.%v.%v", r, a)),
3333
Port: int(port),
34-
})
34+
}
35+
udpAddr := &net.UDPAddr{
36+
IP: net.ParseIP(fmt.Sprintf("10.0.%v.%v", r, a)),
37+
Port: int(port),
38+
}
39+
addrs = append(addrs, &EdgeAddr{tcpAddr, udpAddr})
3540
}
3641
addrMap[srv] = addrs
3742
numAddrs += len(addrs)
@@ -74,13 +79,13 @@ func mockNetLookupIP(
7479
m mockAddrs,
7580
) func(host string) ([]net.IP, error) {
7681
return func(host string) ([]net.IP, error) {
77-
for srv, tcpAddrs := range m.addrMap {
82+
for srv, addrs := range m.addrMap {
7883
if srv.Target != host {
7984
continue
8085
}
81-
result := make([]net.IP, len(tcpAddrs))
82-
for i, tcpAddr := range tcpAddrs {
83-
result[i] = tcpAddr.IP
86+
result := make([]net.IP, len(addrs))
87+
for i, addr := range addrs {
88+
result[i] = addr.TCP.IP
8489
}
8590
return result, nil
8691
}

edgediscovery/allregions/region.go

Lines changed: 12 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,27 @@
11
package allregions
22

3-
import (
4-
"net"
5-
)
6-
73
// Region contains cloudflared edge addresses. The edge is partitioned into several regions for
84
// redundancy purposes.
95
type Region struct {
10-
connFor map[*net.TCPAddr]UsedBy
6+
connFor map[*EdgeAddr]UsedBy
117
}
128

139
// NewRegion creates a region with the given addresses, which are all unused.
14-
func NewRegion(addrs []*net.TCPAddr) Region {
10+
func NewRegion(addrs []*EdgeAddr) Region {
1511
// The zero value of UsedBy is Unused(), so we can just initialize the map's values with their
1612
// zero values.
17-
m := make(map[*net.TCPAddr]UsedBy)
13+
connFor := make(map[*EdgeAddr]UsedBy)
1814
for _, addr := range addrs {
19-
m[addr] = Unused()
15+
connFor[addr] = Unused()
16+
}
17+
return Region{
18+
connFor: connFor,
2019
}
21-
return Region{connFor: m}
2220
}
2321

2422
// AddrUsedBy finds the address used by the given connection in this region.
2523
// Returns nil if the connection isn't using any IP.
26-
func (r *Region) AddrUsedBy(connID int) *net.TCPAddr {
24+
func (r *Region) AddrUsedBy(connID int) *EdgeAddr {
2725
for addr, used := range r.connFor {
2826
if used.Used && used.ConnID == connID {
2927
return addr
@@ -45,7 +43,7 @@ func (r Region) AvailableAddrs() int {
4543

4644
// GetUnusedIP returns a random unused address in this region.
4745
// Returns nil if all addresses are in use.
48-
func (r Region) GetUnusedIP(excluding *net.TCPAddr) *net.TCPAddr {
46+
func (r Region) GetUnusedIP(excluding *EdgeAddr) *EdgeAddr {
4947
for addr, usedby := range r.connFor {
5048
if !usedby.Used && addr != excluding {
5149
return addr
@@ -55,15 +53,15 @@ func (r Region) GetUnusedIP(excluding *net.TCPAddr) *net.TCPAddr {
5553
}
5654

5755
// Use the address, assigning it to a proxy connection.
58-
func (r Region) Use(addr *net.TCPAddr, connID int) {
56+
func (r Region) Use(addr *EdgeAddr, connID int) {
5957
if addr == nil {
6058
return
6159
}
6260
r.connFor[addr] = InUse(connID)
6361
}
6462

6563
// GetAnyAddress returns an arbitrary address from the region.
66-
func (r Region) GetAnyAddress() *net.TCPAddr {
64+
func (r Region) GetAnyAddress() *EdgeAddr {
6765
for addr := range r.connFor {
6866
return addr
6967
}
@@ -72,7 +70,7 @@ func (r Region) GetAnyAddress() *net.TCPAddr {
7270

7371
// GiveBack the address, ensuring it is no longer assigned to an IP.
7472
// Returns true if the address is in this region.
75-
func (r Region) GiveBack(addr *net.TCPAddr) (ok bool) {
73+
func (r Region) GiveBack(addr *EdgeAddr) (ok bool) {
7674
if _, ok := r.connFor[addr]; !ok {
7775
return false
7876
}

0 commit comments

Comments
 (0)