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 | ||||||||
Related bugs: |
|
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Miika Komu | Approve | ||
Review via email: mp+178932@code.launchpad.net |
Commit message
Description of the change
Implement sane SIGHUP handling (reload configs)
Fixes #1132042 and #1189371
To post a comment you must log in.
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), |
Tested, works. There's still some IOerror left (I'll report this separately), but I think you could fix it directly in the trunk.