]>
Commit | Line | Data |
---|---|---|
1136f709 | 1 | /* sar.h - srvx asynchronous resolver |
2 | * Copyright 2005, 2007 Michael Poole <mdpoole@troilus.org> | |
3 | * | |
4 | * This file is part of srvx. | |
5 | * | |
6 | * srvx is free software; you can redistribute it and/or modify | |
7 | * it under the terms of the GNU General Public License as published by | |
be2c97a5 | 8 | * the Free Software Foundation; either version 3 of the License, or |
1136f709 | 9 | * (at your option) any later version. |
10 | * | |
11 | * This program is distributed in the hope that it will be useful, | |
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
14 | * GNU General Public License for more details. | |
15 | * | |
16 | * You should have received a copy of the GNU General Public License | |
17 | * along with srvx; if not, write to the Free Software Foundation, | |
18 | * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. | |
19 | */ | |
20 | ||
21 | #include "sar.h" | |
22 | #include "conf.h" | |
23 | #include "ioset.h" | |
24 | #include "log.h" | |
25 | #include "timeq.h" | |
26 | ||
27 | #if defined(HAVE_NETINET_IN_H) | |
28 | # include <netinet/in.h> /* sockaddr_in6 on some BSDs */ | |
29 | #endif | |
30 | ||
31 | static const char hexdigits[] = "0123456789abcdef"; | |
32 | ||
33 | struct dns_rr; | |
34 | struct sar_getaddr_state; | |
35 | struct sar_getname_state; | |
36 | ||
37 | struct sar_family_helper { | |
38 | const char *localhost_addr; | |
39 | const char *unspec_addr; | |
40 | unsigned int socklen; | |
41 | unsigned int family; | |
42 | ||
43 | unsigned int (*ntop)(char *output, unsigned int out_size, const struct sockaddr *sa, unsigned int socklen); | |
44 | unsigned int (*pton)(struct sockaddr *sa, unsigned int socklen, unsigned int *bits, const char *input); | |
45 | int (*get_port)(const struct sockaddr *sa, unsigned int socklen); | |
46 | int (*set_port)(struct sockaddr *sa, unsigned int socklen, unsigned short port); | |
47 | unsigned int (*build_addr_request)(struct sar_request *req, const char *node, const char *srv_node, unsigned int flags); | |
48 | void (*build_ptr_name)(struct sar_getname_state *state, const struct sockaddr *sa, unsigned int socklen); | |
49 | int (*decode_addr)(struct sar_getaddr_state *state, struct dns_rr *rr, unsigned char *raw, unsigned int raw_size); | |
50 | ||
51 | struct sar_family_helper *next; | |
52 | }; | |
53 | ||
54 | #define MAX_FAMILY AF_INET | |
55 | static struct sar_family_helper sar_ipv4_helper; | |
56 | ||
57 | #if defined(AF_INET6) | |
58 | # if AF_INET6 > MAX_FAMILY | |
59 | # undef MAX_FAMILY | |
60 | # define MAX_FAMILY AF_INET6 | |
61 | # endif | |
62 | static struct sar_family_helper sar_ipv6_helper; | |
63 | #endif | |
64 | ||
65 | static struct sar_family_helper *sar_helpers[MAX_FAMILY+1]; | |
66 | static struct sar_family_helper *sar_first_helper; | |
67 | ||
68 | unsigned int | |
69 | sar_ntop(char *output, unsigned int out_size, const struct sockaddr *sa, unsigned int socklen) | |
70 | { | |
71 | unsigned int pos; | |
72 | assert(output != NULL); | |
73 | assert(sa != NULL); | |
74 | assert(out_size > 0); | |
75 | ||
76 | if (sa->sa_family <= MAX_FAMILY && sar_helpers[sa->sa_family]) { | |
77 | pos = sar_helpers[sa->sa_family]->ntop(output, out_size, sa, socklen); | |
78 | if (pos) | |
79 | return pos; | |
80 | } | |
81 | *output = '\0'; | |
82 | return 0; | |
83 | } | |
84 | ||
85 | unsigned int | |
86 | sar_pton(struct sockaddr *sa, unsigned int socklen, unsigned int *bits, const char *input) | |
87 | { | |
88 | struct sar_family_helper *helper; | |
89 | unsigned int len; | |
90 | ||
91 | assert(sa != NULL); | |
92 | assert(input != NULL); | |
93 | ||
94 | memset(sa, 0, socklen); | |
95 | if (bits) | |
96 | *bits = ~0; | |
97 | for (helper = sar_first_helper; helper; helper = helper->next) { | |
98 | if (socklen < helper->socklen) | |
99 | continue; | |
100 | len = helper->pton(sa, socklen, bits, input); | |
101 | if (len) { | |
102 | sa->sa_family = helper->family; | |
103 | return len; | |
104 | } | |
105 | } | |
106 | return 0; /* parse failed */ | |
107 | } | |
108 | ||
109 | int | |
110 | sar_get_port(const struct sockaddr *sa, unsigned int socklen) | |
111 | { | |
112 | if (sa->sa_family <= MAX_FAMILY | |
113 | && sar_helpers[sa->sa_family] | |
114 | && socklen >= sar_helpers[sa->sa_family]->socklen) | |
115 | return sar_helpers[sa->sa_family]->get_port(sa, socklen); | |
116 | else return -1; | |
117 | } | |
118 | ||
119 | int | |
120 | sar_set_port(struct sockaddr *sa, unsigned int socklen, unsigned short port) | |
121 | { | |
122 | if (sa->sa_family <= MAX_FAMILY | |
123 | && sar_helpers[sa->sa_family] | |
124 | && socklen >= sar_helpers[sa->sa_family]->socklen) | |
125 | return sar_helpers[sa->sa_family]->set_port(sa, socklen, port); | |
126 | else return 1; | |
127 | } | |
128 | ||
129 | const char * | |
130 | sar_strerror(enum sar_errcode errcode) | |
131 | { | |
132 | switch (errcode) { | |
133 | case SAI_SUCCESS: return "Resolution succeeded."; | |
134 | case SAI_FAMILY: return "The requested address family is not supported."; | |
135 | case SAI_SOCKTYPE: return "The requested socket type is not supported."; | |
136 | case SAI_BADFLAGS: return "Invalid flags value."; | |
137 | case SAI_NONAME: return "Unknown name or service."; | |
138 | case SAI_SERVICE: return "The service is unavailable for that socket type."; | |
139 | case SAI_ADDRFAMILY: return "The host has no address in the requested family."; | |
140 | case SAI_NODATA: return "The host has no addresses at all."; | |
141 | case SAI_MEMORY: return "Unable to allocate memory."; | |
142 | case SAI_FAIL: return "The nameserver indicated a permanent error."; | |
143 | case SAI_AGAIN: return "The nameserver indicated a temporary error."; | |
144 | case SAI_MISMATCH: return "Mismatch between reverse and forward resolution."; | |
145 | case SAI_SYSTEM: return strerror(errno); | |
146 | default: return "Unknown resolver error code."; | |
147 | } | |
148 | } | |
149 | ||
150 | void | |
151 | sar_free(struct addrinfo *ai) | |
152 | { | |
153 | struct addrinfo *next; | |
154 | for (; ai; ai = next) { | |
155 | next = ai->ai_next; | |
156 | free(ai); | |
157 | } | |
158 | } | |
159 | ||
160 | /** Global variables to support DNS name resolution. */ | |
161 | static struct { | |
162 | unsigned int sar_timeout; | |
163 | unsigned int sar_retries; | |
164 | unsigned int sar_ndots; | |
165 | unsigned int sar_edns0; | |
166 | char sar_localdomain[MAXLEN]; | |
167 | struct string_list *sar_search; | |
168 | struct string_list *sar_nslist; | |
8536ac6b | 169 | void *sar_bind_address; |
1136f709 | 170 | } conf; |
171 | static struct log_type *sar_log; | |
172 | ||
173 | /* Except as otherwise noted, constants and formats are from RFC1035. | |
174 | * This resolver is believed to implement the behaviors mandated (and | |
175 | * in many cases those recommended) by these standards: RFC1035, | |
176 | * RFC2671, RFC2782, RFC3596, RFC3597. | |
177 | * | |
178 | * Update queries (including RFC 2136) seems a likely candidate for | |
179 | * future support. | |
180 | * DNSSEC (including RFCs 2535, 3007, 3655, etc) is less likely until | |
181 | * a good application is found. | |
182 | * Caching (RFC 2308) and redirection (RFC 2672) are much less likely, | |
183 | * since most users will have a separate local, caching, recursive | |
184 | * nameserver. | |
185 | * Other DNS extensions (at least through RFC 3755) are believed to be | |
186 | * too rare or insufficiently useful to bother supporting. | |
187 | * | |
188 | * The following are useful Reasons For Concern: | |
189 | * RFC1536, RFC1912, RFC2606, RFC3363, RFC3425, RFC3467 | |
190 | * http://www.iana.org/assignments/dns-parameters | |
191 | * http://www.ietf.org/html.charters/dnsext-charter.html | |
192 | */ | |
193 | ||
194 | struct sar_nameserver { | |
195 | char *name; | |
196 | unsigned int valid; | |
197 | unsigned int req_sent; | |
198 | unsigned int resp_used; | |
199 | unsigned int resp_ignored; | |
200 | unsigned int resp_servfail; | |
201 | unsigned int resp_fallback; | |
202 | unsigned int resp_failures; | |
203 | unsigned int resp_scrambled; | |
204 | unsigned int ss_len; | |
8536ac6b | 205 | void *ss; |
1136f709 | 206 | }; |
207 | ||
208 | /* EDNS0 uses 12 bit RCODEs, TSIG/TKEY use 16 bit RCODEs. | |
209 | * Declare local RCODE failures here.*/ | |
210 | enum { | |
211 | RCODE_TIMED_OUT = 65536, | |
212 | RCODE_QUERY_TOO_LONG, | |
213 | RCODE_LABEL_TOO_LONG, | |
214 | RCODE_SOCKET_FAILURE, | |
215 | RCODE_DESTROYED, | |
216 | }; | |
217 | ||
218 | #define DNS_NAME_LENGTH 256 | |
219 | ||
220 | #define RES_SIZE_FLAGS 0xc0 | |
221 | #define RES_SF_LABEL 0x00 | |
222 | #define RES_SF_POINTER 0xc0 | |
223 | ||
224 | static dict_t sar_requests; | |
225 | static dict_t sar_nameservers; | |
226 | static struct io_fd *sar_fd; | |
227 | static int sar_fd_fd; | |
228 | ||
229 | const char * | |
230 | sar_rcode_text(unsigned int rcode) | |
231 | { | |
232 | switch (rcode) { | |
233 | case RCODE_NO_ERROR: return "No error"; | |
234 | case RCODE_FORMAT_ERROR: return "Format error"; | |
235 | case RCODE_SERVER_FAILURE: return "Server failure"; | |
236 | case RCODE_NAME_ERROR: return "Name error"; | |
237 | case RCODE_NOT_IMPLEMENTED: return "Feature not implemented"; | |
238 | case RCODE_REFUSED: return "Query refused"; | |
239 | case RCODE_BAD_OPT_VERSION: return "Unsupported EDNS option version"; | |
240 | case RCODE_TIMED_OUT: return "Request timed out"; | |
241 | case RCODE_QUERY_TOO_LONG: return "Query too long"; | |
242 | case RCODE_LABEL_TOO_LONG: return "Label too long"; | |
243 | case RCODE_SOCKET_FAILURE: return "Resolver socket failure"; | |
244 | case RCODE_DESTROYED: return "Request unexpectedly destroyed"; | |
245 | default: return "Unknown rcode"; | |
246 | } | |
247 | } | |
248 | ||
249 | static void | |
250 | sar_request_fail(struct sar_request *req, unsigned int rcode) | |
251 | { | |
252 | log_module(sar_log, LOG_DEBUG, "sar_request_fail({id=%d}, rcode=%d)", req->id, rcode); | |
253 | req->expiry = 0; | |
254 | if (req->cb_fail) { | |
255 | req->cb_fail(req, rcode); | |
256 | if (req->expiry) | |
257 | return; | |
258 | } | |
259 | sar_request_abort(req); | |
260 | } | |
261 | ||
262 | static unsigned long next_sar_timeout; | |
263 | ||
264 | static void | |
265 | sar_timeout_cb(void *data) | |
266 | { | |
267 | dict_iterator_t it; | |
268 | dict_iterator_t next; | |
269 | time_t next_timeout = INT_MAX; | |
270 | ||
271 | for (it = dict_first(sar_requests); it; it = next) { | |
272 | struct sar_request *req; | |
273 | ||
274 | req = iter_data(it); | |
275 | next = iter_next(it); | |
276 | if (req->expiry > next_timeout) | |
277 | continue; | |
278 | else if (req->expiry > now) | |
279 | next_timeout = req->expiry; | |
280 | else if (req->retries >= conf.sar_retries) | |
281 | sar_request_fail(req, RCODE_TIMED_OUT); | |
282 | else | |
283 | sar_request_send(req); | |
284 | } | |
285 | if (next_timeout < INT_MAX) { | |
286 | next_sar_timeout = next_timeout; | |
287 | timeq_add(next_timeout, sar_timeout_cb, data); | |
288 | } | |
289 | } | |
290 | ||
291 | static void | |
292 | sar_check_timeout(unsigned long when) | |
293 | { | |
294 | if (!next_sar_timeout || when < next_sar_timeout) { | |
295 | timeq_del(0, sar_timeout_cb, NULL, TIMEQ_IGNORE_WHEN | TIMEQ_IGNORE_DATA); | |
296 | timeq_add(when, sar_timeout_cb, NULL); | |
297 | next_sar_timeout = when; | |
298 | } | |
299 | } | |
300 | ||
301 | static void | |
302 | sar_request_cleanup(void *d) | |
303 | { | |
304 | struct sar_request *req = d; | |
305 | log_module(sar_log, LOG_DEBUG, "sar_request_cleanup({id=%d})", req->id); | |
306 | free(req->body); | |
307 | if (req->cb_fail) | |
308 | req->cb_fail(req, RCODE_DESTROYED); | |
309 | free(req); | |
310 | } | |
311 | ||
312 | static void | |
313 | sar_dns_init(const char *resolv_conf_path) | |
314 | { | |
315 | struct string_list *ns_sv; | |
316 | struct string_list *ds_sv; | |
317 | FILE *resolv_conf; | |
318 | dict_t node; | |
319 | const char *str; | |
320 | ||
321 | /* Initialize configuration defaults. */ | |
322 | conf.sar_localdomain[0] = '\0'; | |
323 | conf.sar_timeout = 3; | |
324 | conf.sar_retries = 3; | |
325 | conf.sar_ndots = 1; | |
326 | conf.sar_edns0 = 0; | |
327 | ns_sv = alloc_string_list(4); | |
328 | ds_sv = alloc_string_list(4); | |
329 | ||
330 | /* Scan resolver configuration file. */ | |
331 | resolv_conf = fopen(resolv_conf_path, "r"); | |
332 | if (resolv_conf) { | |
333 | char *arg, *opt; | |
334 | unsigned int len; | |
335 | char linebuf[LINE_MAX], ch; | |
336 | ||
337 | while (fgets(linebuf, sizeof(linebuf), resolv_conf)) { | |
338 | ch = linebuf[len = strcspn(linebuf, " \t\r\n")]; | |
339 | linebuf[len] = '\0'; | |
340 | arg = linebuf + len + 1; | |
341 | if (!strcmp(linebuf, "nameserver")) { | |
342 | while (ch == ' ') { | |
343 | ch = arg[len = strcspn(arg, " \t\r\n")]; | |
344 | arg[len] = '\0'; | |
345 | string_list_append(ns_sv, strdup(arg)); | |
346 | arg += len + 1; | |
347 | } | |
348 | } else if (!strcmp(linebuf, "domain")) { | |
349 | if (ch == ' ') { | |
350 | safestrncpy(conf.sar_localdomain, arg, sizeof(conf.sar_localdomain)); | |
351 | } | |
352 | } else if (!strcmp(linebuf, "search")) { | |
353 | while (ch == ' ') { | |
354 | ch = arg[len = strcspn(arg, " \t\r\n")]; | |
355 | arg[len] = '\0'; | |
356 | string_list_append(ds_sv, strdup(arg)); | |
357 | arg += len + 1; | |
358 | } | |
359 | } else if (!strcmp(linebuf, "options")) { | |
360 | while (ch == ' ') { | |
361 | ch = arg[len = strcspn(arg, " \t\r\n")]; | |
362 | arg[len] = '\0'; | |
363 | opt = strchr(arg, ':'); | |
364 | if (opt) { | |
365 | *opt++ = '\0'; | |
366 | if (!strcmp(arg, "timeout")) { | |
367 | conf.sar_timeout = atoi(opt); | |
368 | } else if (!strcmp(arg, "attempts")) { | |
369 | conf.sar_retries = atoi(opt); | |
370 | } else if (!strcmp(arg, "ndots")) { | |
371 | conf.sar_ndots = atoi(opt); | |
372 | } else if (!strcmp(arg, "edns0")) { | |
373 | conf.sar_edns0 = atoi(opt); | |
374 | } | |
375 | } else if (!strcmp(arg, "edns0")) { | |
376 | conf.sar_edns0 = 1440; | |
377 | } | |
378 | arg += len + 1; | |
379 | } | |
380 | } | |
381 | } | |
382 | fclose(resolv_conf); | |
383 | } else { | |
384 | /* This is apparently what BIND defaults to using. */ | |
385 | string_list_append(ns_sv, "127.0.0.1"); | |
386 | } | |
387 | ||
388 | /* Set default search path if domain is set. */ | |
389 | if (conf.sar_localdomain[0] != '\0' && ds_sv->used == 0) | |
390 | string_list_append(ds_sv, strdup(conf.sar_localdomain)); | |
391 | ||
392 | /* Check configuration entries that might override resolv.conf. */ | |
393 | node = conf_get_data("modules/sar", RECDB_OBJECT); | |
394 | if (node) { | |
395 | struct sockaddr *sa; | |
396 | struct string_list *slist; | |
397 | ||
398 | str = database_get_data(node, "timeout", RECDB_QSTRING); | |
399 | if (str) conf.sar_timeout = ParseInterval(str); | |
400 | str = database_get_data(node, "retries", RECDB_QSTRING); | |
401 | if (str) conf.sar_retries = atoi(str); | |
402 | str = database_get_data(node, "ndots", RECDB_QSTRING); | |
403 | if (str) conf.sar_ndots = atoi(str); | |
404 | str = database_get_data(node, "edns0", RECDB_QSTRING); | |
405 | if (str) conf.sar_edns0 = enabled_string(str); | |
406 | str = database_get_data(node, "domain", RECDB_QSTRING); | |
407 | if (str) safestrncpy(conf.sar_localdomain, str, sizeof(conf.sar_localdomain)); | |
408 | slist = database_get_data(node, "search", RECDB_STRING_LIST); | |
409 | if (slist) { | |
410 | free_string_list(ds_sv); | |
411 | ds_sv = string_list_copy(slist); | |
412 | } | |
413 | slist = database_get_data(node, "nameservers", RECDB_STRING_LIST); | |
414 | if (slist) { | |
415 | free_string_list(ns_sv); | |
416 | ns_sv = string_list_copy(slist); | |
417 | } | |
8536ac6b | 418 | sa = (struct sockaddr*)conf.sar_bind_address; |
419 | memset(sa, 0, sizeof(struct sockaddr_storage)); | |
1136f709 | 420 | str = database_get_data(node, "bind_address", RECDB_QSTRING); |
8536ac6b | 421 | if (str) sar_pton(sa, sizeof(struct sockaddr_storage), NULL, str); |
1136f709 | 422 | str = database_get_data(node, "bind_port", RECDB_QSTRING); |
423 | if (str != NULL) { | |
424 | if (sa->sa_family == AF_INET) { | |
425 | struct sockaddr_in *sin = (struct sockaddr_in*)sa; | |
426 | sin->sin_port = ntohs(atoi(str)); | |
427 | } | |
428 | #if defined(AF_INET6) | |
429 | else if (sa->sa_family == AF_INET6) { | |
430 | struct sockaddr_in6 *sin6 = (struct sockaddr_in6*)sa; | |
431 | sin6->sin6_port = ntohs(atoi(str)); | |
432 | } | |
433 | #endif | |
434 | } | |
435 | } | |
436 | ||
437 | /* Replace config lists with their new values. */ | |
438 | free_string_list(conf.sar_search); | |
439 | conf.sar_search = ds_sv; | |
440 | free_string_list(conf.sar_nslist); | |
441 | conf.sar_nslist = ns_sv; | |
442 | } | |
443 | ||
444 | void | |
445 | sar_request_abort(struct sar_request *req) | |
446 | { | |
447 | if (!req) | |
448 | return; | |
449 | assert(dict_find(sar_requests, req->id_text, NULL) == req); | |
450 | log_module(sar_log, LOG_DEBUG, "sar_request_abort({id=%d})", req->id); | |
451 | req->cb_ok = NULL; | |
452 | req->cb_fail = NULL; | |
453 | dict_remove(sar_requests, req->id_text); | |
454 | } | |
455 | ||
456 | static struct sar_nameserver * | |
457 | sar_our_server(const struct sockaddr_storage *ss, unsigned int ss_len) | |
458 | { | |
459 | dict_iterator_t it; | |
460 | ||
461 | for (it = dict_first(sar_nameservers); it; it = iter_next(it)) { | |
462 | struct sar_nameserver *ns; | |
463 | ||
464 | ns = iter_data(it); | |
8536ac6b | 465 | if (ns->ss_len == ss_len && !memcmp(ss, ns->ss, ss_len)) |
1136f709 | 466 | return ns; |
467 | } | |
468 | return NULL; | |
469 | } | |
470 | ||
471 | char * | |
472 | sar_extract_name(const unsigned char *buf, unsigned int size, unsigned int *ppos) | |
473 | { | |
474 | struct string_buffer cv; | |
475 | unsigned int pos, jumped; | |
476 | ||
477 | pos = *ppos; | |
478 | jumped = 0; | |
479 | cv.used = 0; | |
480 | cv.size = 64; | |
481 | cv.list = calloc(1, cv.size); | |
482 | while (1) { | |
483 | if (pos >= size) | |
484 | goto fail; | |
485 | if (!buf[pos]) { | |
486 | if (!jumped) | |
487 | *ppos = pos + 1; | |
488 | if (cv.used) | |
489 | cv.list[cv.used - 1] = '\0'; /* chop off terminating '.' */ | |
490 | else | |
491 | string_buffer_append(&cv, '\0'); | |
492 | return cv.list; | |
493 | } | |
494 | switch (buf[pos] & RES_SIZE_FLAGS) { | |
495 | case RES_SF_LABEL: { | |
496 | unsigned int len = buf[pos]; | |
497 | if (pos + len + 1 >= size) | |
498 | goto fail; | |
499 | string_buffer_append_substring(&cv, (char*)buf + pos + 1, len); | |
500 | string_buffer_append(&cv, '.'); | |
501 | pos += buf[pos] + 1; | |
502 | break; | |
503 | } | |
504 | case RES_SF_POINTER: | |
505 | if ((pos + 1 >= size) || (cv.used >= size)) | |
506 | goto fail; | |
507 | if (!jumped) | |
508 | *ppos = pos + 2; | |
509 | pos = (buf[pos] & ~RES_SIZE_FLAGS) << 8 | buf[pos+1]; | |
510 | jumped = 1; | |
511 | break; | |
512 | default: | |
513 | goto fail; | |
514 | } | |
515 | } | |
516 | fail: | |
517 | free(cv.list); | |
518 | return NULL; | |
519 | } | |
520 | ||
521 | static int | |
522 | sar_decode_answer(struct sar_request *req, struct dns_header *hdr, unsigned char *buf, unsigned int size) | |
523 | { | |
524 | struct dns_rr *rr; | |
525 | unsigned int ii, rr_count, pos; | |
526 | int res; | |
527 | ||
528 | /* Skip over query section. */ | |
529 | for (ii = 0, pos = 12; ii < hdr->qdcount; ++ii) { | |
530 | /* Skip over compressed names. */ | |
531 | while (1) { | |
532 | if (pos >= size) | |
533 | return 2; | |
534 | if (!buf[pos]) | |
535 | break; | |
536 | switch (buf[pos] & RES_SIZE_FLAGS) { | |
537 | case RES_SF_LABEL: | |
538 | pos += buf[pos] + 1; | |
539 | break; | |
540 | case RES_SF_POINTER: | |
541 | if (pos + 1 >= size) | |
542 | return 2; | |
543 | pos = (buf[pos] & ~RES_SIZE_FLAGS) << 8 | buf[pos+1]; | |
544 | if (pos >= size) | |
545 | return 3; | |
546 | break; | |
547 | default: | |
548 | return 4; | |
549 | } | |
550 | } | |
551 | /* Skip over null terminator, type and class part of question. */ | |
552 | pos += 5; | |
553 | } | |
554 | ||
555 | /* Parse each RR in the answer. */ | |
556 | rr_count = hdr->ancount + hdr->nscount + hdr->arcount; | |
557 | rr = calloc(1, rr_count * sizeof(rr[0])); | |
558 | for (ii = 0; ii < rr_count; ++ii) { | |
559 | rr[ii].name = sar_extract_name(buf, size, &pos); | |
560 | if (!rr[ii].name) { | |
561 | res = 5; | |
562 | goto out; | |
563 | } | |
564 | if (pos + 10 > size) { | |
565 | res = 6; | |
566 | goto out; | |
567 | } | |
568 | rr[ii].type = buf[pos+0] << 8 | buf[pos+1]; | |
569 | rr[ii].class = buf[pos+2] << 8 | buf[pos+3]; | |
570 | rr[ii].ttl = buf[pos+4] << 24 | buf[pos+5] << 16 | buf[pos+6] << 8 | buf[pos+7]; | |
571 | rr[ii].rdlength = buf[pos+8] << 8 | buf[pos+9]; | |
572 | rr[ii].rd_start = pos + 10; | |
573 | pos = pos + rr[ii].rdlength + 10; | |
574 | if (pos > size) { | |
575 | res = 7; | |
576 | goto out; | |
577 | } | |
578 | } | |
579 | res = 0; | |
580 | req->expiry = 0; | |
581 | req->cb_ok(req, hdr, rr, buf, size); | |
582 | if (!req->expiry) { | |
583 | req->cb_ok = NULL; | |
584 | req->cb_fail = NULL; | |
585 | dict_remove(sar_requests, req->id_text); | |
586 | } | |
587 | ||
588 | out: | |
589 | while (ii > 0) | |
590 | free(rr[--ii].name); | |
591 | free(rr); | |
592 | return res; | |
593 | } | |
594 | ||
595 | static const unsigned char * | |
596 | sar_extract_rdata(struct dns_rr *rr, unsigned int len, unsigned char *raw, unsigned int raw_size) | |
597 | { | |
598 | if (len > rr->rdlength) | |
599 | return NULL; | |
600 | if (rr->rd_start + len > raw_size) | |
601 | return NULL; | |
602 | return raw + rr->rd_start; | |
603 | } | |
604 | ||
605 | static void | |
606 | sar_fd_readable(struct io_fd *fd) | |
607 | { | |
1136f709 | 608 | struct dns_header hdr; |
609 | struct sar_nameserver *ns; | |
610 | struct sar_request *req; | |
8536ac6b | 611 | void *ss; |
1136f709 | 612 | unsigned char *buf; |
613 | socklen_t ss_len; | |
614 | int res, rcode, buf_len; | |
615 | char id_text[6]; | |
616 | ||
617 | assert(sar_fd == fd); | |
618 | buf_len = conf.sar_edns0; | |
619 | if (!buf_len) | |
620 | buf_len = 512; | |
621 | buf = alloca(buf_len); | |
8536ac6b | 622 | ss_len = sizeof(struct sockaddr_storage); |
623 | ss = alloca(ss_len); | |
624 | res = recvfrom(sar_fd_fd, buf, buf_len, 0, (struct sockaddr*)ss, &ss_len); | |
625 | if (res < 12 || !(ns = sar_our_server((struct sockaddr_storage*)ss, ss_len))) | |
1136f709 | 626 | return; |
627 | hdr.id = buf[0] << 8 | buf[1]; | |
628 | hdr.flags = buf[2] << 8 | buf[3]; | |
629 | hdr.qdcount = buf[4] << 8 | buf[5]; | |
630 | hdr.ancount = buf[6] << 8 | buf[7]; | |
631 | hdr.nscount = buf[8] << 8 | buf[9]; | |
632 | hdr.arcount = buf[10] << 8 | buf[11]; | |
633 | ||
634 | sprintf(id_text, "%d", hdr.id); | |
635 | req = dict_find(sar_requests, id_text, NULL); | |
636 | log_module(sar_log, LOG_DEBUG, "sar_fd_readable(%p): hdr {id=%d, flags=0x%x, qdcount=%d, ancount=%d, nscount=%d, arcount=%d} -> req %p", (void*)fd, hdr.id, hdr.flags, hdr.qdcount, hdr.ancount, hdr.nscount, hdr.arcount, (void*)req); | |
637 | if (!req || !req->retries || !(hdr.flags & REQ_FLAG_QR)) { | |
638 | ns->resp_ignored++; | |
639 | return; | |
640 | } | |
641 | rcode = hdr.flags & REQ_FLAG_RCODE_MASK; | |
642 | if (rcode != RCODE_NO_ERROR) { | |
643 | sar_request_fail(req, rcode); | |
644 | } else if (sar_decode_answer(req, &hdr, (unsigned char*)buf, res)) { | |
645 | ns->resp_scrambled++; | |
646 | sar_request_fail(req, RCODE_FORMAT_ERROR); | |
647 | } | |
648 | } | |
649 | ||
650 | static void | |
651 | sar_build_nslist(struct string_list *nslist) | |
652 | { | |
653 | dict_iterator_t it, next; | |
654 | struct sar_nameserver *ns; | |
655 | unsigned int ii; | |
656 | ||
657 | for (it = dict_first(sar_nameservers); it; it = iter_next(it)) { | |
658 | ns = iter_data(it); | |
659 | ns->valid = 0; | |
660 | } | |
661 | ||
662 | for (ii = 0; ii < nslist->used; ++ii) { | |
663 | const char *name; | |
664 | ||
665 | name = nslist->list[ii]; | |
666 | ns = dict_find(sar_nameservers, name, NULL); | |
667 | if (!ns) { | |
8536ac6b | 668 | struct sockaddr *sa; |
1136f709 | 669 | ns = calloc(1, sizeof(*ns) + strlen(name) + 1); |
670 | ns->name = (char*)(ns + 1); | |
671 | strcpy(ns->name, name); | |
8536ac6b | 672 | ns->ss_len = sizeof(struct sockaddr_storage); |
673 | ns->ss = calloc(1, ns->ss_len); | |
674 | sa = (struct sockaddr*)ns->ss; | |
675 | if (!sar_pton(sa, ns->ss_len, NULL, name)) { | |
1136f709 | 676 | free(it); |
677 | continue; | |
678 | } | |
8536ac6b | 679 | sar_set_port(sa, ns->ss_len, 53); |
680 | ns->ss_len = sar_helpers[sa->sa_family]->socklen; | |
1136f709 | 681 | dict_insert(sar_nameservers, ns->name, ns); |
682 | } | |
683 | ns->valid = 1; | |
684 | } | |
685 | ||
686 | for (it = dict_first(sar_nameservers); it; it = next) { | |
687 | next = iter_next(it); | |
688 | ns = iter_data(it); | |
689 | if (!ns->valid) | |
690 | dict_remove(sar_nameservers, ns->name); | |
691 | } | |
692 | } | |
693 | ||
8536ac6b | 694 | static void |
695 | sar_free_nameserver(void *obj) | |
696 | { | |
697 | struct sar_nameserver *ns = obj; | |
698 | free(ns->ss); | |
699 | free(ns); | |
700 | } | |
701 | ||
702 | static unsigned int | |
703 | sar_addrlen(const struct sockaddr *sa, UNUSED_ARG(unsigned int size)) | |
704 | { | |
705 | return sa->sa_family <= MAX_FAMILY && sar_helpers[sa->sa_family] | |
706 | ? sar_helpers[sa->sa_family]->socklen : 0; | |
707 | } | |
708 | ||
1136f709 | 709 | static int |
710 | sar_open_fd(void) | |
711 | { | |
8536ac6b | 712 | struct sockaddr *sa; |
1136f709 | 713 | int res; |
714 | ||
715 | /* Build list of nameservers. */ | |
716 | sar_build_nslist(conf.sar_nslist); | |
717 | ||
8536ac6b | 718 | sa = (struct sockaddr*)conf.sar_bind_address; |
719 | if (sa->sa_family != 0) { | |
720 | sar_fd_fd = socket(sa->sa_family, SOCK_DGRAM, 0); | |
1136f709 | 721 | if (sar_fd_fd < 0) { |
722 | log_module(sar_log, LOG_FATAL, "Unable to create resolver socket: %s", strerror(errno)); | |
723 | return 1; | |
724 | } | |
725 | ||
8536ac6b | 726 | res = bind(sar_fd_fd, sa, sar_addrlen(sa, sizeof(struct sockaddr_storage))); |
1136f709 | 727 | if (res < 0) |
728 | log_module(sar_log, LOG_ERROR, "Unable to bind resolver socket to address [%s]:%s: %s", (char*)conf_get_data("modules/sar/bind_address", RECDB_QSTRING), (char*)conf_get_data("modules/sar/bind_port", RECDB_QSTRING), strerror(errno)); | |
729 | } else { | |
730 | dict_iterator_t it; | |
731 | struct sar_nameserver *ns; | |
732 | ||
733 | it = dict_first(sar_nameservers); | |
734 | ns = iter_data(it); | |
8536ac6b | 735 | sar_fd_fd = socket(((struct sockaddr*)ns->ss)->sa_family, SOCK_DGRAM, 0); |
1136f709 | 736 | if (sar_fd_fd < 0) { |
737 | log_module(sar_log, LOG_FATAL, "Unable to create resolver socket: %s", strerror(errno)); | |
738 | return 1; | |
739 | } | |
740 | } | |
741 | ||
742 | sar_fd = ioset_add(sar_fd_fd); | |
743 | if (!sar_fd) { | |
744 | log_module(sar_log, LOG_FATAL, "Unable to register resolver socket with event loop."); | |
745 | return 1; | |
746 | } | |
747 | sar_fd->state = IO_CONNECTED; | |
748 | sar_fd->readable_cb = sar_fd_readable; | |
749 | return 0; | |
750 | } | |
751 | ||
752 | struct name_ofs { | |
753 | const char *name; | |
754 | unsigned int ofs; | |
755 | }; | |
756 | ||
757 | static int | |
758 | set_compare_charp(const void *a_, const void *b_) | |
759 | { | |
760 | char * const *a = a_, * const *b = b_; | |
761 | return strcasecmp(*a, *b); | |
762 | } | |
763 | ||
764 | static void | |
765 | string_buffer_reserve(struct string_buffer *cv, unsigned int min_length) | |
766 | { | |
767 | if (cv->size < min_length) { | |
768 | char *new_buffer; | |
769 | new_buffer = realloc(cv->list, min_length); | |
770 | if (new_buffer) { | |
771 | cv->size = min_length; | |
772 | cv->list = new_buffer; | |
773 | } | |
774 | } | |
775 | } | |
776 | ||
777 | /** Append \a name to \a cv in compressed form. */ | |
778 | static int | |
779 | sar_append_name(struct string_buffer *cv, const char *name, struct name_ofs *ofs, unsigned int *used, unsigned int alloc) | |
780 | { | |
781 | struct name_ofs *pofs; | |
782 | unsigned int len; | |
783 | ||
784 | while (1) { | |
785 | pofs = bsearch(&name, ofs, *used, sizeof(ofs[0]), set_compare_charp); | |
786 | if (pofs) { | |
787 | string_buffer_reserve(cv, cv->used + 2); | |
788 | cv->list[cv->used++] = RES_SF_POINTER | (pofs->ofs >> 8); | |
789 | cv->list[cv->used++] = pofs->ofs & 255; | |
790 | return 0; | |
791 | } | |
792 | len = strcspn(name, "."); | |
793 | if (len > 63) | |
794 | return 1; | |
795 | if (*used < alloc) { | |
796 | ofs[*used].name = name; | |
797 | ofs[*used].ofs = cv->used; | |
798 | qsort(ofs, (*used)++, sizeof(ofs[0]), set_compare_charp); | |
799 | } | |
800 | string_buffer_reserve(cv, cv->used + len + 1); | |
801 | cv->list[cv->used] = RES_SF_LABEL | len; | |
802 | memcpy(cv->list + cv->used + 1, name, len); | |
803 | cv->used += len + 1; | |
804 | if (name[len] == '.') | |
805 | name += len + 1; | |
806 | else if (name[len] == '\0') | |
807 | break; | |
808 | } | |
809 | string_buffer_append(cv, '\0'); | |
810 | return 0; | |
811 | } | |
812 | ||
813 | /** Build a DNS question packet from a variable-length argument list. | |
814 | * In \a args, there is at least one pari consisting of const char | |
815 | * *name and unsigned int qtype. A null name argument terminates the | |
816 | * list. | |
817 | */ | |
818 | unsigned int | |
819 | sar_request_vbuild(struct sar_request *req, va_list args) | |
820 | { | |
821 | struct name_ofs suffixes[32]; | |
822 | struct string_buffer cv; | |
823 | const char *name; | |
824 | unsigned int suf_used; | |
825 | unsigned int val; | |
826 | unsigned int qdcount; | |
827 | ||
828 | cv.used = 0; | |
829 | cv.size = 512; | |
830 | cv.list = calloc(1, cv.size); | |
831 | suf_used = 0; | |
832 | val = REQ_OPCODE_QUERY | REQ_FLAG_RD; | |
833 | cv.list[0] = req->id >> 8; | |
834 | cv.list[1] = req->id & 255; | |
835 | cv.list[2] = val >> 8; | |
836 | cv.list[3] = val & 255; | |
837 | cv.list[6] = cv.list[7] = cv.list[8] = cv.list[9] = cv.list[10] = 0; | |
838 | cv.used = 12; | |
839 | for (qdcount = 0; (name = va_arg(args, const char*)); ++qdcount) { | |
840 | if (sar_append_name(&cv, name, suffixes, &suf_used, ArrayLength(suffixes))) { | |
841 | string_buffer_clean(&cv); | |
842 | goto out; | |
843 | } | |
844 | string_buffer_reserve(&cv, cv.used + 4); | |
845 | val = va_arg(args, unsigned int); | |
846 | cv.list[cv.used++] = val >> 8; | |
847 | cv.list[cv.used++] = val & 255; | |
848 | cv.list[cv.used++] = REQ_CLASS_IN >> 8; | |
849 | cv.list[cv.used++] = REQ_CLASS_IN & 255; | |
850 | } | |
851 | cv.list[4] = qdcount >> 8; | |
852 | cv.list[5] = qdcount & 255; | |
853 | val = conf.sar_edns0; | |
854 | if (val) { | |
855 | string_buffer_reserve(&cv, cv.used + 11); | |
856 | cv.list[cv.used + 0] = '\0'; /* empty name */ | |
857 | cv.list[cv.used + 1] = REQ_TYPE_OPT >> 8; | |
858 | cv.list[cv.used + 2] = REQ_TYPE_OPT & 255; | |
859 | cv.list[cv.used + 3] = val >> 8; | |
860 | cv.list[cv.used + 4] = val & 255; | |
861 | cv.list[cv.used + 5] = 0; /* extended-rcode */ | |
862 | cv.list[cv.used + 6] = 0; /* version */ | |
863 | cv.list[cv.used + 7] = 0; /* reserved */ | |
864 | cv.list[cv.used + 8] = 0; /* reserved */ | |
865 | cv.list[cv.used + 9] = 0; /* msb rdlen */ | |
866 | cv.list[cv.used + 10] = 0; /* lsb rdlen */ | |
867 | cv.used += 11; | |
868 | cv.list[11] = 1; /* update arcount */ | |
869 | } else cv.list[11] = 0; | |
870 | ||
871 | out: | |
872 | free(req->body); | |
873 | req->body = (unsigned char*)cv.list; | |
874 | req->body_len = cv.used; | |
875 | return cv.used; | |
876 | } | |
877 | ||
878 | /** Build a DNS question packet. After \a req, there is at least one | |
879 | * pair consisting of const char *name and unsigned int qtype. A null | |
880 | * name argument terminates the list. | |
881 | */ | |
882 | unsigned int | |
883 | sar_request_build(struct sar_request *req, ...) | |
884 | { | |
885 | va_list vargs; | |
886 | unsigned int ret; | |
887 | va_start(vargs, req); | |
888 | ret = sar_request_vbuild(req, vargs); | |
889 | va_end(vargs); | |
890 | return ret; | |
891 | } | |
892 | ||
893 | void | |
894 | sar_request_send(struct sar_request *req) | |
895 | { | |
896 | dict_iterator_t it; | |
897 | ||
898 | /* make sure we have our local socket */ | |
899 | if (!sar_fd && sar_open_fd()) { | |
900 | sar_request_fail(req, RCODE_SOCKET_FAILURE); | |
901 | return; | |
902 | } | |
903 | ||
904 | log_module(sar_log, LOG_DEBUG, "sar_request_send({id=%d})", req->id); | |
905 | ||
906 | /* send query to each configured nameserver */ | |
907 | for (it = dict_first(sar_nameservers); it; it = iter_next(it)) { | |
908 | struct sar_nameserver *ns; | |
909 | int res; | |
910 | ||
911 | ns = iter_data(it); | |
8536ac6b | 912 | res = sendto(sar_fd_fd, req->body, req->body_len, 0, (struct sockaddr*)ns->ss, ns->ss_len); |
1136f709 | 913 | if (res > 0) { |
914 | ns->req_sent++; | |
915 | log_module(sar_log, LOG_DEBUG, "Sent %u bytes to %s.", res, ns->name); | |
916 | } else if (res < 0) | |
917 | log_module(sar_log, LOG_ERROR, "Unable to send %u bytes to nameserver %s: %s", req->body_len, ns->name, strerror(errno)); | |
918 | else /* res == 0 */ | |
919 | assert(0 && "resolver sendto() unexpectedly returned zero"); | |
920 | } | |
921 | ||
922 | /* Check that query timeout is soon enough. */ | |
923 | req->expiry = now + (conf.sar_timeout << ++req->retries); | |
924 | sar_check_timeout(req->expiry); | |
925 | } | |
926 | ||
927 | struct sar_request * | |
928 | sar_request_alloc(unsigned int data_len, sar_request_ok_cb ok_cb, sar_request_fail_cb fail_cb) | |
929 | { | |
930 | struct sar_request *req; | |
931 | ||
932 | req = calloc(1, sizeof(*req) + data_len); | |
933 | req->cb_ok = ok_cb; | |
934 | req->cb_fail = fail_cb; | |
935 | do { | |
936 | req->id = rand() & 0xffff; | |
937 | sprintf(req->id_text, "%d", req->id); | |
938 | } while (dict_find(sar_requests, req->id_text, NULL)); | |
939 | dict_insert(sar_requests, req->id_text, req); | |
940 | log_module(sar_log, LOG_DEBUG, "sar_request_alloc(%d) -> {id=%d}", data_len, req->id); | |
941 | return req; | |
942 | } | |
943 | ||
944 | struct sar_request * | |
945 | sar_request_simple(unsigned int data_len, sar_request_ok_cb ok_cb, sar_request_fail_cb fail_cb, ...) | |
946 | { | |
947 | struct sar_request *req; | |
948 | ||
949 | req = sar_request_alloc(data_len, ok_cb, fail_cb); | |
950 | if (req) { | |
951 | va_list args; | |
952 | ||
953 | va_start(args, fail_cb); | |
954 | sar_request_vbuild(req, args); | |
955 | va_end(args); | |
956 | sar_request_send(req); | |
957 | } | |
958 | return req; | |
959 | } | |
960 | ||
961 | enum service_proto { | |
962 | SERVICE_UDP, | |
963 | SERVICE_TCP, | |
964 | SERVICE_NUM_PROTOS | |
965 | }; | |
966 | ||
967 | struct service_byname { | |
968 | const char *name; /* service name */ | |
969 | struct { | |
970 | /* note: if valid != 0, port == 0, check canonical entry */ | |
971 | struct service_byname *canon; /* if NULL, this is canonical */ | |
972 | uint16_t port; | |
973 | unsigned int valid : 1; | |
974 | unsigned int srv : 1; | |
975 | } protos[SERVICE_NUM_PROTOS]; | |
976 | }; | |
977 | ||
978 | struct service_byport { | |
979 | unsigned int port; | |
980 | char port_text[6]; | |
981 | struct service_byname *byname[SERVICE_NUM_PROTOS]; | |
982 | }; | |
983 | ||
984 | static dict_t services_byname; /* contains struct service_byname */ | |
985 | static dict_t services_byport; /* contains struct service_byport */ | |
986 | ||
987 | static struct service_byname * | |
988 | sar_service_byname(const char *name, int autocreate) | |
989 | { | |
990 | struct service_byname *byname; | |
991 | ||
992 | byname = dict_find(services_byname, name, NULL); | |
993 | if (!byname && autocreate) { | |
994 | byname = calloc(1, sizeof(*byname) + strlen(name) + 1); | |
995 | byname->name = strcpy((char*)(byname + 1), name); | |
996 | dict_insert(services_byname, byname->name, byname); | |
997 | } | |
998 | return byname; | |
999 | } | |
1000 | ||
1001 | static struct service_byport * | |
1002 | sar_service_byport(unsigned int port, int autocreate) | |
1003 | { | |
1004 | struct service_byport *byport; | |
1005 | char port_text[12]; | |
1006 | ||
1007 | sprintf(port_text, "%d", port); | |
1008 | byport = dict_find(services_byport, port_text, NULL); | |
1009 | if (!byport && autocreate) { | |
1010 | byport = calloc(1, sizeof(*byport)); | |
1011 | byport->port = port; | |
1012 | sprintf(byport->port_text, "%d", port); | |
1013 | dict_insert(services_byport, byport->port_text, byport); | |
1014 | } | |
1015 | return byport; | |
1016 | } | |
1017 | ||
1018 | static void | |
1019 | sar_services_load_file(const char *etc_services) | |
1020 | { | |
1021 | static const char *whitespace = " \t\r\n"; | |
1022 | struct service_byname *canon; | |
1023 | struct service_byport *byport; | |
1024 | char *name, *port, *alias, *ptr; | |
1025 | FILE *file; | |
1026 | unsigned int pnum; | |
1027 | enum service_proto proto; | |
1028 | char linebuf[LINE_MAX]; | |
1029 | ||
1030 | file = fopen(etc_services, "r"); | |
1031 | if (!file) | |
1032 | return; | |
1033 | while (fgets(linebuf, sizeof(linebuf), file)) { | |
1034 | ptr = strchr(linebuf, '#'); | |
1035 | if (ptr) | |
1036 | *ptr = '\0'; | |
1037 | /* Tokenize canonical service name and port number. */ | |
1038 | name = strtok_r(linebuf, whitespace, &ptr); | |
1039 | if (name == NULL) | |
1040 | continue; | |
1041 | port = strtok_r(NULL, whitespace, &ptr); | |
1042 | if (port == NULL) | |
1043 | continue; | |
1044 | pnum = strtoul(port, &port, 10); | |
1045 | if (pnum == 0 || *port++ != '/') | |
1046 | continue; | |
1047 | if (!strcmp(port, "udp")) | |
1048 | proto = SERVICE_UDP; | |
1049 | else if (!strcmp(port, "tcp")) | |
1050 | proto = SERVICE_TCP; | |
1051 | else continue; | |
1052 | ||
1053 | /* Set up canonical name-indexed service entry. */ | |
1054 | canon = sar_service_byname(name, 1); | |
1055 | if (canon->protos[proto].valid) { | |
63e4abc0 | 1056 | /* log_module(sar_log, LOG_ERROR, "Service %s/%s listed twice.", name, port); who cares? */ |
1136f709 | 1057 | continue; |
1058 | } | |
1059 | canon->protos[proto].canon = NULL; | |
1060 | canon->protos[proto].port = pnum; | |
1061 | canon->protos[proto].valid = 1; | |
1062 | ||
1063 | /* Set up port-indexed service entry. */ | |
1064 | byport = sar_service_byport(pnum, 1); | |
1065 | if (!byport->byname[proto]) | |
1066 | byport->byname[proto] = canon; | |
1067 | ||
1068 | /* Add alias entries. */ | |
1069 | while ((alias = strtok_r(NULL, whitespace, &ptr))) { | |
1070 | struct service_byname *byname; | |
1071 | ||
1072 | byname = sar_service_byname(alias, 1); | |
1073 | if (byname->protos[proto].valid) { | |
1074 | /* We do not log this since there are a lot of | |
1075 | * duplicate aliases, some only differing in case. */ | |
1076 | continue; | |
1077 | } | |
1078 | byname->protos[proto].canon = canon; | |
1079 | byname->protos[proto].port = pnum; | |
1080 | byname->protos[proto].valid = 1; | |
1081 | } | |
1082 | } | |
1083 | fclose(file); | |
1084 | } | |
1085 | ||
1086 | static void | |
1087 | sar_services_init(const char *etc_services) | |
1088 | { | |
1089 | /* These are a portion of the services listed at | |
1090 | * http://www.dns-sd.org/ServiceTypes.html. | |
1091 | */ | |
1092 | static const char *tcp_srvs[] = { "cvspserver", "distcc", "ftp", "http", | |
1093 | "imap", "ipp", "irc", "ldap", "login", "nfs", "pop3", "postgresql", | |
1094 | "rsync", "sftp-ssh", "soap", "ssh", "telnet", "webdav", "xmpp-client", | |
1095 | "xmpp-server", "xul-http", NULL }; | |
1096 | static const char *udp_srvs[] = { "bootps", "dns-update", "domain", "nfs", | |
1097 | "ntp", "tftp", NULL }; | |
1098 | struct service_byname *byname; | |
1099 | unsigned int ii; | |
1100 | ||
1101 | /* Forget old services dicts and allocate new ones. */ | |
1102 | dict_delete(services_byname); | |
1103 | services_byname = dict_new(); | |
1104 | dict_set_free_data(services_byname, free); | |
1105 | ||
1106 | dict_delete(services_byport); | |
1107 | services_byport = dict_new(); | |
1108 | dict_set_free_data(services_byport, free); | |
1109 | ||
1110 | /* Load the list from the services file. */ | |
1111 | sar_services_load_file(etc_services); | |
1112 | ||
1113 | /* Mark well-known services as using DNS-SD SRV records. */ | |
1114 | for (ii = 0; tcp_srvs[ii]; ++ii) { | |
1115 | byname = sar_service_byname(tcp_srvs[ii], 1); | |
1116 | byname->protos[SERVICE_TCP].srv = 1; | |
1117 | } | |
1118 | ||
1119 | for (ii = 0; udp_srvs[ii]; ++ii) { | |
1120 | byname = sar_service_byname(udp_srvs[ii], 1); | |
1121 | byname->protos[SERVICE_UDP].srv = 1; | |
1122 | } | |
1123 | } | |
1124 | ||
1125 | static void | |
1126 | sar_register_helper(struct sar_family_helper *helper) | |
1127 | { | |
1128 | assert(helper->family <= MAX_FAMILY); | |
1129 | sar_helpers[helper->family] = helper; | |
1130 | helper->next = sar_first_helper; | |
1131 | sar_first_helper = helper; | |
1132 | } | |
1133 | ||
1136f709 | 1134 | struct sar_getaddr_state { |
1135 | struct sar_family_helper *helper; | |
1136 | struct addrinfo *ai_head; | |
1137 | struct addrinfo *ai_tail; | |
1138 | sar_addr_cb cb; | |
1139 | void *cb_ctx; | |
1140 | unsigned int search_pos; | |
1141 | unsigned int flags, socktype, protocol, port; | |
1142 | unsigned int srv_ofs; | |
1143 | char full_name[DNS_NAME_LENGTH]; | |
1144 | }; | |
1145 | ||
1146 | static unsigned int | |
1147 | sar_getaddr_append(struct sar_getaddr_state *state, struct addrinfo *ai, int copy) | |
1148 | { | |
1149 | unsigned int count; | |
1150 | ||
1151 | log_module(sar_log, LOG_DEBUG, "sar_getaddr_append({full_name=%s}, ai=%p, copy=%d)", state->full_name, (void*)ai, copy); | |
1152 | ||
1153 | /* Set the appropriate pointer to the new element(s). */ | |
1154 | if (state->ai_tail) | |
1155 | state->ai_tail->ai_next = ai; | |
1156 | else | |
1157 | state->ai_head = ai; | |
1158 | ||
1159 | /* Find the end of the list. */ | |
1160 | if (copy) { | |
1161 | /* Make sure we copy fields for both the first and last entries. */ | |
1162 | count = 1; | |
1163 | while (1) { | |
1164 | if (!ai->ai_addrlen) { | |
1165 | assert(sar_helpers[ai->ai_family]); | |
1166 | ai->ai_addrlen = sar_helpers[ai->ai_family]->socklen; | |
1167 | } | |
1168 | #if defined(HAVE_SOCKADDR_SA_LEN) | |
1169 | ai->ai_addr->sa_len = ai->ai_addrlen; | |
1170 | #endif | |
1171 | ai->ai_addr->sa_family = ai->ai_family; | |
1172 | ai->ai_socktype = state->socktype; | |
1173 | ai->ai_protocol = state->protocol; | |
1174 | if (!ai->ai_next) | |
1175 | break; | |
1176 | count++; | |
1177 | ai = ai->ai_next; | |
1178 | } | |
1179 | } else { | |
1180 | for (count = 1; ai->ai_next; ++count, ai = ai->ai_next) | |
1181 | ; | |
1182 | } | |
1183 | ||
1184 | /* Set the tail pointer and return count of appended items. */ | |
1185 | state->ai_tail = ai; | |
1186 | return count; | |
1187 | } | |
1188 | ||
1189 | static struct sar_request * | |
1190 | sar_getaddr_request(struct sar_request *req) | |
1191 | { | |
1192 | struct sar_getaddr_state *state; | |
1193 | unsigned int len; | |
1194 | char full_name[DNS_NAME_LENGTH]; | |
1195 | ||
1196 | state = (struct sar_getaddr_state*)(req + 1); | |
1197 | ||
1198 | /* If we can and should, append the current search domain. */ | |
1199 | if (state->search_pos < conf.sar_search->used) | |
1200 | snprintf(full_name, sizeof(full_name), "%s.%s", state->full_name, conf.sar_search->list[state->search_pos]); | |
1201 | else if (state->search_pos == conf.sar_search->used) | |
1202 | safestrncpy(full_name, state->full_name, sizeof(full_name)); | |
1203 | else { | |
1204 | log_module(sar_log, LOG_DEBUG, "sar_getaddr_request({id=%d}): failed", req->id); | |
1205 | state->cb(state->cb_ctx, NULL, SAI_NONAME); | |
1206 | return NULL; | |
1207 | } | |
1208 | ||
1209 | /* Build the appropriate request for DNS record(s). */ | |
1210 | if (state->flags & SAI_ALL) | |
1211 | len = sar_request_build(req, full_name + state->srv_ofs, REQ_QTYPE_ALL, NULL); | |
1212 | else if (state->srv_ofs) | |
1213 | len = state->helper->build_addr_request(req, full_name + state->srv_ofs, full_name, state->flags); | |
1214 | else | |
1215 | len = state->helper->build_addr_request(req, full_name, NULL, state->flags); | |
1216 | ||
1217 | log_module(sar_log, LOG_DEBUG, "sar_getaddr_request({id=%d}): full_name=%s, srv_ofs=%d", req->id, full_name, state->srv_ofs); | |
1218 | ||
1219 | /* Check that the request could be built. */ | |
1220 | if (!len) { | |
1221 | state->cb(state->cb_ctx, NULL, SAI_NODATA); | |
1222 | return NULL; | |
1223 | } | |
1224 | ||
1225 | /* Send the request. */ | |
1226 | sar_request_send(req); | |
1227 | return req; | |
1228 | } | |
1229 | ||
1230 | static int | |
1231 | sar_getaddr_decode(struct sar_request *req, struct dns_header *hdr, struct dns_rr *rr, unsigned char *raw, unsigned int raw_size, unsigned int rr_idx) | |
1232 | { | |
1233 | struct sar_getaddr_state *state; | |
1234 | char *cname; | |
1235 | unsigned int jj, pos, hit; | |
1236 | ||
1237 | log_module(sar_log, LOG_DEBUG, " sar_getaddr_decode(id=%d, <hdr>, {type=%d, rdlength=%d, name=%s}, <data>, %u, <idx>)", hdr->id, rr[rr_idx].type, rr[rr_idx].rdlength, rr[rr_idx].name, raw_size); | |
1238 | state = (struct sar_getaddr_state*)(req + 1); | |
1239 | ||
1240 | switch (rr[rr_idx].type) { | |
1241 | case REQ_TYPE_A: | |
1242 | if (state->flags & SAI_ALL) | |
1243 | return sar_ipv4_helper.decode_addr(state, rr + rr_idx, raw, raw_size); | |
1244 | #if defined(AF_INET6) | |
1245 | else if (state->flags & SAI_V4MAPPED) | |
1246 | return sar_ipv6_helper.decode_addr(state, rr + rr_idx, raw, raw_size); | |
1247 | #endif | |
1248 | return state->helper->decode_addr(state, rr + rr_idx, raw, raw_size); | |
1249 | ||
1250 | case REQ_TYPE_AAAA: | |
1251 | #if defined(AF_INET6) | |
1252 | if (state->flags & SAI_ALL) | |
1253 | return sar_ipv6_helper.decode_addr(state, rr + rr_idx, raw, raw_size); | |
1254 | return state->helper->decode_addr(state, rr + rr_idx, raw, raw_size); | |
1255 | #else | |
1256 | return 0; | |
1257 | #endif | |
1258 | ||
1259 | case REQ_TYPE_CNAME: | |
1260 | /* there should be the canonical name next */ | |
1261 | pos = rr[rr_idx].rd_start; | |
1262 | cname = sar_extract_name(raw, raw_size, &pos); | |
1263 | if (!cname) | |
1264 | return 0; /* XXX: eventually log the unhandled body */ | |
1265 | /* and it should correspond to some other answer in the response */ | |
1266 | for (jj = hit = 0; jj < hdr->ancount; ++jj) { | |
1267 | if (strcasecmp(cname, rr[jj].name)) | |
1268 | continue; | |
1269 | hit += sar_getaddr_decode(req, hdr, rr, raw, raw_size, jj); | |
1270 | } | |
1271 | /* XXX: if (!hit) handle or log the incomplete recursion; */ | |
1272 | return hit; | |
1273 | ||
1274 | case REQ_TYPE_SRV: | |
1275 | /* TODO: decode the SRV record */ | |
1276 | ||
1277 | default: | |
1278 | return 0; | |
1279 | } | |
1280 | } | |
1281 | ||
1282 | static void | |
1283 | sar_getaddr_ok(struct sar_request *req, struct dns_header *hdr, struct dns_rr *rr, unsigned char *raw, unsigned int raw_size) | |
1284 | { | |
1285 | struct sar_getaddr_state *state; | |
1286 | unsigned int ii; | |
1287 | ||
1288 | state = (struct sar_getaddr_state*)(req + 1); | |
1289 | ||
1290 | log_module(sar_log, LOG_DEBUG, "sar_getaddr_ok({id=%d}, {id=%d}, <rr>, <data>, %u)", req->id, hdr->id, raw_size); | |
1291 | for (ii = 0; ii < hdr->ancount; ++ii) | |
1292 | sar_getaddr_decode(req, hdr, rr, raw, raw_size, ii); | |
1293 | ||
1294 | /* If we found anything, report it, else try again. */ | |
1295 | if (state->ai_head) | |
1296 | state->cb(state->cb_ctx, state->ai_head, SAI_SUCCESS); | |
1297 | else | |
1298 | sar_getaddr_request(req); | |
1299 | } | |
1300 | ||
1301 | static void | |
1302 | sar_getaddr_fail(struct sar_request *req, UNUSED_ARG(unsigned int rcode)) | |
1303 | { | |
1304 | struct sar_getaddr_state *state; | |
1305 | ||
1306 | log_module(sar_log, LOG_DEBUG, "sar_getaddr_fail({id=%d}, rcode=%u)", req->id, rcode); | |
1307 | state = (struct sar_getaddr_state*)(req + 1); | |
1308 | state->cb(state->cb_ctx, NULL, SAI_FAIL); | |
1309 | } | |
1310 | ||
1311 | struct sar_request * | |
1312 | sar_getaddr(const char *node, const char *service, const struct addrinfo *hints_, sar_addr_cb cb, void *cb_ctx) | |
1313 | { | |
1136f709 | 1314 | struct addrinfo hints; |
1315 | struct sar_family_helper *helper; | |
1316 | struct service_byname *svc; | |
1317 | char *end; | |
8536ac6b | 1318 | void *ss; |
1319 | size_t ss_len; | |
1136f709 | 1320 | unsigned int portnum; |
1321 | unsigned int pos; | |
1322 | enum service_proto proto; | |
1323 | ||
1324 | if (!node && !service) { | |
1325 | cb(cb_ctx, NULL, SAI_NONAME); | |
1326 | return NULL; | |
1327 | } | |
1328 | ||
1329 | /* Initialize local hints structure. */ | |
1330 | if (hints_) | |
1331 | memcpy(&hints, hints_, sizeof(hints)); | |
1332 | else | |
1333 | memset(&hints, 0, sizeof(hints)); | |
1334 | ||
1335 | /* Translate socket type to internal protocol. */ | |
1336 | switch (hints.ai_socktype) { | |
1337 | case 0: hints.ai_socktype = SOCK_STREAM; /* and fall through */ | |
1338 | case SOCK_STREAM: proto = SERVICE_TCP; break; | |
1339 | case SOCK_DGRAM: proto = SERVICE_UDP; break; | |
1340 | default: | |
1341 | cb(cb_ctx, NULL, SAI_SOCKTYPE); | |
1342 | return NULL; | |
1343 | } | |
1344 | ||
1345 | /* Figure out preferred socket size. */ | |
1346 | if (hints.ai_family == AF_UNSPEC) | |
1347 | hints.ai_family = AF_INET; | |
1348 | if (hints.ai_family > MAX_FAMILY | |
1349 | || !(helper = sar_helpers[hints.ai_family])) { | |
1350 | cb(cb_ctx, NULL, SAI_FAMILY); | |
1351 | return NULL; | |
1352 | } | |
1353 | hints.ai_addrlen = helper->socklen; | |
1354 | ||
1355 | /* If \a node is NULL, figure out the correct default from the | |
1356 | * requested family and SAI_PASSIVE flag. | |
1357 | */ | |
1358 | if (node == NULL) | |
1359 | node = (hints.ai_flags & SAI_PASSIVE) ? helper->unspec_addr : helper->localhost_addr; | |
1360 | ||
1361 | /* Try to parse (failing that, look up) \a service. */ | |
1362 | if (!service) | |
1363 | portnum = 0, svc = NULL; | |
1364 | else if ((portnum = strtoul(service, &end, 10)), *end == '\0') | |
1365 | svc = NULL; | |
1366 | else if ((svc = sar_service_byname(service, 0)) != NULL) | |
1367 | portnum = svc->protos[proto].port; | |
1368 | else { | |
1369 | cb(cb_ctx, NULL, SAI_SERVICE); | |
1370 | return NULL; | |
1371 | } | |
1372 | ||
1373 | /* Try to parse \a node as a numeric hostname.*/ | |
8536ac6b | 1374 | ss_len = sizeof(struct sockaddr_storage); |
1375 | ss = alloca(ss_len); | |
1376 | pos = sar_pton((struct sockaddr*)ss, ss_len, NULL, node); | |
1136f709 | 1377 | if (pos && node[pos] == '\0') { |
1378 | struct addrinfo *ai; | |
1379 | char canonname[SAR_NTOP_MAX]; | |
1380 | ||
1381 | /* we have a valid address; use it */ | |
8536ac6b | 1382 | sar_set_port((struct sockaddr*)ss, ss_len, portnum); |
1383 | hints.ai_addrlen = sar_addrlen((struct sockaddr*)ss, ss_len); | |
1136f709 | 1384 | if (!hints.ai_addrlen) { |
1385 | cb(cb_ctx, NULL, SAI_FAMILY); | |
1386 | return NULL; | |
1387 | } | |
8536ac6b | 1388 | pos = sar_ntop(canonname, sizeof(canonname), (struct sockaddr*)ss, hints.ai_addrlen); |
1136f709 | 1389 | |
1390 | /* allocate and fill in the addrinfo response */ | |
1391 | ai = calloc(1, sizeof(*ai) + hints.ai_addrlen + pos + 1); | |
8536ac6b | 1392 | ai->ai_family = ((struct sockaddr*)ss)->sa_family; |
1136f709 | 1393 | ai->ai_socktype = hints.ai_socktype; |
1394 | ai->ai_protocol = hints.ai_protocol; | |
1395 | ai->ai_addrlen = hints.ai_addrlen; | |
8536ac6b | 1396 | ai->ai_addr = memcpy(ai + 1, ss, ai->ai_addrlen); |
1136f709 | 1397 | ai->ai_canonname = strcpy((char*)ai->ai_addr + ai->ai_addrlen, canonname); |
1398 | cb(cb_ctx, ai, SAI_SUCCESS); | |
1399 | return NULL; | |
1400 | } else if (hints.ai_flags & SAI_NUMERICHOST) { | |
1401 | cb(cb_ctx, NULL, SAI_NONAME); | |
1402 | return NULL; | |
1403 | } else { | |
1404 | struct sar_request *req; | |
1405 | struct sar_getaddr_state *state; | |
1406 | unsigned int len, ii; | |
1407 | ||
1408 | req = sar_request_alloc(sizeof(*state), sar_getaddr_ok, sar_getaddr_fail); | |
1409 | ||
1410 | state = (struct sar_getaddr_state*)(req + 1); | |
1411 | state->helper = helper; | |
1412 | state->ai_head = state->ai_tail = NULL; | |
1413 | state->cb = cb; | |
1414 | state->cb_ctx = cb_ctx; | |
1415 | state->flags = hints.ai_flags; | |
1416 | state->socktype = hints.ai_socktype; | |
1417 | state->protocol = hints.ai_protocol; | |
1418 | state->port = portnum; | |
1419 | ||
1420 | if ((state->flags & SAI_NOSRV) || !svc) | |
1421 | state->srv_ofs = 0; | |
1422 | else if (svc->protos[proto].srv) | |
1423 | state->srv_ofs = snprintf(state->full_name, sizeof(state->full_name), "_%s._%s.", svc->name, (proto == SERVICE_UDP ? "udp" : "tcp")); | |
1424 | else if (state->flags & SAI_FORCESRV) | |
1425 | state->srv_ofs = snprintf(state->full_name, sizeof(state->full_name), "_%s._%s.", service, (proto == SERVICE_UDP ? "udp" : "tcp")); | |
1426 | else | |
1427 | state->srv_ofs = 0; | |
1428 | ||
1429 | if (state->srv_ofs < sizeof(state->full_name)) | |
1430 | safestrncpy(state->full_name + state->srv_ofs, node, sizeof(state->full_name) - state->srv_ofs); | |
1431 | ||
1432 | for (ii = len = 0; node[ii]; ++ii) | |
1433 | if (node[ii] == '.') | |
1434 | len++; | |
1435 | if (len >= conf.sar_ndots) | |
1436 | state->search_pos = conf.sar_search->used; | |
1437 | else | |
1438 | state->search_pos = 0; | |
1439 | ||
1440 | /* XXX: fill in *state with any other fields needed to parse responses. */ | |
1441 | ||
1442 | if (!sar_getaddr_request(req)) { | |
1443 | free(req); | |
1444 | return NULL; | |
1445 | } | |
1446 | return req; | |
1447 | } | |
1448 | } | |
1449 | ||
1450 | struct sar_getname_state { | |
1451 | sar_name_cb cb; | |
1452 | void *cb_ctx; | |
1453 | char *hostname; | |
1454 | unsigned int flags; | |
1455 | unsigned int family; | |
1456 | enum service_proto proto; | |
1457 | unsigned short port; | |
1458 | unsigned int doing_arpa : 1; /* checking .ip6.arpa vs .ip6.int */ | |
1459 | unsigned char original[16]; /* original address data */ | |
1460 | /* name must be long enough to hold "0.0.<etc>.ip6.arpa" */ | |
1461 | char name[74]; | |
1462 | }; | |
1463 | ||
1464 | static void | |
1465 | sar_getname_fail(struct sar_request *req, UNUSED_ARG(unsigned int rcode)) | |
1466 | { | |
1467 | struct sar_getname_state *state; | |
1468 | unsigned int len; | |
1469 | ||
1470 | state = (struct sar_getname_state*)(req + 1); | |
1471 | if (state->doing_arpa) { | |
1472 | len = strlen(state->name); | |
1473 | assert(len == 73); | |
1474 | strcpy(state->name + len - 4, "int"); | |
1475 | len = sar_request_build(req, state->name, REQ_TYPE_PTR, NULL); | |
1476 | if (len) { | |
1477 | sar_request_send(req); | |
1478 | return; | |
1479 | } | |
1480 | } | |
1481 | state->cb(state->cb_ctx, NULL, NULL, SAI_FAIL); | |
1482 | free(state->hostname); | |
1483 | } | |
1484 | ||
1485 | static const char *sar_getname_port(unsigned int port, unsigned int flags, char *tmpbuf, unsigned int tmpbuf_len) | |
1486 | { | |
1487 | struct service_byport *service; | |
1488 | enum service_proto proto; | |
1489 | char port_text[12]; | |
1490 | ||
1491 | sprintf(port_text, "%d", port); | |
1492 | proto = (flags & SNI_DGRAM) ? SERVICE_UDP : SERVICE_TCP; | |
1493 | if (!(flags & SNI_NUMERICSERV) | |
1494 | && (service = dict_find(services_byport, port_text, NULL)) | |
1495 | && service->byname[proto]) | |
1496 | return service->byname[proto]->name; | |
1497 | snprintf(tmpbuf, tmpbuf_len, "%d", port); | |
1498 | return tmpbuf; | |
1499 | } | |
1500 | ||
1501 | static void | |
1502 | sar_getname_confirm(struct sar_request *req, struct dns_header *hdr, struct dns_rr *rr, unsigned char *raw, unsigned int raw_size) | |
1503 | { | |
1504 | struct sar_getname_state *state; | |
1505 | const unsigned char *data; | |
1506 | const char *portname; | |
1507 | char servbuf[16]; | |
1508 | unsigned int ii, nbr; | |
1509 | ||
1510 | state = (struct sar_getname_state*)(req + 1); | |
1511 | for (ii = 0; ii < hdr->ancount; ++ii) { | |
1512 | /* Is somebody confused or trying to play games? */ | |
1513 | if (rr[ii].class != REQ_CLASS_IN | |
1514 | || strcasecmp(state->hostname, rr[ii].name)) | |
1515 | continue; | |
1516 | switch (rr[ii].type) { | |
1517 | case REQ_TYPE_A: nbr = 4; break; | |
1518 | case REQ_TYPE_AAAA: nbr = 16; break; | |
1519 | default: continue; | |
1520 | } | |
1521 | data = sar_extract_rdata(rr, nbr, raw, raw_size); | |
1522 | if (data && !memcmp(data, state->original, nbr)) { | |
1523 | portname = sar_getname_port(state->port, state->flags, servbuf, sizeof(servbuf)); | |
1524 | state->cb(state->cb_ctx, state->hostname, portname, SAI_SUCCESS); | |
1525 | free(state->hostname); | |
1526 | return; | |
1527 | } | |
1528 | } | |
1529 | state->cb(state->cb_ctx, NULL, NULL, SAI_MISMATCH); | |
1530 | free(state->hostname); | |
1531 | } | |
1532 | ||
1533 | static void | |
1534 | sar_getname_ok(struct sar_request *req, struct dns_header *hdr, struct dns_rr *rr, unsigned char *raw, unsigned int raw_size) | |
1535 | { | |
1536 | struct sar_getname_state *state; | |
1537 | const char *portname; | |
1538 | unsigned int ii, pos; | |
1539 | char servbuf[16]; | |
1540 | ||
1541 | state = (struct sar_getname_state*)(req + 1); | |
1542 | for (ii = 0; ii < hdr->ancount; ++ii) { | |
1543 | if (rr[ii].type != REQ_TYPE_PTR | |
1544 | || rr[ii].class != REQ_CLASS_IN | |
1545 | || strcasecmp(rr[ii].name, state->name)) | |
1546 | continue; | |
1547 | pos = rr[ii].rd_start; | |
1548 | state->hostname = sar_extract_name(raw, raw_size, &pos); | |
1549 | break; | |
1550 | } | |
1551 | ||
1552 | if (!state->hostname) { | |
1553 | state->cb(state->cb_ctx, NULL, NULL, SAI_NONAME); | |
1554 | return; | |
1555 | } | |
1556 | ||
1557 | if (state->flags & SNI_PARANOID) { | |
1558 | req->cb_ok = sar_getname_confirm; | |
1559 | pos = sar_helpers[state->family]->build_addr_request(req, state->hostname, NULL, 0); | |
1560 | if (pos) | |
1561 | sar_request_send(req); | |
1562 | else { | |
1563 | free(state->hostname); | |
1564 | state->cb(state->cb_ctx, NULL, NULL, SAI_FAIL); | |
1565 | } | |
1566 | return; | |
1567 | } | |
1568 | ||
1569 | portname = sar_getname_port(state->port, state->flags, servbuf, sizeof(servbuf)); | |
1570 | state->cb(state->cb_ctx, state->hostname, portname, SAI_SUCCESS); | |
1571 | free(state->hostname); | |
1572 | } | |
1573 | ||
1574 | struct sar_request * | |
1575 | sar_getname(const struct sockaddr *sa, unsigned int salen, int flags, sar_name_cb cb, void *cb_ctx) | |
1576 | { | |
1577 | struct sar_family_helper *helper; | |
1578 | struct sar_request *req; | |
1579 | struct sar_getname_state *state; | |
1580 | unsigned int len; | |
1581 | int port; | |
1582 | ||
1583 | if (sa->sa_family > MAX_FAMILY | |
1584 | || !(helper = sar_helpers[sa->sa_family])) { | |
1585 | cb(cb_ctx, NULL, NULL, SAI_FAMILY); | |
1586 | return NULL; | |
1587 | } | |
1588 | ||
1589 | port = helper->get_port(sa, salen); | |
1590 | ||
1591 | if (flags & SNI_NUMERICHOST) { | |
1592 | const char *servname; | |
1593 | char host[SAR_NTOP_MAX], servbuf[16]; | |
1594 | ||
1595 | /* If appropriate, try to look up service name. */ | |
1596 | servname = sar_getname_port(port, flags, servbuf, sizeof(servbuf)); | |
1597 | len = sar_ntop(host, sizeof(host), sa, salen); | |
1598 | assert(len != 0); | |
1599 | cb(cb_ctx, host, servname, SAI_SUCCESS); | |
1600 | return NULL; | |
1601 | } | |
1602 | ||
1603 | req = sar_request_alloc(sizeof(*state), sar_getname_ok, sar_getname_fail); | |
1604 | ||
1605 | state = (struct sar_getname_state*)(req + 1); | |
1606 | state->cb = cb; | |
1607 | state->cb_ctx = cb_ctx; | |
1608 | state->flags = flags; | |
1609 | state->family = sa->sa_family; | |
1610 | state->port = port; | |
1611 | ||
1612 | helper->build_ptr_name(state, sa, salen); | |
1613 | assert(strlen(state->name) < sizeof(state->name)); | |
1614 | len = sar_request_build(req, state->name, REQ_TYPE_PTR, NULL); | |
1615 | if (!len) { | |
1616 | cb(cb_ctx, NULL, NULL, SAI_NODATA); | |
1617 | free(req); | |
1618 | return NULL; | |
1619 | } | |
1620 | ||
1621 | sar_request_send(req); | |
1622 | return req; | |
1623 | } | |
1624 | ||
1625 | static unsigned int | |
1626 | ipv4_ntop(char *output, unsigned int out_size, const struct sockaddr *sa, UNUSED_ARG(unsigned int socklen)) | |
1627 | { | |
1628 | struct sockaddr_in *sin; | |
1629 | unsigned int ip4, pos; | |
1630 | ||
1631 | sin = (struct sockaddr_in*)sa; | |
1632 | ip4 = ntohl(sin->sin_addr.s_addr); | |
1633 | pos = snprintf(output, out_size, "%u.%u.%u.%u", (ip4 >> 24), (ip4 >> 16) & 255, (ip4 >> 8) & 255, ip4 & 255); | |
1634 | return (pos < out_size) ? pos : 0; | |
1635 | } | |
1636 | ||
1637 | static unsigned int | |
1638 | sar_pton_ip4(const char *input, unsigned int *bits, uint32_t *output) | |
1639 | { | |
1640 | unsigned int dots = 0, pos = 0, part = 0, ip = 0; | |
1641 | ||
1642 | /* Intentionally no support for bizarre IPv4 formats (plain | |
1643 | * integers, octal or hex components) -- only vanilla dotted | |
1644 | * decimal quads, optionally with trailing /nn. | |
1645 | */ | |
1646 | if (input[0] == '.') | |
1647 | return 0; | |
1648 | while (1) { | |
1649 | if (isdigit(input[pos])) { | |
1650 | part = part * 10 + input[pos++] - '0'; | |
1651 | if (part > 255) | |
1652 | return 0; | |
1653 | if ((dots == 3) && !isdigit(input[pos])) { | |
1654 | *output = htonl(ip | part); | |
1655 | return pos; | |
1656 | } | |
1657 | } else if (input[pos] == '.') { | |
1658 | if (input[++pos] == '.') | |
1659 | return 0; | |
1660 | ip |= part << (24 - 8 * dots++); | |
1661 | part = 0; | |
1662 | } else if (bits && input[pos] == '/' && isdigit(input[pos + 1])) { | |
1663 | unsigned int len; | |
1664 | char *term; | |
1665 | ||
1666 | len = strtoul(input + pos + 1, &term, 10); | |
1667 | if (term <= input + pos + 1) | |
1668 | return pos; | |
1669 | else if (len > 32) | |
1670 | return 0; | |
1671 | *bits = len; | |
1672 | return term - input; | |
1673 | } else return 0; | |
1674 | } | |
1675 | } | |
1676 | ||
1677 | static unsigned int | |
1678 | ipv4_pton(struct sockaddr *sa, UNUSED_ARG(unsigned int socklen), unsigned int *bits, const char *input) | |
1679 | { | |
1680 | unsigned int pos; | |
1681 | ||
1682 | pos = sar_pton_ip4(input, bits, &((struct sockaddr_in*)sa)->sin_addr.s_addr); | |
1683 | if (!pos) | |
1684 | return 0; | |
1685 | sa->sa_family = AF_INET; | |
e9df2b7d | 1686 | #if defined(HAVE_SOCKADDR_SA_LEN) |
1687 | sa->sa_len = sizeof(struct sockaddr_in); | |
1688 | #endif | |
1136f709 | 1689 | return pos; |
1690 | } | |
1691 | ||
1692 | static int | |
1693 | ipv4_get_port(const struct sockaddr *sa, UNUSED_ARG(unsigned int socklen)) | |
1694 | { | |
1695 | return ntohs(((const struct sockaddr_in*)sa)->sin_port); | |
1696 | } | |
1697 | ||
1698 | static int | |
1699 | ipv4_set_port(struct sockaddr *sa, UNUSED_ARG(unsigned int socklen), unsigned short port) | |
1700 | { | |
1701 | ((struct sockaddr_in*)sa)->sin_port = htons(port); | |
1702 | return 0; | |
1703 | } | |
1704 | ||
1705 | static unsigned int | |
1706 | ipv4_addr_request(struct sar_request *req, const char *node, const char *srv_node, UNUSED_ARG(unsigned int flags)) | |
1707 | { | |
1708 | unsigned int len; | |
1709 | if (srv_node) | |
1710 | len = sar_request_build(req, node, REQ_TYPE_A, srv_node, REQ_TYPE_SRV, NULL); | |
1711 | else | |
1712 | len = sar_request_build(req, node, REQ_TYPE_A, NULL); | |
1713 | return len; | |
1714 | } | |
1715 | ||
1716 | static void | |
1717 | ipv4_ptr_name(struct sar_getname_state *state, const struct sockaddr *sa, UNUSED_ARG(unsigned int socklen)) | |
1718 | { | |
1719 | const uint8_t *bytes; | |
1720 | ||
1721 | bytes = (uint8_t*)&((struct sockaddr_in*)sa)->sin_addr.s_addr; | |
1722 | memcpy(state->original, bytes, 4); | |
1723 | snprintf(state->name, sizeof(state->name), | |
1724 | "%u.%u.%u.%u.in-addr.arpa", | |
1725 | bytes[3], bytes[2], bytes[1], bytes[0]); | |
1726 | } | |
1727 | ||
1728 | static int | |
1729 | ipv4_decode(struct sar_getaddr_state *state, struct dns_rr *rr, unsigned char *raw, UNUSED_ARG(unsigned int raw_size)) | |
1730 | { | |
1731 | struct sockaddr_in *sa; | |
1732 | struct addrinfo *ai; | |
1733 | ||
1734 | if (rr->rdlength != 4) | |
1735 | return 0; | |
1736 | ||
1737 | if (state->flags & SAI_CANONNAME) { | |
1738 | ai = calloc(1, sizeof(*ai) + sizeof(*sa) + strlen(rr->name) + 1); | |
1739 | sa = (struct sockaddr_in*)(ai->ai_addr = (struct sockaddr*)(ai + 1)); | |
1740 | ai->ai_canonname = strcpy((char*)(sa + 1), rr->name); | |
1741 | } else { | |
1742 | ai = calloc(1, sizeof(*ai) + sizeof(*sa)); | |
1743 | sa = (struct sockaddr_in*)(ai->ai_addr = (struct sockaddr*)(ai + 1)); | |
1744 | ai->ai_canonname = NULL; | |
1745 | } | |
1746 | ||
1747 | ai->ai_family = AF_INET; | |
1748 | sa->sin_port = htons(state->port); | |
1749 | memcpy(&sa->sin_addr.s_addr, raw + rr->rd_start, 4); | |
1750 | return sar_getaddr_append(state, ai, 1); | |
1751 | } | |
1752 | ||
1753 | static struct sar_family_helper sar_ipv4_helper = { | |
1754 | "127.0.0.1", | |
1755 | "0.0.0.0", | |
1756 | sizeof(struct sockaddr_in), | |
1757 | AF_INET, | |
1758 | ipv4_ntop, | |
1759 | ipv4_pton, | |
1760 | ipv4_get_port, | |
1761 | ipv4_set_port, | |
1762 | ipv4_addr_request, | |
1763 | ipv4_ptr_name, | |
1764 | ipv4_decode, | |
1765 | NULL | |
1766 | }; | |
1767 | ||
1768 | #if defined(AF_INET6) | |
1769 | ||
1770 | static unsigned int | |
1771 | ipv6_ntop(char *output, unsigned int out_size, const struct sockaddr *sa, UNUSED_ARG(unsigned int socklen)) | |
1772 | { | |
1773 | struct sockaddr_in6 *sin6; | |
1774 | unsigned int pos, part, max_start, max_zeros, curr_zeros, ii; | |
1775 | unsigned short addr16; | |
1776 | ||
1777 | sin6 = (struct sockaddr_in6*)sa; | |
1778 | /* Find longest run of zeros. */ | |
1779 | for (max_start = max_zeros = curr_zeros = ii = 0; ii < 8; ++ii) { | |
1780 | addr16 = (sin6->sin6_addr.s6_addr[ii * 2] << 8) | sin6->sin6_addr.s6_addr[ii * 2 + 1]; | |
1781 | if (!addr16) | |
1782 | curr_zeros++; | |
1783 | else if (curr_zeros > max_zeros) { | |
1784 | max_start = ii - curr_zeros; | |
1785 | max_zeros = curr_zeros; | |
1786 | curr_zeros = 0; | |
1787 | } | |
1788 | } | |
1789 | if (curr_zeros > max_zeros) { | |
1790 | max_start = ii - curr_zeros; | |
1791 | max_zeros = curr_zeros; | |
1792 | } | |
1793 | ||
1794 | /* Print out address. */ | |
1795 | #define APPEND(CH) do { output[pos++] = (CH); if (pos >= out_size) return 0; } while (0) | |
1796 | for (pos = 0, ii = 0; ii < 8; ++ii) { | |
1797 | if ((max_zeros > 0) && (ii == max_start)) { | |
1798 | if (ii == 0) | |
1799 | APPEND(':'); | |
1800 | APPEND(':'); | |
1801 | ii += max_zeros - 1; | |
1802 | continue; | |
1803 | } | |
1804 | part = (sin6->sin6_addr.s6_addr[ii * 2] << 8) | sin6->sin6_addr.s6_addr[ii * 2 + 1]; | |
1805 | if (part >= 0x1000) | |
1806 | APPEND(hexdigits[part >> 12]); | |
1807 | if (part >= 0x100) | |
1808 | APPEND(hexdigits[(part >> 8) & 15]); | |
1809 | if (part >= 0x10) | |
1810 | APPEND(hexdigits[(part >> 4) & 15]); | |
1811 | APPEND(hexdigits[part & 15]); | |
1812 | if (ii < 7) | |
1813 | APPEND(':'); | |
1814 | } | |
1815 | APPEND('\0'); | |
1816 | #undef APPEND | |
1817 | ||
1818 | return pos; | |
1819 | } | |
1820 | ||
1821 | static const unsigned char xdigit_value[256] = { | |
1822 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | |
1823 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | |
1824 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | |
1825 | 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 0, 0, 0, 0, | |
1826 | 0,10,11,12,13,14,15, 0, 0, 0, 0, 0, 0, 0, 0, 0, | |
1827 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | |
1828 | 0,10,11,12,13,14,15, 0, 0, 0, 0, 0, 0, 0, 0, 0, | |
1829 | }; | |
1830 | ||
1831 | static unsigned int | |
1832 | ipv6_pton(struct sockaddr *sa, UNUSED_ARG(unsigned int socklen), unsigned int *bits, const char *input) | |
1833 | { | |
1834 | const char *part_start = NULL; | |
1835 | struct sockaddr_in6 *sin6; | |
1836 | char *colon; | |
1837 | char *dot; | |
1838 | unsigned int part = 0, pos = 0, ii = 0, cpos = 8; | |
1839 | ||
1840 | if (!(colon = strchr(input, ':'))) | |
1841 | return 0; | |
1842 | dot = strchr(input, '.'); | |
1843 | if (dot && dot < colon) | |
1844 | return 0; | |
1845 | sin6 = (struct sockaddr_in6*)sa; | |
1846 | /* Parse IPv6, possibly like ::127.0.0.1. | |
1847 | * This is pretty straightforward; the only trick is borrowed | |
1848 | * from Paul Vixie (BIND): when it sees a "::" continue as if | |
1849 | * it were a single ":", but note where it happened, and fill | |
1850 | * with zeros afterwards. | |
1851 | */ | |
1852 | if (input[pos] == ':') { | |
1853 | if ((input[pos+1] != ':') || (input[pos+2] == ':')) | |
1854 | return 0; | |
1855 | cpos = 0; | |
1856 | pos += 2; | |
1857 | part_start = input + pos; | |
1858 | } | |
1859 | while (ii < 8) { | |
1860 | if (isxdigit(input[pos])) { | |
1861 | part = (part << 4) | xdigit_value[(unsigned char)input[pos]]; | |
1862 | if (part > 0xffff) | |
1863 | return 0; | |
1864 | pos++; | |
1865 | } else if (input[pos] == ':') { | |
1866 | part_start = input + ++pos; | |
1867 | if (input[pos] == '.') | |
1868 | return 0; | |
1869 | sin6->sin6_addr.s6_addr[ii * 2] = part >> 8; | |
1870 | sin6->sin6_addr.s6_addr[ii * 2 + 1] = part & 255; | |
1871 | ii++; | |
1872 | part = 0; | |
1873 | if (input[pos] == ':') { | |
1874 | if (cpos < 8) | |
1875 | return 0; | |
1876 | cpos = ii; | |
1877 | pos++; | |
1878 | } | |
1879 | } else if (input[pos] == '.') { | |
1880 | uint32_t ip4; | |
1881 | unsigned int len; | |
1882 | len = sar_pton_ip4(part_start, bits, &ip4); | |
1883 | if (!len || (ii > 6)) | |
1884 | return 0; | |
1885 | memcpy(sin6->sin6_addr.s6_addr + ii * 2, &ip4, sizeof(ip4)); | |
1886 | if (bits) | |
1887 | *bits += ii * 16; | |
1888 | ii += 2; | |
1889 | pos = part_start + len - input; | |
1890 | break; | |
1891 | } else if (bits && input[pos] == '/' && isdigit(input[pos + 1])) { | |
1892 | unsigned int len; | |
1893 | char *term; | |
1894 | ||
1895 | len = strtoul(input + pos + 1, &term, 10); | |
1896 | if (term <= input + pos + 1) | |
1897 | break; | |
1898 | else if (len > 128) | |
1899 | return 0; | |
1900 | if (bits) | |
1901 | *bits = len; | |
1902 | pos = term - input; | |
1903 | break; | |
1904 | } else if (cpos <= 8) { | |
1905 | sin6->sin6_addr.s6_addr[ii * 2] = part >> 8; | |
1906 | sin6->sin6_addr.s6_addr[ii * 2 + 1] = part & 255; | |
1907 | ii++; | |
1908 | break; | |
1909 | } else return 0; | |
1910 | } | |
1911 | /* Shift stuff after "::" up and fill middle with zeros. */ | |
1912 | if (cpos < 8) { | |
1913 | unsigned int jj; | |
1914 | ii <<= 1; | |
1915 | cpos <<= 1; | |
1916 | for (jj = 0; jj < ii - cpos; jj++) | |
1917 | sin6->sin6_addr.s6_addr[15 - jj] = sin6->sin6_addr.s6_addr[ii - jj - 1]; | |
1918 | for (jj = 0; jj < 16 - ii; jj++) | |
1919 | sin6->sin6_addr.s6_addr[cpos + jj] = 0; | |
1920 | } | |
1921 | sa->sa_family = AF_INET6; | |
e9df2b7d | 1922 | #if defined(HAVE_SOCKADDR_SA_LEN) |
1923 | sa->sa_len = sizeof(struct sockaddr_in6); | |
1924 | #endif | |
1136f709 | 1925 | return pos; |
1926 | } | |
1927 | ||
1928 | static int | |
1929 | ipv6_get_port(const struct sockaddr *sa, UNUSED_ARG(unsigned int socklen)) | |
1930 | { | |
1931 | return ntohs(((const struct sockaddr_in6*)sa)->sin6_port); | |
1932 | } | |
1933 | ||
1934 | static int | |
1935 | ipv6_set_port(struct sockaddr *sa, UNUSED_ARG(unsigned int socklen), unsigned short port) | |
1936 | { | |
1937 | ((struct sockaddr_in6*)sa)->sin6_port = htons(port); | |
1938 | return 0; | |
1939 | } | |
1940 | ||
1941 | static unsigned int | |
1942 | ipv6_addr_request(struct sar_request *req, const char *node, const char *srv_node, unsigned int flags) | |
1943 | { | |
1944 | unsigned int len; | |
1945 | if (flags & SAI_V4MAPPED) { | |
1946 | if (srv_node) | |
1947 | len = sar_request_build(req, node, REQ_TYPE_AAAA, node, REQ_TYPE_A, srv_node, REQ_TYPE_SRV, NULL); | |
1948 | else | |
1949 | len = sar_request_build(req, node, REQ_TYPE_AAAA, node, REQ_TYPE_A, NULL); | |
1950 | } else { | |
1951 | if (srv_node) | |
1952 | len = sar_request_build(req, node, REQ_TYPE_AAAA, srv_node, REQ_TYPE_SRV, NULL); | |
1953 | else | |
1954 | len = sar_request_build(req, node, REQ_TYPE_AAAA, NULL); | |
1955 | } | |
1956 | return len; | |
1957 | } | |
1958 | ||
1959 | static void | |
1960 | ipv6_ptr_name(struct sar_getname_state *state, const struct sockaddr *sa, UNUSED_ARG(unsigned int socklen)) | |
1961 | { | |
1962 | const uint8_t *bytes; | |
1963 | unsigned int ii, jj; | |
1964 | ||
1965 | bytes = ((struct sockaddr_in6*)sa)->sin6_addr.s6_addr; | |
1966 | memcpy(state->original, bytes, 16); | |
1967 | for (jj = 0, ii = 16; ii > 0; ) { | |
1968 | state->name[jj++] = hexdigits[bytes[--ii] & 15]; | |
1969 | state->name[jj++] = hexdigits[bytes[ii] >> 4]; | |
1970 | state->name[jj++] = '.'; | |
1971 | } | |
1972 | strcpy(state->name + jj, ".ip6.arpa"); | |
1973 | state->doing_arpa = 1; | |
1974 | } | |
1975 | ||
1976 | static int | |
1977 | ipv6_decode(struct sar_getaddr_state *state, struct dns_rr *rr, unsigned char *raw, UNUSED_ARG(unsigned int raw_size)) | |
1978 | { | |
1979 | struct sockaddr_in6 *sa; | |
1980 | struct addrinfo *ai; | |
1981 | ||
1982 | if (state->flags & SAI_CANONNAME) { | |
1983 | ai = calloc(1, sizeof(*ai) + sizeof(*sa) + strlen(rr->name) + 1); | |
1984 | sa = (struct sockaddr_in6*)(ai->ai_addr = (struct sockaddr*)(ai + 1)); | |
1985 | ai->ai_canonname = strcpy((char*)(sa + 1), rr->name); | |
1986 | } else { | |
1987 | ai = calloc(1, sizeof(*ai) + sizeof(*sa)); | |
1988 | sa = (struct sockaddr_in6*)(ai->ai_addr = (struct sockaddr*)(ai + 1)); | |
1989 | ai->ai_canonname = NULL; | |
1990 | } | |
1991 | ||
1992 | if (rr->rdlength == 4) { | |
1993 | sa->sin6_addr.s6_addr[10] = sa->sin6_addr.s6_addr[11] = 0xff; | |
1994 | memcpy(sa->sin6_addr.s6_addr + 12, raw + rr->rd_start, 4); | |
1995 | } else if (rr->rdlength == 16) { | |
1996 | memcpy(sa->sin6_addr.s6_addr, raw + rr->rd_start, 16); | |
1997 | } else { | |
1998 | free(ai); | |
1999 | return 0; | |
2000 | } | |
2001 | ||
2002 | ai->ai_family = AF_INET6; | |
2003 | sa->sin6_port = htons(state->port); | |
2004 | return sar_getaddr_append(state, ai, 1); | |
2005 | } | |
2006 | ||
2007 | static struct sar_family_helper sar_ipv6_helper = { | |
2008 | "::1", | |
2009 | "::", | |
2010 | sizeof(struct sockaddr_in6), | |
2011 | AF_INET6, | |
2012 | ipv6_ntop, | |
2013 | ipv6_pton, | |
2014 | ipv6_get_port, | |
2015 | ipv6_set_port, | |
2016 | ipv6_addr_request, | |
2017 | ipv6_ptr_name, | |
2018 | ipv6_decode, | |
2019 | NULL | |
2020 | }; | |
2021 | ||
2022 | #endif /* defined(AF_INET6) */ | |
2023 | ||
2024 | static void | |
30874d66 | 2025 | sar_cleanup(UNUSED_ARG(void *extra)) |
1136f709 | 2026 | { |
2027 | ioset_close(sar_fd, 1); | |
2028 | dict_delete(services_byname); | |
2029 | dict_delete(services_byport); | |
2030 | dict_delete(sar_nameservers); | |
2031 | dict_delete(sar_requests); | |
2032 | free_string_list(conf.sar_search); | |
2033 | free_string_list(conf.sar_nslist); | |
2034 | } | |
2035 | ||
2036 | static void | |
2037 | sar_conf_reload(void) | |
2038 | { | |
2039 | dict_t node; | |
2040 | const char *resolv_conf = "/etc/resolv.conf"; | |
2041 | const char *services = "/etc/services"; | |
2042 | const char *str; | |
2043 | ||
2044 | node = conf_get_data("modules/sar", RECDB_OBJECT); | |
2045 | if (node != NULL) { | |
2046 | str = database_get_data(node, "resolv_conf", RECDB_QSTRING); | |
2047 | if (str) resolv_conf = str; | |
2048 | str = database_get_data(node, "services", RECDB_QSTRING); | |
2049 | if (str) services = str; | |
2050 | } | |
2051 | sar_dns_init(resolv_conf); | |
2052 | sar_services_init(services); | |
2053 | } | |
2054 | ||
2055 | void | |
2056 | sar_init(void) | |
2057 | { | |
8536ac6b | 2058 | conf.sar_bind_address = calloc(1, sizeof(struct sockaddr_storage)); |
30874d66 | 2059 | reg_exit_func(sar_cleanup, NULL); |
1136f709 | 2060 | sar_log = log_register_type("sar", NULL); |
2061 | ||
2062 | sar_requests = dict_new(); | |
2063 | dict_set_free_data(sar_requests, sar_request_cleanup); | |
2064 | ||
2065 | sar_nameservers = dict_new(); | |
8536ac6b | 2066 | dict_set_free_data(sar_nameservers, sar_free_nameserver); |
1136f709 | 2067 | |
2068 | sar_register_helper(&sar_ipv4_helper); | |
2069 | #if defined(AF_INET6) | |
2070 | sar_register_helper(&sar_ipv6_helper); | |
2071 | #endif | |
2072 | ||
2073 | conf_register_reload(sar_conf_reload); | |
2074 | } |