]>
Commit | Line | Data |
---|---|---|
8d22a19d RG |
1 | #!/usr/bin/env python |
2 | import copy | |
3 | import dns | |
4 | import socket | |
5 | import struct | |
6 | import sys | |
7 | ||
8 | from proxyprotocol import ProxyProtocol | |
9 | ||
10 | def ProxyProtocolUDPResponder(port, fromQueue, toQueue): | |
11 | sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) | |
12 | sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEPORT, 1) | |
13 | try: | |
14 | sock.bind(("127.0.0.1", port)) | |
15 | except socket.error as e: | |
16 | print("Error binding in the Proxy Protocol UDP responder: %s" % str(e)) | |
17 | sys.exit(1) | |
18 | ||
19 | while True: | |
20 | data, addr = sock.recvfrom(4096) | |
21 | ||
22 | proxy = ProxyProtocol() | |
23 | if len(data) < proxy.HEADER_SIZE: | |
24 | continue | |
25 | ||
26 | if not proxy.parseHeader(data): | |
27 | continue | |
28 | ||
29 | if proxy.local: | |
30 | # likely a healthcheck | |
31 | data = data[proxy.HEADER_SIZE:] | |
32 | request = dns.message.from_wire(data) | |
33 | response = dns.message.make_response(request) | |
34 | wire = response.to_wire() | |
35 | sock.settimeout(2.0) | |
36 | sock.sendto(wire, addr) | |
37 | sock.settimeout(None) | |
38 | ||
39 | continue | |
40 | ||
41 | payload = data[:(proxy.HEADER_SIZE + proxy.contentLen)] | |
42 | dnsData = data[(proxy.HEADER_SIZE + proxy.contentLen):] | |
43 | toQueue.put([payload, dnsData], True, 2.0) | |
44 | # computing the correct ID for the response | |
45 | request = dns.message.from_wire(dnsData) | |
46 | response = fromQueue.get(True, 2.0) | |
47 | response.id = request.id | |
48 | ||
49 | sock.settimeout(2.0) | |
50 | sock.sendto(response.to_wire(), addr) | |
51 | sock.settimeout(None) | |
52 | ||
53 | sock.close() | |
54 | ||
55 | def ProxyProtocolTCPResponder(port, fromQueue, toQueue): | |
56 | # be aware that this responder will not accept a new connection | |
57 | # until the last one has been closed. This is done on purpose to | |
58 | # to check for connection reuse, making sure that a lot of connections | |
59 | # are not opened in parallel. | |
60 | sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) | |
61 | sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEPORT, 1) | |
62 | sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1) | |
63 | try: | |
64 | sock.bind(("127.0.0.1", port)) | |
65 | except socket.error as e: | |
66 | print("Error binding in the TCP responder: %s" % str(e)) | |
67 | sys.exit(1) | |
68 | ||
69 | sock.listen(100) | |
70 | while True: | |
71 | (conn, _) = sock.accept() | |
72 | conn.settimeout(5.0) | |
73 | # try to read the entire Proxy Protocol header | |
74 | proxy = ProxyProtocol() | |
75 | header = conn.recv(proxy.HEADER_SIZE) | |
76 | if not header: | |
77 | conn.close() | |
78 | continue | |
79 | ||
80 | if not proxy.parseHeader(header): | |
81 | conn.close() | |
82 | continue | |
83 | ||
84 | proxyContent = conn.recv(proxy.contentLen) | |
85 | if not proxyContent: | |
86 | conn.close() | |
87 | continue | |
88 | ||
89 | payload = header + proxyContent | |
90 | while True: | |
91 | try: | |
92 | data = conn.recv(2) | |
93 | except socket.timeout: | |
94 | data = None | |
95 | ||
96 | if not data: | |
97 | conn.close() | |
98 | break | |
99 | ||
100 | (datalen,) = struct.unpack("!H", data) | |
101 | data = conn.recv(datalen) | |
102 | ||
103 | toQueue.put([payload, data], True, 2.0) | |
104 | ||
105 | response = copy.deepcopy(fromQueue.get(True, 2.0)) | |
106 | if not response: | |
107 | conn.close() | |
108 | break | |
109 | ||
110 | # computing the correct ID for the response | |
111 | request = dns.message.from_wire(data) | |
112 | response.id = request.id | |
113 | ||
114 | wire = response.to_wire() | |
115 | conn.send(struct.pack("!H", len(wire))) | |
116 | conn.send(wire) | |
117 | ||
118 | conn.close() | |
119 | ||
120 | sock.close() |