Skip to content

Commit 23b7697

Browse files
Merge pull request #20475 from pravisankar/egress-dns-router-backend-ha
Egress DNS proxy router: Allow load distribution when domain resolves to multiple IP addrs
2 parents c4d30d2 + 69c3274 commit 23b7697

File tree

2 files changed

+123
-9
lines changed

2 files changed

+123
-9
lines changed

images/egress/dns-proxy/egress-dns-proxy.sh

+46-5
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,9 @@ IPADDR_REGEX="[[:digit:]]+\.[[:digit:]]+\.[[:digit:]]+\.[[:digit:]]+"
1515
PORT_REGEX="[[:digit:]]+"
1616
DOMAINNAME_REGEX="[[:alnum:]][[:alnum:]-]+?\.[[:alnum:].-]+"
1717

18+
# Fetch nameservers from /etc/resolv.conf
19+
declare -a NAMESERVERS=($(awk '/^nameserver/ {print $2}' /etc/resolv.conf))
20+
1821
function die() {
1922
echo "$*" 1>&2
2023
exit 1
@@ -64,11 +67,8 @@ defaults
6467
function generate_dns_resolvers() {
6568
echo "resolvers dns-resolver"
6669

67-
# Fetch nameservers from /etc/resolv.conf
68-
nameservers=()
69-
nameservers=$(awk '/^nameserver/ {print $2}' /etc/resolv.conf)
7070
n=0
71-
for ns in ${nameservers[@]}; do
71+
for ns in "${NAMESERVERS[@]}"; do
7272
n=$(($n + 1))
7373
echo " nameserver ns$n ${ns}:${NS_PORT}"
7474
done
@@ -80,12 +80,31 @@ function generate_dns_resolvers() {
8080
echo ""
8181
}
8282

83+
function get_num_servers() {
84+
local domain=$1
85+
86+
if [[ "${EGRESS_DNS_PROXY_MODE:-}" == "unit-test" ]]; then
87+
echo "${DNS_SERVERS[${domain}]:-1}"
88+
return
89+
fi
90+
91+
declare -A servers=()
92+
for ns in "${NAMESERVERS[@]}"; do
93+
local output=$( dig +noall +answer a "${domain}" @"${ns}" | awk '{ print $5 }' )
94+
for ip in $output; do
95+
servers[${ip}]=1
96+
done
97+
done
98+
echo "${#servers[@]}"
99+
}
100+
83101
function generate_haproxy_frontends_backends() {
84102
local n=0
85103
declare -A used_ports=()
86104

87105
while read dest; do
88106
local port target targetport resolvers
107+
local num_servers=1
89108

90109
if [[ "${dest}" =~ ^${BLANK_LINE_OR_COMMENT_REGEX}$ ]]; then
91110
continue
@@ -102,9 +121,11 @@ function generate_haproxy_frontends_backends() {
102121
read port target <<< "${dest}"
103122
targetport="${port}"
104123
resolvers="resolvers dns-resolver resolve-prefer ipv4"
124+
num_servers=$( get_num_servers "${target}" )
105125
elif [[ "${dest}" =~ ^${PORT_REGEX}\ +${DOMAINNAME_REGEX}\ +${PORT_REGEX}$ ]]; then
106126
read port target targetport <<< "${dest}"
107127
resolvers="resolvers dns-resolver resolve-prefer ipv4"
128+
num_servers=$( get_num_servers "${target}" )
108129
else
109130
die "Bad destination '${dest}'"
110131
fi
@@ -118,13 +139,20 @@ function generate_haproxy_frontends_backends() {
118139
die "Proxy port $port already used, must be unique for each destination"
119140
fi
120141

142+
local server_str=""
143+
if [[ "${num_servers}" -gt "1" ]]; then
144+
server_str="server-template dest ${num_servers}"
145+
else
146+
server_str="server dest1"
147+
fi
148+
121149
echo "
122150
frontend fe$n
123151
bind :${port}
124152
default_backend be$n
125153
126154
backend be$n
127-
server dest$n ${target}:${targetport} check $resolvers
155+
${server_str} ${target}:${targetport} check $resolvers
128156
"
129157
done <<< "${EGRESS_DNS_PROXY_DESTINATION}"
130158
}
@@ -170,6 +198,19 @@ function run() {
170198
}
171199

172200
if [[ "${EGRESS_DNS_PROXY_MODE:-}" == "unit-test" ]]; then
201+
202+
declare -A DNS_SERVERS=()
203+
if [[ "${EGRESS_DNS_SERVERS:-}" != "" ]]; then
204+
servers=(${EGRESS_DNS_SERVERS//;/ })
205+
for server in "${servers[@]}"; do
206+
si=(${server//:/ })
207+
if [[ "${#si[@]}" -ne "2" ]]; then
208+
die "Invalid server entry in EGRESS_DNS_SERVERS: ${server}"
209+
fi
210+
DNS_SERVERS[${si[0]}]=${si[1]}
211+
done
212+
fi
213+
173214
check_prereqs
174215
setup_haproxy_config
175216
exit 0

images/egress/dns-proxy/egress_dns_proxy_test.go

+77-4
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ func TestHAProxyFrontendBackendConf(t *testing.T) {
1313
dest string
1414
frontends []string
1515
backends []string
16+
dnsMap map[string]int
1617
}{
1718
// Single destination IP
1819
{
@@ -39,7 +40,7 @@ frontend fe2
3940
backend be1
4041
server dest1 11.12.13.14:80 check`, `
4142
backend be2
42-
server dest2 21.22.23.24:100 check`},
43+
server dest1 21.22.23.24:100 check`},
4344
},
4445
// Single destination domain name
4546
{
@@ -51,6 +52,9 @@ frontend fe1
5152
backends: []string{`
5253
backend be1
5354
server dest1 example.com:80 check resolvers dns-resolver`},
55+
dnsMap: map[string]int{
56+
"example.com": 1,
57+
},
5458
},
5559
// Multiple destination domain names
5660
{
@@ -66,7 +70,11 @@ frontend fe2
6670
backend be1
6771
server dest1 example.com:80 check resolvers dns-resolver`, `
6872
backend be2
69-
server dest2 foo.com:100 check resolvers dns-resolver`},
73+
server dest1 foo.com:100 check resolvers dns-resolver`},
74+
dnsMap: map[string]int{
75+
"example.com": 1,
76+
"foo.com": 1,
77+
},
7078
},
7179
// Destination IP and destination domain name
7280
{
@@ -82,7 +90,10 @@ frontend fe2
8290
backend be1
8391
server dest1 11.12.13.14:80 check`, `
8492
backend be2
85-
server dest2 example.com:100 check resolvers dns-resolver`},
93+
server dest1 example.com:100 check resolvers dns-resolver`},
94+
dnsMap: map[string]int{
95+
"example.com": 1,
96+
},
8697
},
8798
// Destination with comments and blank lines
8899
{
@@ -111,18 +122,80 @@ frontend fe2
111122
backend be1
112123
server dest1 11.12.13.14:80 check`, `
113124
backend be2
114-
server dest2 example.com:100 check resolvers dns-resolver`},
125+
server dest1 example.com:100 check resolvers dns-resolver`},
126+
dnsMap: map[string]int{
127+
"example.com": 1,
128+
},
129+
},
130+
// Destination domain name with multiple backends
131+
{
132+
dest: `
133+
# Port 8080 forwards to port 100 on example.com
134+
8080 example.com 100
135+
`,
136+
frontends: []string{`
137+
frontend fe1
138+
bind :8080
139+
default_backend be1`},
140+
backends: []string{`
141+
backend be1
142+
server-template dest 3 example.com:100 check resolvers dns-resolver`},
143+
dnsMap: map[string]int{
144+
"example.com": 3,
145+
},
146+
},
147+
// Destination IP and Destination domain name with single and multiple backends
148+
{
149+
dest: `
150+
80 11.12.13.14
151+
9000 foo.com 200
152+
8080 example.com 100
153+
8081 bar.com 100
154+
`,
155+
frontends: []string{`
156+
frontend fe1
157+
bind :80
158+
default_backend be1`, `
159+
frontend fe2
160+
bind :9000
161+
default_backend be2`, `
162+
frontend fe3
163+
bind :8080
164+
default_backend be3`, `
165+
frontend fe4
166+
bind :8081
167+
default_backend be4`},
168+
backends: []string{`
169+
backend be1
170+
server dest1 11.12.13.14:80 check`, `
171+
backend be2
172+
server-template dest 2 foo.com:200 check resolvers dns-resolver`, `
173+
backend be3
174+
server dest1 example.com:100 check resolvers dns-resolver`, `
175+
backend be4
176+
server dest1 bar.com:100 check resolvers dns-resolver`},
177+
dnsMap: map[string]int{
178+
"foo.com": 2,
179+
"example.com": 1,
180+
"bar.com": 1,
181+
},
115182
},
116183
}
117184

118185
frontendRegex := regexp.MustCompile("\nfrontend ")
119186
backendRegex := regexp.MustCompile("\nbackend ")
120187

121188
for n, test := range tests {
189+
servers := ""
190+
for domain, numServers := range test.dnsMap {
191+
servers += fmt.Sprintf("%s:%d;", domain, numServers)
192+
}
193+
122194
cmd := exec.Command("./egress-dns-proxy.sh")
123195
cmd.Env = []string{
124196
fmt.Sprintf("EGRESS_DNS_PROXY_DESTINATION=%s", test.dest),
125197
fmt.Sprintf("EGRESS_DNS_PROXY_MODE=unit-test"),
198+
fmt.Sprintf("EGRESS_DNS_SERVERS=%s", servers),
126199
}
127200
outBytes, err := cmd.CombinedOutput()
128201
if err != nil {

0 commit comments

Comments
 (0)