Merge lp:~ptman/hipl/reload into lp:hipl

Proposed by Paul Tötterman
Status: Merged
Merged at revision: 6429
Proposed branch: lp:~ptman/hipl/reload
Merge into: lp:hipl
Diff against target: 394 lines (+85/-73)
6 files modified
debian/hipl-dnsproxy.install.in (+1/-0)
debian/resolvconf/hipdnsproxy (+2/-0)
tools/hipdnsproxy/DNS/Type.py (+1/-0)
tools/hipdnsproxy/dnsproxy.py (+43/-37)
tools/hipdnsproxy/resolvconf.py (+20/-10)
tools/hipdnsproxy/util.py (+18/-26)
To merge this branch: bzr merge lp:~ptman/hipl/reload
Reviewer Review Type Date Requested Status
Miika Komu Approve
Review via email: mp+178932@code.launchpad.net

Description of the change

Implement sane SIGHUP handling (reload configs)

Fixes #1132042 and #1189371

To post a comment you must log in.
Revision history for this message
Miika Komu (miika-iki) wrote :

Tested, works. There's still some IOerror left (I'll report this separately), but I think you could fix it directly in the trunk.

review: Approve
lp:~ptman/hipl/reload updated
6425. By Paul Tötterman

Retry in case of EINTR

6426. By Paul Tötterman

Merge trunk

6427. By Paul Tötterman

