X-Git-Url: https://jfr.im/git/irc/evilnet/x3.git/blobdiff_plain/ff3b058ac51e9caf5cf1fd310b8a401a97a85582..1ef37f9e521eaa2673d792badff62c25681a009e:/src/sar.c diff --git a/src/sar.c b/src/sar.c index 545c890..05094e5 100644 --- a/src/sar.c +++ b/src/sar.c @@ -5,7 +5,7 @@ * * srvx is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or + * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, @@ -24,6 +24,10 @@ #include "log.h" #include "timeq.h" +#if defined(HAVE_NETINET_IN_H) +# include /* sockaddr_in6 on some BSDs */ +#endif + static const char hexdigits[] = "0123456789abcdef"; struct dns_rr; @@ -162,7 +166,7 @@ static struct { char sar_localdomain[MAXLEN]; struct string_list *sar_search; struct string_list *sar_nslist; - struct sockaddr_storage sar_bind_address; + void *sar_bind_address; } conf; static struct log_type *sar_log; @@ -198,7 +202,7 @@ struct sar_nameserver { unsigned int resp_failures; unsigned int resp_scrambled; unsigned int ss_len; - struct sockaddr_storage ss; + void *ss; }; /* EDNS0 uses 12 bit RCODEs, TSIG/TKEY use 16 bit RCODEs. @@ -255,7 +259,7 @@ sar_request_fail(struct sar_request *req, unsigned int rcode) sar_request_abort(req); } -static time_t next_sar_timeout; +static unsigned long next_sar_timeout; static void sar_timeout_cb(void *data) @@ -285,7 +289,7 @@ sar_timeout_cb(void *data) } static void -sar_check_timeout(time_t when) +sar_check_timeout(unsigned long when) { if (!next_sar_timeout || when < next_sar_timeout) { timeq_del(0, sar_timeout_cb, NULL, TIMEQ_IGNORE_WHEN | TIMEQ_IGNORE_DATA); @@ -411,10 +415,10 @@ sar_dns_init(const char *resolv_conf_path) free_string_list(ns_sv); ns_sv = string_list_copy(slist); } - sa = (struct sockaddr*)&conf.sar_bind_address; - memset(sa, 0, sizeof(conf.sar_bind_address)); + sa = (struct sockaddr*)conf.sar_bind_address; + memset(sa, 0, sizeof(struct sockaddr_storage)); str = database_get_data(node, "bind_address", RECDB_QSTRING); - if (str) sar_pton(sa, sizeof(conf.sar_bind_address), NULL, str); + if (str) sar_pton(sa, sizeof(struct sockaddr_storage), NULL, str); str = database_get_data(node, "bind_port", RECDB_QSTRING); if (str != NULL) { if (sa->sa_family == AF_INET) { @@ -458,7 +462,7 @@ sar_our_server(const struct sockaddr_storage *ss, unsigned int ss_len) struct sar_nameserver *ns; ns = iter_data(it); - if (ns->ss_len == ss_len && !memcmp(ss, &ns->ss, ss_len)) + if (ns->ss_len == ss_len && !memcmp(ss, ns->ss, ss_len)) return ns; } return NULL; @@ -601,10 +605,10 @@ sar_extract_rdata(struct dns_rr *rr, unsigned int len, unsigned char *raw, unsig static void sar_fd_readable(struct io_fd *fd) { - struct sockaddr_storage ss; struct dns_header hdr; struct sar_nameserver *ns; struct sar_request *req; + void *ss; unsigned char *buf; socklen_t ss_len; int res, rcode, buf_len; @@ -615,9 +619,10 @@ sar_fd_readable(struct io_fd *fd) if (!buf_len) buf_len = 512; buf = alloca(buf_len); - ss_len = sizeof(ss); - res = recvfrom(sar_fd_fd, buf, buf_len, 0, (struct sockaddr*)&ss, &ss_len); - if (res < 12 || !(ns = sar_our_server(&ss, ss_len))) + ss_len = sizeof(struct sockaddr_storage); + ss = alloca(ss_len); + res = recvfrom(sar_fd_fd, buf, buf_len, 0, (struct sockaddr*)ss, &ss_len); + if (res < 12 || !(ns = sar_our_server((struct sockaddr_storage*)ss, ss_len))) return; hdr.id = buf[0] << 8 | buf[1]; hdr.flags = buf[2] << 8 | buf[3]; @@ -628,7 +633,7 @@ sar_fd_readable(struct io_fd *fd) sprintf(id_text, "%d", hdr.id); req = dict_find(sar_requests, id_text, NULL); - 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", fd, hdr.id, hdr.flags, hdr.qdcount, hdr.ancount, hdr.nscount, hdr.arcount, req); + 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); if (!req || !req->retries || !(hdr.flags & REQ_FLAG_QR)) { ns->resp_ignored++; return; @@ -660,16 +665,19 @@ sar_build_nslist(struct string_list *nslist) name = nslist->list[ii]; ns = dict_find(sar_nameservers, name, NULL); if (!ns) { + struct sockaddr *sa; ns = calloc(1, sizeof(*ns) + strlen(name) + 1); ns->name = (char*)(ns + 1); strcpy(ns->name, name); - ns->ss_len = sizeof(ns->ss); - if (!sar_pton((struct sockaddr*)&ns->ss, sizeof(ns->ss), NULL, name)) { + ns->ss_len = sizeof(struct sockaddr_storage); + ns->ss = calloc(1, ns->ss_len); + sa = (struct sockaddr*)ns->ss; + if (!sar_pton(sa, ns->ss_len, NULL, name)) { free(it); continue; } - sar_set_port((struct sockaddr*)&ns->ss, sizeof(ns->ss), 53); - ns->ss_len = sar_helpers[ns->ss.ss_family]->socklen; + sar_set_port(sa, ns->ss_len, 53); + ns->ss_len = sar_helpers[sa->sa_family]->socklen; dict_insert(sar_nameservers, ns->name, ns); } ns->valid = 1; @@ -683,25 +691,39 @@ sar_build_nslist(struct string_list *nslist) } } +static void +sar_free_nameserver(void *obj) +{ + struct sar_nameserver *ns = obj; + free(ns->ss); + free(ns); +} + +static unsigned int +sar_addrlen(const struct sockaddr *sa, UNUSED_ARG(unsigned int size)) +{ + return sa->sa_family <= MAX_FAMILY && sar_helpers[sa->sa_family] + ? sar_helpers[sa->sa_family]->socklen : 0; +} + static int sar_open_fd(void) { + struct sockaddr *sa; int res; /* Build list of nameservers. */ sar_build_nslist(conf.sar_nslist); - if (conf.sar_bind_address.ss_family != 0) { - struct addrinfo *ai; - - ai = (struct addrinfo*)&conf.sar_bind_address; - sar_fd_fd = socket(ai->ai_family, SOCK_DGRAM, 0); + sa = (struct sockaddr*)conf.sar_bind_address; + if (sa->sa_family != 0) { + sar_fd_fd = socket(sa->sa_family, SOCK_DGRAM, 0); if (sar_fd_fd < 0) { log_module(sar_log, LOG_FATAL, "Unable to create resolver socket: %s", strerror(errno)); return 1; } - res = bind(sar_fd_fd, ai->ai_addr, ai->ai_addrlen); + res = bind(sar_fd_fd, sa, sar_addrlen(sa, sizeof(struct sockaddr_storage))); if (res < 0) 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)); } else { @@ -710,7 +732,7 @@ sar_open_fd(void) it = dict_first(sar_nameservers); ns = iter_data(it); - sar_fd_fd = socket(ns->ss.ss_family, SOCK_DGRAM, 0); + sar_fd_fd = socket(((struct sockaddr*)ns->ss)->sa_family, SOCK_DGRAM, 0); if (sar_fd_fd < 0) { log_module(sar_log, LOG_FATAL, "Unable to create resolver socket: %s", strerror(errno)); return 1; @@ -887,7 +909,7 @@ sar_request_send(struct sar_request *req) int res; ns = iter_data(it); - res = sendto(sar_fd_fd, req->body, req->body_len, 0, (struct sockaddr*)&ns->ss, ns->ss_len); + res = sendto(sar_fd_fd, req->body, req->body_len, 0, (struct sockaddr*)ns->ss, ns->ss_len); if (res > 0) { ns->req_sent++; log_module(sar_log, LOG_DEBUG, "Sent %u bytes to %s.", res, ns->name); @@ -1031,7 +1053,7 @@ sar_services_load_file(const char *etc_services) /* Set up canonical name-indexed service entry. */ canon = sar_service_byname(name, 1); if (canon->protos[proto].valid) { - log_module(sar_log, LOG_ERROR, "Service %s/%s listed twice.", name, port); + /* log_module(sar_log, LOG_ERROR, "Service %s/%s listed twice.", name, port); who cares? */ continue; } canon->protos[proto].canon = NULL; @@ -1076,8 +1098,19 @@ sar_services_init(const char *etc_services) struct service_byname *byname; unsigned int ii; + /* Forget old services dicts and allocate new ones. */ + dict_delete(services_byname); + services_byname = dict_new(); + dict_set_free_data(services_byname, free); + + dict_delete(services_byport); + services_byport = dict_new(); + dict_set_free_data(services_byport, free); + + /* Load the list from the services file. */ sar_services_load_file(etc_services); + /* Mark well-known services as using DNS-SD SRV records. */ for (ii = 0; tcp_srvs[ii]; ++ii) { byname = sar_service_byname(tcp_srvs[ii], 1); byname->protos[SERVICE_TCP].srv = 1; @@ -1098,13 +1131,6 @@ sar_register_helper(struct sar_family_helper *helper) sar_first_helper = helper; } -static unsigned int -sar_addrlen(const struct sockaddr *sa, UNUSED_ARG(unsigned int size)) -{ - return sa->sa_family <= MAX_FAMILY && sar_helpers[sa->sa_family] - ? sar_helpers[sa->sa_family]->socklen : 0; -} - struct sar_getaddr_state { struct sar_family_helper *helper; struct addrinfo *ai_head; @@ -1122,7 +1148,7 @@ sar_getaddr_append(struct sar_getaddr_state *state, struct addrinfo *ai, int cop { unsigned int count; - log_module(sar_log, LOG_DEBUG, "sar_getaddr_append({full_name=%s}, ai=%p, copy=%d)", state->full_name, ai, copy); + log_module(sar_log, LOG_DEBUG, "sar_getaddr_append({full_name=%s}, ai=%p, copy=%d)", state->full_name, (void*)ai, copy); /* Set the appropriate pointer to the new element(s). */ if (state->ai_tail) @@ -1285,11 +1311,12 @@ sar_getaddr_fail(struct sar_request *req, UNUSED_ARG(unsigned int rcode)) struct sar_request * sar_getaddr(const char *node, const char *service, const struct addrinfo *hints_, sar_addr_cb cb, void *cb_ctx) { - struct sockaddr_storage ss; struct addrinfo hints; struct sar_family_helper *helper; struct service_byname *svc; char *end; + void *ss; + size_t ss_len; unsigned int portnum; unsigned int pos; enum service_proto proto; @@ -1344,27 +1371,29 @@ sar_getaddr(const char *node, const char *service, const struct addrinfo *hints_ } /* Try to parse \a node as a numeric hostname.*/ - pos = sar_pton((struct sockaddr*)&ss, sizeof(ss), NULL, node); + ss_len = sizeof(struct sockaddr_storage); + ss = alloca(ss_len); + pos = sar_pton((struct sockaddr*)ss, ss_len, NULL, node); if (pos && node[pos] == '\0') { struct addrinfo *ai; char canonname[SAR_NTOP_MAX]; /* we have a valid address; use it */ - sar_set_port((struct sockaddr*)&ss, sizeof(ss), portnum); - hints.ai_addrlen = sar_addrlen((struct sockaddr*)&ss, sizeof(ss)); + sar_set_port((struct sockaddr*)ss, ss_len, portnum); + hints.ai_addrlen = sar_addrlen((struct sockaddr*)ss, ss_len); if (!hints.ai_addrlen) { cb(cb_ctx, NULL, SAI_FAMILY); return NULL; } - pos = sar_ntop(canonname, sizeof(canonname), (struct sockaddr*)&ss, hints.ai_addrlen); + pos = sar_ntop(canonname, sizeof(canonname), (struct sockaddr*)ss, hints.ai_addrlen); /* allocate and fill in the addrinfo response */ ai = calloc(1, sizeof(*ai) + hints.ai_addrlen + pos + 1); - ai->ai_family = ss.ss_family; + ai->ai_family = ((struct sockaddr*)ss)->sa_family; ai->ai_socktype = hints.ai_socktype; ai->ai_protocol = hints.ai_protocol; ai->ai_addrlen = hints.ai_addrlen; - ai->ai_addr = memcpy(ai + 1, &ss, ai->ai_addrlen); + ai->ai_addr = memcpy(ai + 1, ss, ai->ai_addrlen); ai->ai_canonname = strcpy((char*)ai->ai_addr + ai->ai_addrlen, canonname); cb(cb_ctx, ai, SAI_SUCCESS); return NULL; @@ -1561,7 +1590,6 @@ sar_getname(const struct sockaddr *sa, unsigned int salen, int flags, sar_name_c if (flags & SNI_NUMERICHOST) { const char *servname; - unsigned int len; char host[SAR_NTOP_MAX], servbuf[16]; /* If appropriate, try to look up service name. */ @@ -1655,6 +1683,9 @@ ipv4_pton(struct sockaddr *sa, UNUSED_ARG(unsigned int socklen), unsigned int *b if (!pos) return 0; sa->sa_family = AF_INET; +#if defined(HAVE_SOCKADDR_SA_LEN) + sa->sa_len = sizeof(struct sockaddr_in); +#endif return pos; } @@ -1888,6 +1919,9 @@ ipv6_pton(struct sockaddr *sa, UNUSED_ARG(unsigned int socklen), unsigned int *b sin6->sin6_addr.s6_addr[cpos + jj] = 0; } sa->sa_family = AF_INET6; +#if defined(HAVE_SOCKADDR_SA_LEN) + sa->sa_len = sizeof(struct sockaddr_in6); +#endif return pos; } @@ -1988,13 +2022,15 @@ static struct sar_family_helper sar_ipv6_helper = { #endif /* defined(AF_INET6) */ static void -sar_cleanup(void) +sar_cleanup(UNUSED_ARG(void *extra)) { ioset_close(sar_fd, 1); dict_delete(services_byname); dict_delete(services_byport); dict_delete(sar_nameservers); dict_delete(sar_requests); + free_string_list(conf.sar_search); + free_string_list(conf.sar_nslist); } static void @@ -2019,20 +2055,15 @@ sar_conf_reload(void) void sar_init(void) { - reg_exit_func(sar_cleanup); + conf.sar_bind_address = calloc(1, sizeof(struct sockaddr_storage)); + reg_exit_func(sar_cleanup, NULL); sar_log = log_register_type("sar", NULL); sar_requests = dict_new(); dict_set_free_data(sar_requests, sar_request_cleanup); sar_nameservers = dict_new(); - dict_set_free_data(sar_nameservers, free); - - services_byname = dict_new(); - dict_set_free_data(services_byname, free); - - services_byport = dict_new(); - dict_set_free_data(services_byport, free); + dict_set_free_data(sar_nameservers, sar_free_nameserver); sar_register_helper(&sar_ipv4_helper); #if defined(AF_INET6)