9 from dnsdisttests
import DNSDistTest
10 from proxyprotocol
import ProxyProtocol
12 # Python2/3 compatibility hacks
14 from queue
import Queue
16 from Queue
import Queue
18 def ProxyProtocolUDPResponder(port
, fromQueue
, toQueue
):
19 sock
= socket
.socket(socket
.AF_INET
, socket
.SOCK_DGRAM
)
20 sock
.setsockopt(socket
.SOL_SOCKET
, socket
.SO_REUSEPORT
, 1)
22 sock
.bind(("127.0.0.1", port
))
23 except socket
.error
as e
:
24 print("Error binding in the Proxy Protocol UDP responder: %s" % str(e
))
28 data
, addr
= sock
.recvfrom(4096)
30 proxy
= ProxyProtocol()
31 if len(data
) < proxy
.HEADER_SIZE
:
34 if not proxy
.parseHeader(data
):
38 # likely a healthcheck
39 data
= data
[proxy
.HEADER_SIZE
:]
40 request
= dns
.message
.from_wire(data
)
41 response
= dns
.message
.make_response(request
)
42 wire
= response
.to_wire()
44 sock
.sendto(wire
, addr
)
49 payload
= data
[:(proxy
.HEADER_SIZE
+ proxy
.contentLen
)]
50 dnsData
= data
[(proxy
.HEADER_SIZE
+ proxy
.contentLen
):]
51 toQueue
.put([payload
, dnsData
], True, 2.0)
52 # computing the correct ID for the response
53 request
= dns
.message
.from_wire(dnsData
)
54 response
= fromQueue
.get(True, 2.0)
55 response
.id = request
.id
58 sock
.sendto(response
.to_wire(), addr
)
63 def ProxyProtocolTCPResponder(port
, fromQueue
, toQueue
):
64 # be aware that this responder will not accept a new connection
65 # until the last one has been closed. This is done on purpose to
66 # to check for connection reuse, making sure that a lot of connections
67 # are not opened in parallel.
68 sock
= socket
.socket(socket
.AF_INET
, socket
.SOCK_STREAM
)
69 sock
.setsockopt(socket
.SOL_SOCKET
, socket
.SO_REUSEPORT
, 1)
70 sock
.setsockopt(socket
.IPPROTO_TCP
, socket
.TCP_NODELAY
, 1)
72 sock
.bind(("127.0.0.1", port
))
73 except socket
.error
as e
:
74 print("Error binding in the TCP responder: %s" % str(e
))
79 (conn
, _
) = sock
.accept()
81 # try to read the entire Proxy Protocol header
82 proxy
= ProxyProtocol()
83 header
= conn
.recv(proxy
.HEADER_SIZE
)
88 if not proxy
.parseHeader(header
):
92 proxyContent
= conn
.recv(proxy
.contentLen
)
97 payload
= header
+ proxyContent
101 except socket
.timeout
:
108 (datalen
,) = struct
.unpack("!H", data
)
109 data
= conn
.recv(datalen
)
111 toQueue
.put([payload
, data
], True, 2.0)
113 response
= fromQueue
.get(True, 2.0)
118 # computing the correct ID for the response
119 request
= dns
.message
.from_wire(data
)
120 response
.id = request
.id
122 wire
= response
.to_wire()
123 conn
.send(struct
.pack("!H", len(wire
)))
130 toProxyQueue
= Queue()
131 fromProxyQueue
= Queue()
132 proxyResponderPort
= 5470
134 udpResponder
= threading
.Thread(name
='UDP Proxy Protocol Responder', target
=ProxyProtocolUDPResponder
, args
=[proxyResponderPort
, toProxyQueue
, fromProxyQueue
])
135 udpResponder
.setDaemon(True)
137 tcpResponder
= threading
.Thread(name
='TCP Proxy Protocol Responder', target
=ProxyProtocolTCPResponder
, args
=[proxyResponderPort
, toProxyQueue
, fromProxyQueue
])
138 tcpResponder
.setDaemon(True)
141 class ProxyProtocolTest(DNSDistTest
):
142 _proxyResponderPort
= proxyResponderPort
143 _config_params
= ['_proxyResponderPort']
145 def checkMessageProxyProtocol(self
, receivedProxyPayload
, source
, destination
, isTCP
, values
=[], v6
=False, sourcePort
=None, destinationPort
=None):
146 proxy
= ProxyProtocol()
147 self
.assertTrue(proxy
.parseHeader(receivedProxyPayload
))
148 self
.assertEqual(proxy
.version
, 0x02)
149 self
.assertEqual(proxy
.command
, 0x01)
151 self
.assertEqual(proxy
.family
, 0x02)
153 self
.assertEqual(proxy
.family
, 0x01)
155 self
.assertEqual(proxy
.protocol
, 0x02)
157 self
.assertEqual(proxy
.protocol
, 0x01)
158 self
.assertGreater(proxy
.contentLen
, 0)
160 self
.assertTrue(proxy
.parseAddressesAndPorts(receivedProxyPayload
))
161 self
.assertEqual(proxy
.source
, source
)
162 self
.assertEqual(proxy
.destination
, destination
)
164 self
.assertEqual(proxy
.sourcePort
, sourcePort
)
166 self
.assertEqual(proxy
.destinationPort
, destinationPort
)
168 self
.assertEqual(proxy
.destinationPort
, self
._dnsDistPort
)
170 self
.assertTrue(proxy
.parseAdditionalValues(receivedProxyPayload
))
173 self
.assertEqual(proxy
.values
, values
)
175 class TestProxyProtocol(ProxyProtocolTest
):
177 dnsdist is configured to prepend a Proxy Protocol header to the query
180 _config_template
= """
181 newServer{address="127.0.0.1:%d", useProxyProtocol=true}
183 function addValues(dq)
184 local values = { [0]="foo", [42]="bar" }
185 dq:setProxyProtocolValues(values)
186 return DNSAction.None
189 addAction("values-lua.proxy.tests.powerdns.com.", LuaAction(addValues))
190 addAction("values-action.proxy.tests.powerdns.com.", SetProxyProtocolValuesAction({ ["1"]="dnsdist", ["255"]="proxy-protocol"}))
192 _config_params
= ['_proxyResponderPort']
194 def testProxyUDP(self
):
196 Proxy Protocol: no value (UDP)
198 name
= 'simple-udp.proxy.tests.powerdns.com.'
199 query
= dns
.message
.make_query(name
, 'A', 'IN')
200 response
= dns
.message
.make_response(query
)
202 toProxyQueue
.put(response
, True, 2.0)
204 data
= query
.to_wire()
205 self
._sock
.send(data
)
206 receivedResponse
= None
208 self
._sock
.settimeout(2.0)
209 data
= self
._sock
.recv(4096)
210 except socket
.timeout
:
214 receivedResponse
= dns
.message
.from_wire(data
)
216 (receivedProxyPayload
, receivedDNSData
) = fromProxyQueue
.get(True, 2.0)
217 self
.assertTrue(receivedProxyPayload
)
218 self
.assertTrue(receivedDNSData
)
219 self
.assertTrue(receivedResponse
)
221 receivedQuery
= dns
.message
.from_wire(receivedDNSData
)
222 receivedQuery
.id = query
.id
223 receivedResponse
.id = response
.id
224 self
.assertEqual(receivedQuery
, query
)
225 self
.assertEqual(receivedResponse
, response
)
226 self
.checkMessageProxyProtocol(receivedProxyPayload
, '127.0.0.1', '127.0.0.1', False)
228 def testProxyTCP(self
):
230 Proxy Protocol: no value (TCP)
232 name
= 'simple-tcp.proxy.tests.powerdns.com.'
233 query
= dns
.message
.make_query(name
, 'A', 'IN')
234 response
= dns
.message
.make_response(query
)
236 toProxyQueue
.put(response
, True, 2.0)
238 conn
= self
.openTCPConnection(2.0)
239 data
= query
.to_wire()
240 self
.sendTCPQueryOverConnection(conn
, data
, rawQuery
=True)
241 receivedResponse
= None
243 receivedResponse
= self
.recvTCPResponseOverConnection(conn
)
244 except socket
.timeout
:
247 (receivedProxyPayload
, receivedDNSData
) = fromProxyQueue
.get(True, 2.0)
248 self
.assertTrue(receivedProxyPayload
)
249 self
.assertTrue(receivedDNSData
)
250 self
.assertTrue(receivedResponse
)
252 receivedQuery
= dns
.message
.from_wire(receivedDNSData
)
253 receivedQuery
.id = query
.id
254 receivedResponse
.id = response
.id
255 self
.assertEqual(receivedQuery
, query
)
256 self
.assertEqual(receivedResponse
, response
)
257 self
.checkMessageProxyProtocol(receivedProxyPayload
, '127.0.0.1', '127.0.0.1', True)
259 def testProxyUDPWithValuesFromLua(self
):
261 Proxy Protocol: values from Lua (UDP)
263 name
= 'values-lua.proxy.tests.powerdns.com.'
264 query
= dns
.message
.make_query(name
, 'A', 'IN')
265 response
= dns
.message
.make_response(query
)
267 toProxyQueue
.put(response
, True, 2.0)
269 data
= query
.to_wire()
270 self
._sock
.send(data
)
271 receivedResponse
= None
273 self
._sock
.settimeout(2.0)
274 data
= self
._sock
.recv(4096)
275 except socket
.timeout
:
279 receivedResponse
= dns
.message
.from_wire(data
)
281 (receivedProxyPayload
, receivedDNSData
) = fromProxyQueue
.get(True, 2.0)
282 self
.assertTrue(receivedProxyPayload
)
283 self
.assertTrue(receivedDNSData
)
284 self
.assertTrue(receivedResponse
)
286 receivedQuery
= dns
.message
.from_wire(receivedDNSData
)
287 receivedQuery
.id = query
.id
288 receivedResponse
.id = response
.id
289 self
.assertEqual(receivedQuery
, query
)
290 self
.assertEqual(receivedResponse
, response
)
291 self
.checkMessageProxyProtocol(receivedProxyPayload
, '127.0.0.1', '127.0.0.1', False, [ [0, b
'foo'] , [ 42, b
'bar'] ])
293 def testProxyTCPWithValuesFromLua(self
):
295 Proxy Protocol: values from Lua (TCP)
297 name
= 'values-lua.proxy.tests.powerdns.com.'
298 query
= dns
.message
.make_query(name
, 'A', 'IN')
299 response
= dns
.message
.make_response(query
)
301 toProxyQueue
.put(response
, True, 2.0)
303 conn
= self
.openTCPConnection(2.0)
304 data
= query
.to_wire()
305 self
.sendTCPQueryOverConnection(conn
, data
, rawQuery
=True)
306 receivedResponse
= None
308 receivedResponse
= self
.recvTCPResponseOverConnection(conn
)
309 except socket
.timeout
:
312 (receivedProxyPayload
, receivedDNSData
) = fromProxyQueue
.get(True, 2.0)
313 self
.assertTrue(receivedProxyPayload
)
314 self
.assertTrue(receivedDNSData
)
315 self
.assertTrue(receivedResponse
)
317 receivedQuery
= dns
.message
.from_wire(receivedDNSData
)
318 receivedQuery
.id = query
.id
319 receivedResponse
.id = response
.id
320 self
.assertEqual(receivedQuery
, query
)
321 self
.assertEqual(receivedResponse
, response
)
322 self
.checkMessageProxyProtocol(receivedProxyPayload
, '127.0.0.1', '127.0.0.1', True, [ [0, b
'foo'] , [ 42, b
'bar'] ])
324 def testProxyUDPWithValuesFromAction(self
):
326 Proxy Protocol: values from Action (UDP)
328 name
= 'values-action.proxy.tests.powerdns.com.'
329 query
= dns
.message
.make_query(name
, 'A', 'IN')
330 response
= dns
.message
.make_response(query
)
332 toProxyQueue
.put(response
, True, 2.0)
334 data
= query
.to_wire()
335 self
._sock
.send(data
)
336 receivedResponse
= None
338 self
._sock
.settimeout(2.0)
339 data
= self
._sock
.recv(4096)
340 except socket
.timeout
:
344 receivedResponse
= dns
.message
.from_wire(data
)
346 (receivedProxyPayload
, receivedDNSData
) = fromProxyQueue
.get(True, 2.0)
347 self
.assertTrue(receivedProxyPayload
)
348 self
.assertTrue(receivedDNSData
)
349 self
.assertTrue(receivedResponse
)
351 receivedQuery
= dns
.message
.from_wire(receivedDNSData
)
352 receivedQuery
.id = query
.id
353 receivedResponse
.id = response
.id
354 self
.assertEqual(receivedQuery
, query
)
355 self
.assertEqual(receivedResponse
, response
)
356 self
.checkMessageProxyProtocol(receivedProxyPayload
, '127.0.0.1', '127.0.0.1', False, [ [1, b
'dnsdist'] , [ 255, b
'proxy-protocol'] ])
358 def testProxyTCPWithValuesFromAction(self
):
360 Proxy Protocol: values from Action (TCP)
362 name
= 'values-action.proxy.tests.powerdns.com.'
363 query
= dns
.message
.make_query(name
, 'A', 'IN')
364 response
= dns
.message
.make_response(query
)
366 toProxyQueue
.put(response
, True, 2.0)
368 conn
= self
.openTCPConnection(2.0)
369 data
= query
.to_wire()
370 self
.sendTCPQueryOverConnection(conn
, data
, rawQuery
=True)
371 receivedResponse
= None
373 receivedResponse
= self
.recvTCPResponseOverConnection(conn
)
374 except socket
.timeout
:
377 (receivedProxyPayload
, receivedDNSData
) = fromProxyQueue
.get(True, 2.0)
378 self
.assertTrue(receivedProxyPayload
)
379 self
.assertTrue(receivedDNSData
)
380 self
.assertTrue(receivedResponse
)
382 receivedQuery
= dns
.message
.from_wire(receivedDNSData
)
383 receivedQuery
.id = query
.id
384 receivedResponse
.id = response
.id
385 self
.assertEqual(receivedQuery
, query
)
386 self
.assertEqual(receivedResponse
, response
)
387 self
.checkMessageProxyProtocol(receivedProxyPayload
, '127.0.0.1', '127.0.0.1', True, [ [1, b
'dnsdist'] , [ 255, b
'proxy-protocol'] ])
389 def testProxyTCPSeveralQueriesOnSameConnection(self
):
391 Proxy Protocol: Several queries on the same TCP connection
393 name
= 'several-queries-same-conn.proxy.tests.powerdns.com.'
394 query
= dns
.message
.make_query(name
, 'A', 'IN')
395 response
= dns
.message
.make_response(query
)
397 conn
= self
.openTCPConnection(2.0)
398 data
= query
.to_wire()
400 for idx
in range(10):
401 toProxyQueue
.put(response
, True, 2.0)
402 self
.sendTCPQueryOverConnection(conn
, data
, rawQuery
=True)
403 receivedResponse
= None
405 receivedResponse
= self
.recvTCPResponseOverConnection(conn
)
406 except socket
.timeout
:
409 (receivedProxyPayload
, receivedDNSData
) = fromProxyQueue
.get(True, 2.0)
410 self
.assertTrue(receivedProxyPayload
)
411 self
.assertTrue(receivedDNSData
)
412 self
.assertTrue(receivedResponse
)
414 receivedQuery
= dns
.message
.from_wire(receivedDNSData
)
415 receivedQuery
.id = query
.id
416 receivedResponse
.id = response
.id
417 self
.assertEqual(receivedQuery
, query
)
418 self
.assertEqual(receivedResponse
, response
)
419 self
.checkMessageProxyProtocol(receivedProxyPayload
, '127.0.0.1', '127.0.0.1', True, [])
421 class TestProxyProtocolIncoming(ProxyProtocolTest
):
423 dnsdist is configured to prepend a Proxy Protocol header to the query and expect one on incoming queries
426 _config_template
= """
427 setProxyProtocolACL( { "127.0.0.1/32" } )
428 newServer{address="127.0.0.1:%d", useProxyProtocol=true}
430 function addValues(dq)
431 dq:addProxyProtocolValue(0, 'foo')
432 dq:addProxyProtocolValue(42, 'bar')
433 return DNSAction.None
436 -- refuse queries with no TLV value type 2
437 addAction(NotRule(ProxyProtocolValueRule(2)), RCodeAction(DNSRCode.REFUSED))
438 -- or with a TLV value type 3 different from "proxy"
439 addAction(NotRule(ProxyProtocolValueRule(3, "proxy")), RCodeAction(DNSRCode.REFUSED))
441 function answerBasedOnForwardedDest(dq)
442 local port = dq.localaddr:getPort()
443 local dest = dq.localaddr:toString()
444 return DNSAction.Spoof, "address-was-"..dest.."-port-was-"..port..".proxy-protocol-incoming.tests.powerdns.com."
446 addAction("get-forwarded-dest.proxy-protocol-incoming.tests.powerdns.com.", LuaAction(answerBasedOnForwardedDest))
448 function answerBasedOnForwardedSrc(dq)
449 local port = dq.remoteaddr:getPort()
450 local src = dq.remoteaddr:toString()
451 return DNSAction.Spoof, "address-was-"..src.."-port-was-"..port..".proxy-protocol-incoming.tests.powerdns.com."
453 addAction("get-forwarded-src.proxy-protocol-incoming.tests.powerdns.com.", LuaAction(answerBasedOnForwardedSrc))
455 -- add these values for all queries
456 addAction("proxy-protocol-incoming.tests.powerdns.com.", LuaAction(addValues))
457 addAction("proxy-protocol-incoming.tests.powerdns.com.", SetAdditionalProxyProtocolValueAction(1, "dnsdist"))
458 addAction("proxy-protocol-incoming.tests.powerdns.com.", SetAdditionalProxyProtocolValueAction(255, "proxy-protocol"))
460 -- override all existing values
461 addAction("override.proxy-protocol-incoming.tests.powerdns.com.", SetProxyProtocolValuesAction({["50"]="overridden"}))
463 _config_params
= ['_proxyResponderPort']
466 def testNoHeader(self
):
468 Incoming Proxy Protocol: no header
470 # no proxy protocol header while one is expected, should be dropped
471 name
= 'no-header.incoming-proxy-protocol.tests.powerdns.com.'
472 query
= dns
.message
.make_query(name
, 'A', 'IN')
474 for method
in ("sendUDPQuery", "sendTCPQuery"):
475 sender
= getattr(self
, method
)
476 (_
, receivedResponse
) = sender(query
, response
=None)
477 self
.assertEqual(receivedResponse
, None)
479 def testIncomingProxyDest(self
):
481 Incoming Proxy Protocol: values from Lua
483 name
= 'get-forwarded-dest.proxy-protocol-incoming.tests.powerdns.com.'
484 query
= dns
.message
.make_query(name
, 'A', 'IN')
485 # dnsdist set RA = RD for spoofed responses
486 query
.flags
&= ~dns
.flags
.RD
488 destAddr
= "2001:db8::9"
490 srcAddr
= "2001:db8::8"
492 response
= dns
.message
.make_response(query
)
493 rrset
= dns
.rrset
.from_text(name
,
497 "address-was-{}-port-was-{}.proxy-protocol-incoming.tests.powerdns.com.".format(destAddr
, destPort
, self
._dnsDistPort
))
498 response
.answer
.append(rrset
)
500 udpPayload
= ProxyProtocol
.getPayload(False, False, True, srcAddr
, destAddr
, srcPort
, destPort
, [ [ 2, b
'foo'], [ 3, b
'proxy'] ])
501 (_
, receivedResponse
) = self
.sendUDPQuery(udpPayload
+ query
.to_wire(), response
=None, useQueue
=False, rawQuery
=True)
502 self
.assertEqual(receivedResponse
, response
)
504 tcpPayload
= ProxyProtocol
.getPayload(False, True, True, srcAddr
, destAddr
, srcPort
, destPort
, [ [ 2, b
'foo'], [ 3, b
'proxy'] ])
505 wire
= query
.to_wire()
507 receivedResponse
= None
509 conn
= self
.openTCPConnection(2.0)
510 conn
.send(tcpPayload
)
511 conn
.send(struct
.pack("!H", len(wire
)))
513 receivedResponse
= self
.recvTCPResponseOverConnection(conn
)
514 except socket
.timeout
:
516 self
.assertEqual(receivedResponse
, response
)
518 def testProxyUDPWithValuesFromLua(self
):
520 Incoming Proxy Protocol: values from Lua (UDP)
522 name
= 'values-lua.proxy-protocol-incoming.tests.powerdns.com.'
523 query
= dns
.message
.make_query(name
, 'A', 'IN')
524 response
= dns
.message
.make_response(query
)
526 destAddr
= "2001:db8::9"
528 srcAddr
= "2001:db8::8"
530 response
= dns
.message
.make_response(query
)
532 udpPayload
= ProxyProtocol
.getPayload(False, False, True, srcAddr
, destAddr
, srcPort
, destPort
, [ [ 2, b
'foo'], [ 3, b
'proxy'] ])
533 toProxyQueue
.put(response
, True, 2.0)
534 (_
, receivedResponse
) = self
.sendUDPQuery(udpPayload
+ query
.to_wire(), response
=None, useQueue
=False, rawQuery
=True)
536 (receivedProxyPayload
, receivedDNSData
) = fromProxyQueue
.get(True, 2.0)
537 self
.assertTrue(receivedProxyPayload
)
538 self
.assertTrue(receivedDNSData
)
539 self
.assertTrue(receivedResponse
)
541 receivedQuery
= dns
.message
.from_wire(receivedDNSData
)
542 receivedQuery
.id = query
.id
543 receivedResponse
.id = response
.id
544 self
.assertEqual(receivedQuery
, query
)
545 self
.assertEqual(receivedResponse
, response
)
546 self
.checkMessageProxyProtocol(receivedProxyPayload
, srcAddr
, destAddr
, False, [ [0, b
'foo'], [1, b
'dnsdist'], [ 2, b
'foo'], [3, b
'proxy'], [ 42, b
'bar'], [255, b
'proxy-protocol'] ], True, srcPort
, destPort
)
548 def testProxyTCPWithValuesFromLua(self
):
550 Incoming Proxy Protocol: values from Lua (TCP)
552 name
= 'values-lua.proxy-protocol-incoming.tests.powerdns.com.'
553 query
= dns
.message
.make_query(name
, 'A', 'IN')
554 response
= dns
.message
.make_response(query
)
556 destAddr
= "2001:db8::9"
558 srcAddr
= "2001:db8::8"
560 response
= dns
.message
.make_response(query
)
562 tcpPayload
= ProxyProtocol
.getPayload(False, True, True, srcAddr
, destAddr
, srcPort
, destPort
, [ [ 2, b
'foo'], [ 3, b
'proxy'] ])
564 toProxyQueue
.put(response
, True, 2.0)
566 wire
= query
.to_wire()
568 receivedResponse
= None
570 conn
= self
.openTCPConnection(2.0)
571 conn
.send(tcpPayload
)
572 conn
.send(struct
.pack("!H", len(wire
)))
574 receivedResponse
= self
.recvTCPResponseOverConnection(conn
)
575 except socket
.timeout
:
577 self
.assertEqual(receivedResponse
, response
)
579 (receivedProxyPayload
, receivedDNSData
) = fromProxyQueue
.get(True, 2.0)
580 self
.assertTrue(receivedProxyPayload
)
581 self
.assertTrue(receivedDNSData
)
582 self
.assertTrue(receivedResponse
)
584 receivedQuery
= dns
.message
.from_wire(receivedDNSData
)
585 receivedQuery
.id = query
.id
586 receivedResponse
.id = response
.id
587 self
.assertEqual(receivedQuery
, query
)
588 self
.assertEqual(receivedResponse
, response
)
589 self
.checkMessageProxyProtocol(receivedProxyPayload
, srcAddr
, destAddr
, True, [ [0, b
'foo'], [1, b
'dnsdist'], [ 2, b
'foo'], [3, b
'proxy'], [ 42, b
'bar'], [255, b
'proxy-protocol'] ], True, srcPort
, destPort
)
591 def testProxyUDPWithValueOverride(self
):
593 Incoming Proxy Protocol: override existing value (UDP)
595 name
= 'override.proxy-protocol-incoming.tests.powerdns.com.'
596 query
= dns
.message
.make_query(name
, 'A', 'IN')
597 response
= dns
.message
.make_response(query
)
599 destAddr
= "2001:db8::9"
601 srcAddr
= "2001:db8::8"
603 response
= dns
.message
.make_response(query
)
605 udpPayload
= ProxyProtocol
.getPayload(False, False, True, srcAddr
, destAddr
, srcPort
, destPort
, [ [2, b
'foo'], [3, b
'proxy'], [ 50, b
'initial-value']])
606 toProxyQueue
.put(response
, True, 2.0)
607 (_
, receivedResponse
) = self
.sendUDPQuery(udpPayload
+ query
.to_wire(), response
=None, useQueue
=False, rawQuery
=True)
609 (receivedProxyPayload
, receivedDNSData
) = fromProxyQueue
.get(True, 2.0)
610 self
.assertTrue(receivedProxyPayload
)
611 self
.assertTrue(receivedDNSData
)
612 self
.assertTrue(receivedResponse
)
614 receivedQuery
= dns
.message
.from_wire(receivedDNSData
)
615 receivedQuery
.id = query
.id
616 receivedResponse
.id = response
.id
617 self
.assertEqual(receivedQuery
, query
)
618 self
.assertEqual(receivedResponse
, response
)
619 self
.checkMessageProxyProtocol(receivedProxyPayload
, srcAddr
, destAddr
, False, [ [50, b
'overridden'] ], True, srcPort
, destPort
)
621 def testProxyTCPSeveralQueriesOverConnection(self
):
623 Incoming Proxy Protocol: Several queries over the same connection (TCP)
625 name
= 'several-queries.proxy-protocol-incoming.tests.powerdns.com.'
626 query
= dns
.message
.make_query(name
, 'A', 'IN')
627 response
= dns
.message
.make_response(query
)
629 destAddr
= "2001:db8::9"
631 srcAddr
= "2001:db8::8"
633 response
= dns
.message
.make_response(query
)
635 tcpPayload
= ProxyProtocol
.getPayload(False, True, True, srcAddr
, destAddr
, srcPort
, destPort
, [ [ 2, b
'foo'], [ 3, b
'proxy'] ])
637 toProxyQueue
.put(response
, True, 2.0)
639 wire
= query
.to_wire()
641 receivedResponse
= None
642 conn
= self
.openTCPConnection(2.0)
644 conn
.send(tcpPayload
)
645 conn
.send(struct
.pack("!H", len(wire
)))
647 receivedResponse
= self
.recvTCPResponseOverConnection(conn
)
648 except socket
.timeout
:
650 self
.assertEqual(receivedResponse
, response
)
652 (receivedProxyPayload
, receivedDNSData
) = fromProxyQueue
.get(True, 2.0)
653 self
.assertTrue(receivedProxyPayload
)
654 self
.assertTrue(receivedDNSData
)
655 self
.assertTrue(receivedResponse
)
657 receivedQuery
= dns
.message
.from_wire(receivedDNSData
)
658 receivedQuery
.id = query
.id
659 receivedResponse
.id = response
.id
660 self
.assertEqual(receivedQuery
, query
)
661 self
.assertEqual(receivedResponse
, response
)
662 self
.checkMessageProxyProtocol(receivedProxyPayload
, srcAddr
, destAddr
, True, [ [0, b
'foo'], [1, b
'dnsdist'], [ 2, b
'foo'], [3, b
'proxy'], [ 42, b
'bar'], [255, b
'proxy-protocol'] ], True, srcPort
, destPort
)
665 receivedResponse
= None
666 toProxyQueue
.put(response
, True, 2.0)
668 conn
.send(struct
.pack("!H", len(wire
)))
670 receivedResponse
= self
.recvTCPResponseOverConnection(conn
)
671 except socket
.timeout
:
674 self
.assertEqual(receivedResponse
, response
)
676 (receivedProxyPayload
, receivedDNSData
) = fromProxyQueue
.get(True, 2.0)
677 self
.assertTrue(receivedProxyPayload
)
678 self
.assertTrue(receivedDNSData
)
679 self
.assertTrue(receivedResponse
)
681 receivedQuery
= dns
.message
.from_wire(receivedDNSData
)
682 receivedQuery
.id = query
.id
683 receivedResponse
.id = response
.id
684 self
.assertEqual(receivedQuery
, query
)
685 self
.assertEqual(receivedResponse
, response
)
686 self
.checkMessageProxyProtocol(receivedProxyPayload
, srcAddr
, destAddr
, True, [ [0, b
'foo'], [1, b
'dnsdist'], [ 2, b
'foo'], [3, b
'proxy'], [ 42, b
'bar'], [255, b
'proxy-protocol'] ], True, srcPort
, destPort
)
688 class TestProxyProtocolNotExpected(DNSDistTest
):
690 dnsdist is configured to expect a Proxy Protocol header on incoming queries but not from 127.0.0.1
693 _config_template
= """
694 setProxyProtocolACL( { "192.0.2.1/32" } )
695 newServer{address="127.0.0.1:%d"}
697 # NORMAL responder, does not expect a proxy protocol payload!
698 _config_params
= ['_testServerPort']
701 def testNoHeader(self
):
703 Unexpected Proxy Protocol: no header
705 # no proxy protocol header and none is expected from this source, should be passed on
706 name
= 'no-header.unexpected-proxy-protocol.tests.powerdns.com.'
707 query
= dns
.message
.make_query(name
, 'A', 'IN')
708 response
= dns
.message
.make_response(query
)
709 rrset
= dns
.rrset
.from_text(name
,
715 response
.answer
.append(rrset
)
717 for method
in ("sendUDPQuery", "sendTCPQuery"):
718 sender
= getattr(self
, method
)
719 (receivedQuery
, receivedResponse
) = sender(query
, response
)
720 receivedQuery
.id = query
.id
721 self
.assertEqual(query
, receivedQuery
)
722 self
.assertEqual(response
, receivedResponse
)
724 def testIncomingProxyDest(self
):
726 Unexpected Proxy Protocol: should be dropped
728 name
= 'with-proxy-payload.unexpected-protocol-incoming.tests.powerdns.com.'
729 query
= dns
.message
.make_query(name
, 'A', 'IN')
731 # Make sure that the proxy payload does NOT turn into a legal qname
732 destAddr
= "ff:db8::ffff"
734 srcAddr
= "ff:db8::ffff"
737 udpPayload
= ProxyProtocol
.getPayload(False, False, True, srcAddr
, destAddr
, srcPort
, destPort
, [ [ 2, b
'foo'], [ 3, b
'proxy'] ])
738 (_
, receivedResponse
) = self
.sendUDPQuery(udpPayload
+ query
.to_wire(), response
=None, useQueue
=False, rawQuery
=True)
739 self
.assertEqual(receivedResponse
, None)
741 tcpPayload
= ProxyProtocol
.getPayload(False, True, True, srcAddr
, destAddr
, srcPort
, destPort
, [ [ 2, b
'foo'], [ 3, b
'proxy'] ])
742 wire
= query
.to_wire()
744 receivedResponse
= None
746 conn
= self
.openTCPConnection(2.0)
747 conn
.send(tcpPayload
)
748 conn
.send(struct
.pack("!H", len(wire
)))
750 receivedResponse
= self
.recvTCPResponseOverConnection(conn
)
751 except socket
.timeout
:
753 self
.assertEqual(receivedResponse
, None)