Merged trunk

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'debian/hipl-dnsproxy.install.in'
2--- debian/hipl-dnsproxy.install.in 2011-02-08 17:55:52 +0000
3+++ debian/hipl-dnsproxy.install.in 2013-08-12 13:20:15 +0000
4@@ -3,3 +3,4 @@
5 debian/tmp/@pythondir@/DNS @pythondir@
6 debian/tmp/@pythondir@/hipdnskeyparse @pythondir@
7 debian/tmp/@pythondir@/hipdnsproxy @pythondir@
8+debian/resolvconf/hipdnsproxy etc/resolvconf/update.d
9
10=== added directory 'debian/resolvconf'
11=== added file 'debian/resolvconf/hipdnsproxy'
12--- debian/resolvconf/hipdnsproxy 1970-01-01 00:00:00 +0000
13+++ debian/resolvconf/hipdnsproxy 2013-08-12 13:20:15 +0000
14@@ -0,0 +1,2 @@
15+#!/bin/sh
16+/bin/kill -HUP `/usr/bin/head -1 /var/run/hipdnsproxy.pid` > /dev/null 2>&1
17
18=== modified file 'tools/hipdnsproxy/DNS/Type.py'
19--- tools/hipdnsproxy/DNS/Type.py 2010-02-18 16:45:11 +0000
20+++ tools/hipdnsproxy/DNS/Type.py 2013-08-12 13:20:15 +0000
21@@ -28,6 +28,7 @@
22 TXT = 16 # text strings
23 AAAA = 28 # IPv6 AAAA records (RFC 1886)
24 SRV = 33 # DNS RR for specifying the location of services (RFC 2782)
25+HIP = 55 # Host Identity Protocol (RFC 5205)
26
27
28 # Additional TYPE values from host.c source
29
30=== modified file 'tools/hipdnsproxy/dnsproxy.py'
31--- tools/hipdnsproxy/dnsproxy.py 2013-05-26 15:29:43 +0000
32+++ tools/hipdnsproxy/dnsproxy.py 2013-08-12 13:20:15 +0000
33@@ -82,7 +82,7 @@
34 import hosts
35 import resolvconf
36 import util
37-from DNS import Serialize, DeSerialize
38+from DNS import Serialize, DeSerialize, Type
39
40
41 DEFAULT_HOSTS = '/etc/hosts'
42@@ -167,7 +167,6 @@
43 self.server_port = server_port
44
45 self.resolvconf = resolvconf.ResolvConf()
46- self.resolvconf.parse()
47
48 if self.hostsnames is None:
49 self.hostsnames = []
50@@ -218,8 +217,6 @@
51 env = os.environ
52 if self.server_ip is None:
53 self.server_ip = env.get('SERVER', None)
54- if self.server_ip is None:
55- self.server_ip = self.resolvconf.nameserver
56 if self.server_port is None:
57 server_port = env.get('SERVERPORT', None)
58 if server_port is not None:
59@@ -367,7 +364,7 @@
60
61 # convert 1.2....1.0.0.1.0.0.2.ip6.arpa to a HIT and
62 # map host name to address from cache
63- if qtype == 12:
64+ if qtype == Type.PTR:
65 lr_ptr = None
66 addr_str = hosts.ptr_to_addr(qname)
67 if (not self.disable_lsi and addr_str is not None and
68@@ -387,19 +384,19 @@
69 add_hit_ip_map(lr_aaaa_hit[0], lr_a[0])
70 if lr_aaaa is not None:
71 add_hit_ip_map(lr_aaaa_hit[0], lr_aaaa[0])
72- if qtype == 28: # 28: AAAA
73+ if qtype == Type.AAAA:
74 result = lr_aaaa_hit
75- elif qtype == 1 and not self.disable_lsi: # 1: A
76+ elif qtype == Type.A and not self.disable_lsi:
77 lsi = hit_to_lsi(lr_aaaa_hit[0])
78 if lsi is not None:
79 result = (lsi, lr_aaaa_hit[1])
80 elif self.prefix and packet['questions'][0][0].startswith(self.prefix):
81 result = None
82- elif qtype == 28:
83+ elif qtype == Type.AAAA:
84 result = lr_aaaa
85- elif qtype == 1:
86+ elif qtype == Type.A:
87 result = lr_a
88- elif qtype == 12 and lr_ptr is not None: # 12: PTR
89+ elif qtype == Type.PTR and lr_ptr is not None:
90 result = (lr_ptr, self.hosts_ttl)
91
92 if result is not None:
93@@ -418,7 +415,7 @@
94
95 dns_hit_found = False
96 for answer in packet['answers']:
97- if answer[1] == 55:
98+ if answer[1] == Type.HIP:
99 dns_hit_found = True
100 break
101
102@@ -429,20 +426,20 @@
103 lsi_ans = []
104
105 for answer in packet['answers']:
106- if answer[1] != 55:
107+ if answer[1] != Type.HIP:
108 continue
109
110 hit = socket.inet_ntop(socket.AF_INET6, answer[7])
111- hit_ans.append([qname, 28, 1, answer[3], hit])
112+ hit_ans.append([qname, Type.AAAA, 1, answer[3], hit])
113
114- if qtype == 1 and not self.disable_lsi:
115+ if qtype == Type.A and not self.disable_lsi:
116 lsi = hit_to_lsi(hit)
117 if lsi is not None:
118 lsi_ans.append([qname, 1, 1, self.hosts_ttl, lsi])
119
120 self.cache_name(qname, hit, answer[3])
121
122- if qtype == 28 and hit_found:
123+ if qtype == Type.AAAA and hit_found:
124 packet['answers'] = hit_ans
125 elif lsi is not None:
126 packet['answers'] = lsi_ans
127@@ -459,10 +456,6 @@
128
129 self.parameter_defaults()
130
131- if self.server_ip is None:
132- logging.critical('No upstream DNS server, exiting...')
133- return
134-
135 # Default virtual interface and address for dnsproxy to
136 # avoid problems with other dns forwarders (e.g. dnsmasq)
137 os.system('ifconfig lo:53 %s' % (self.bind_ip,))
138@@ -475,7 +468,6 @@
139 self.bind_port)
140 return
141
142- self.resolvconf.nameserver = self.bind_ip
143
144 servsock.settimeout(self.app_timeout)
145
146@@ -494,10 +486,20 @@
147
148 query_id = 1
149
150- util.init_wantdown()
151- util.init_wantdown_int() # Keyboard interrupts
152+ util.init_wantdown() # Initialize signal handler for shutdown
153+ util.init_hup() # Initialize signal handler for reload
154
155 while not util.wantdown():
156+ self.resolvconf.parse()
157+
158+ if self.server_ip is None:
159+ self.server_ip = self.resolvconf.nameserver
160+
161+ if util.wanthup():
162+ logging.info('Received SIGHUP. Picking %s as new upstream '
163+ 'DNS server', self.server_ip)
164+ util.wanthup(False)
165+
166 logging.info('Connecting to upstream DNS server...')
167 if ':' not in self.server_ip:
168 server_family = socket.AF_INET
169@@ -509,12 +511,13 @@
170 clisock.connect((self.server_ip, self.server_port))
171 connected = True
172 logging.debug('... connected!')
173+ self.resolvconf.nameserver = self.bind_ip
174 except socket.error:
175 logging.error('Connecting to upstream DNS server failed!')
176 time.sleep(3)
177 connected = False
178
179- while connected and (not util.wantdown()):
180+ while connected and (not util.wantdown()) and (not util.wanthup()):
181 try:
182 self.hosts_recheck()
183
184@@ -532,7 +535,7 @@
185
186 sent_answer = False
187
188- if qtype in (1, 28, 12):
189+ if qtype in (Type.A, Type.AAAA, Type.PTR):
190 if self.hip_cache_lookup(packet):
191 try:
192 outbuf = Serialize(packet).get_packet()
193@@ -563,21 +566,22 @@
194 query_id = (query_id % 65535) + 1
195 pckt = copy.copy(packet)
196 pckt['id'] = query_id
197- if ((qtype == 28 or
198- (qtype == 1 and not self.disable_lsi)) and not
199- is_reverse_hit_query(
200+ if ((qtype == Type.AAAA or
201+ (qtype == Type.A and
202+ not self.disable_lsi)) and
203+ not is_reverse_hit_query(
204 packet['questions'][0][0])):
205
206 if not self.prefix:
207- pckt['questions'][0][1] = 55
208+ pckt['questions'][0][1] = Type.HIP
209 if (self.prefix and
210 pckt['questions'][0][0].startswith(
211 self.prefix)):
212 pckt['questions'][0][0] = pckt[
213 'questions'][0][0][len(self.prefix):]
214- pckt['questions'][0][1] = 55
215+ pckt['questions'][0][1] = Type.HIP
216
217- if qtype == 12 and not self.disable_lsi:
218+ if qtype == Type.PTR and not self.disable_lsi:
219 qname = packet['questions'][0][0]
220 addr_str = hosts.ptr_to_addr(qname)
221 if (addr_str is not None and
222@@ -616,7 +620,8 @@
223 # Replace with the original query id
224 packet['id'] = packet_o['id']
225
226- if qtype == 55 and query_o[3] in (1, 28):
227+ if qtype == Type.HIP and query_o[3] in (Type.A,
228+ Type.AAAA):
229 # Restore qtype
230 packet['questions'][0][1] = query_o[3]
231 self.hip_lookup(packet)
232@@ -634,18 +639,18 @@
233 for answer in packet['answers']:
234 answer[0] = self.prefix + answer[0]
235
236- elif qtype in (1, 28):
237+ elif qtype in (Type.A, Type.AAAA):
238 hit = self.getaaaa_hit(qname)
239 ip6 = self.getaaaa(qname)
240 ip4 = self.geta(qname)
241 for answer in packet['answers']:
242- if answer[1] in (1, 28):
243+ if answer[1] in (Type.A, Type.AAAA):
244 self.cache_name(qname, answer[4],
245 answer[3])
246 if hit is not None:
247 for answer in packet['answers']:
248- if (answer[1] == 1 or
249- (answer[1] == 28 and not
250+ if (answer[1] == Type.A or
251+ (answer[1] == Type.AAAA and not
252 hosts.valid_hit(answer[4]))):
253 add_hit_ip_map(hit[0], answer[4])
254 # Reply with HIT/LSI once it's been mapped
255@@ -675,14 +680,15 @@
256 # IP was queried for cache only
257 send_reply = False
258
259- elif qtype == 12 and isinstance(query_o[3], str):
260+ elif qtype == Type.PTR and isinstance(query_o[3],
261+ str):
262 packet['questions'][0][0] = query_o[3]
263 for answer in packet['answers']:
264 answer[0] = query_o[3]
265
266 if query_again:
267 if hit_found:
268- qtypes = [28, 1]
269+ qtypes = [Type.AAAA, Type.A]
270 pckt = copy.deepcopy(packet)
271 else:
272 qtypes = [query_o[3]]
273
274=== modified file 'tools/hipdnsproxy/resolvconf.py'
275--- tools/hipdnsproxy/resolvconf.py 2013-05-26 15:28:42 +0000
276+++ tools/hipdnsproxy/resolvconf.py 2013-08-12 13:20:15 +0000
277@@ -26,6 +26,7 @@
278 """Handler for resolv.conf, including resolvconf(8)."""
279
280 import collections
281+import errno
282 import logging
283 import os
284 import subprocess
285@@ -112,16 +113,25 @@
286
287 @classmethod
288 def fragments(cls):
289- proc = subprocess.Popen([ResolvConf.LIST_RECORDS],
290- cwd=ResolvConf.FRAGMENT_DIR, stdout=subprocess.PIPE)
291-
292- out = proc.stdout.readlines()
293- proc.communicate()
294- proc.wait()
295-
296- frags = [x.strip() for x in out]
297-
298- return [os.path.join(ResolvConf.FRAGMENT_DIR, x) for x in frags]
299+ """Return list of resolvconf fragments."""
300+ retries = 3
301+ while retries > 0:
302+ try:
303+ proc = subprocess.Popen([ResolvConf.LIST_RECORDS],
304+ cwd=ResolvConf.FRAGMENT_DIR, stdout=subprocess.PIPE)
305+
306+ out = proc.stdout.readlines()
307+ proc.communicate()
308+ proc.wait()
309+
310+ frags = [x.strip() for x in out]
311+
312+ return [os.path.join(ResolvConf.FRAGMENT_DIR, x) for x in frags]
313+ except IOError, ioe:
314+ if ioe.errno != errno.EINTR:
315+ raise
316+ retries -= 1
317+
318
319 @classmethod
320 def resolvconf_add(cls, ifile):
321
322=== modified file 'tools/hipdnsproxy/util.py'
323--- tools/hipdnsproxy/util.py 2013-02-22 15:16:12 +0000
324+++ tools/hipdnsproxy/util.py 2013-08-12 13:20:15 +0000
325@@ -32,8 +32,7 @@
326 import struct
327 import sys
328
329-__FLAGS = {'down': False,
330- 'alarm': False}
331+__FLAGS = {'down': False, 'hup': False}
332
333
334 class Random:
335@@ -67,42 +66,35 @@
336
337 def sighandler(signum, unused_frame):
338 """A signal handler that toggles flags about received signals."""
339- if signum == signal.SIGTERM:
340- __FLAGS['down'] = True
341- if signum == signal.SIGINT:
342- __FLAGS['down'] = True
343- if signum == signal.SIGALRM:
344- __FLAGS['alarm'] = True
345+ if signum in (signal.SIGTERM, signal.SIGINT):
346+ __FLAGS['down'] = True
347+ if signum == signal.SIGHUP:
348+ __FLAGS['hup'] = True
349
350
351 def init_wantdown():
352 """Hook signal handler to SIGTERM."""
353 signal.signal(signal.SIGTERM, sighandler)
354-
355-
356-def init_wantdown_int():
357- """Hook signal handler to SIGINT."""
358 signal.signal(signal.SIGINT, sighandler)
359
360
361-def init_wantalarm():
362- """Hook signal handler to SIGALRM."""
363- signal.signal(signal.SIGALRM, sighandler)
364+def init_hup():
365+ """Hook signal handler to SIGHUP."""
366+ signal.signal(signal.SIGHUP, sighandler)
367
368
369 def wantdown():
370 """Check if SIGINT or SIGTERM has been received."""
371- previous = __FLAGS['down']
372- __FLAGS['down'] = False
373- return previous
374-
375-
376-def wantalarm():
377- """Check if SIGALRM has been received."""
378- previous = __FLAGS['alarm']
379- __FLAGS['alarm'] = False
380- return previous
381-
382+ return __FLAGS['down']
383+
384+def wanthup(reset=None):
385+ """Check if SIGHUP has been received."""
386+ previous = __FLAGS['hup']
387+
388+ if reset is not None:
389+ __FLAGS['hup'] = reset
390+
391+ return previous
392
393 TMULT = (
394 (re.compile('^(?P<tval>-?\d+(\.\d*))(s|)$', re.I), float, 1),

Subscribers

People subscribed via source and target branches