diff --git a/src/dnsmasq.c b/src/dnsmasq.c index f6daae6..7a6da56 100644 --- a/src/dnsmasq.c +++ b/src/dnsmasq.c @@ -1980,11 +1980,11 @@ static void do_tcp_connection(struct listener *listener, time_t now, int slot) pid_t p; union mysockaddr tcp_addr; socklen_t tcp_len = sizeof(union mysockaddr); - unsigned char *buff; struct server *s; int flags, auth_dns = 0; struct in_addr netmask; int pipefd[2]; + struct iovec tcpbuff; #ifdef HAVE_LINUX_NETWORK unsigned char a = 0; #endif @@ -2159,10 +2159,8 @@ static void do_tcp_connection(struct listener *listener, time_t now, int slot) if ((flags = fcntl(confd, F_GETFL, 0)) != -1) while(retry_send(fcntl(confd, F_SETFL, flags & ~O_NONBLOCK))); - buff = tcp_request(confd, now, &tcp_addr, netmask, auth_dns); - - if (buff) - free(buff); + tcp_request(confd, now, &tcpbuff, &tcp_addr, netmask, auth_dns); + free(tcpbuff.iov_base); for (s = daemon->servers; s; s = s->next) if (s->tcpfd != -1) diff --git a/src/dnsmasq.h b/src/dnsmasq.h index b9062e3..0a5064c 100644 --- a/src/dnsmasq.h +++ b/src/dnsmasq.h @@ -1569,8 +1569,8 @@ int tcp_from_udp(time_t now, int status, struct dns_header *header, ssize_t *n, int class, char *name, struct server *server, int *keycount, int *validatecount); #endif -unsigned char *tcp_request(int confd, time_t now, - union mysockaddr *local_addr, struct in_addr netmask, int auth_dns); +void tcp_request(int confd, time_t now, struct iovec *bigbuff, + union mysockaddr *local_addr, struct in_addr netmask, int auth_dns); void server_gone(struct server *server); int send_from(int fd, int nowild, char *packet, size_t len, union mysockaddr *to, union all_addr *source, diff --git a/src/forward.c b/src/forward.c index 11d61b7..65bd080 100644 --- a/src/forward.c +++ b/src/forward.c @@ -135,9 +135,9 @@ static void log_query_mysockaddr(unsigned int flags, char *name, union mysockadd } static void server_send(struct server *server, int fd, - const void *header, size_t plen, int flags) + const void *header, size_t plen) { - while (retry_send(sendto(fd, header, plen, flags, + while (retry_send(sendto(fd, header, plen, 0, &server->addr.sa, sa_len(&server->addr)))); } @@ -1074,7 +1074,7 @@ static void dnssec_validate(struct frec *forward, struct dns_header *header, set_outgoing_mark(orig, fd); #endif - server_send(server, fd, header, nn, 0); + server_send(server, fd, header, nn); server->queries++; #ifdef HAVE_DUMPFILE dump_packet_udp(DUMP_SEC_QUERY, (void *)header, (size_t)nn, NULL, &server->addr, fd); @@ -2018,20 +2018,21 @@ void receive_query(struct listener *listen, time_t now) } -/* Send query in packet, qsize to a server determined by first,last,start and - get the reply. return reply size. */ -static ssize_t tcp_talk(int first, int last, int start, unsigned char *packet, size_t qsize, - int have_mark, unsigned int mark, struct server **servp) +/* Send query in header, qsize to a server determined by first,last,start and + get the reply into the buffer passed by outbuff. Return reply size. */ +static ssize_t tcp_talk(int first, int last, int start, struct dns_header *header, size_t qsize, + struct iovec *recvbuff, int have_mark, unsigned int mark, struct server **servp) { int firstsendto = -1; - u16 *length = (u16 *)packet; - unsigned char *payload = &packet[2]; - struct dns_header *header = (struct dns_header *)payload; - unsigned int rsize; + u16 length; + unsigned int rsize = 0; int class, rclass, type, rtype; unsigned char *p; - struct blockdata *saved_question; struct timeval tv; +#ifdef MSG_FASTOPEN + struct msghdr msg; + struct iovec sendio[2]; +#endif (void)mark; (void)have_mark; @@ -2043,10 +2044,6 @@ static ssize_t tcp_talk(int first, int last, int start, unsigned char *packet, GETSHORT(type, p); GETSHORT(class, p); - /* Save question for retry. */ - if (!(saved_question = blockdata_alloc((char *)header, (size_t)qsize))) - return 0; - while (1) { int data_sent = 0, fatal = 0; @@ -2068,9 +2065,7 @@ static ssize_t tcp_talk(int first, int last, int start, unsigned char *packet, *servp = serv = daemon->serverarray[start]; retry: - blockdata_retrieve(saved_question, qsize, header); - - *length = htons(qsize); + length = htons(qsize); if (serv->tcpfd == -1) { @@ -2104,8 +2099,20 @@ static ssize_t tcp_talk(int first, int last, int start, unsigned char *packet, #endif #ifdef MSG_FASTOPEN - server_send(serv, serv->tcpfd, packet, qsize + sizeof(u16), MSG_FASTOPEN); - + sendio[0].iov_base = (unsigned char *)&length; + sendio[0].iov_len = sizeof(length); + sendio[1].iov_base = (unsigned char *)header; + sendio[1].iov_len = qsize; + msg.msg_name = &serv->addr.sa; + msg.msg_namelen = sa_len(&serv->addr); + msg.msg_iov = sendio; + msg.msg_iovlen = 2; + msg.msg_control = NULL; + msg.msg_controllen = 0; + msg.msg_flags = 0; + + while (retry_send(sendmsg(serv->tcpfd, &msg, MSG_FASTOPEN))); + if (errno == 0) data_sent = 1; else if (errno == ETIMEDOUT || errno == EHOSTUNREACH || errno == EINPROGRESS || errno == ECONNREFUSED) @@ -2131,12 +2138,15 @@ static ssize_t tcp_talk(int first, int last, int start, unsigned char *packet, serv->flags &= ~SERV_GOT_TCP; } - /* We us the _ONCE veriant of read_write() here because we've set a timeout on the tcp socket + /* We us the _ONCE variant of read_write() here because we've set a timeout on the tcp socket and wish to abort if the whole data is not read/written within the timeout. */ - if ((!data_sent && !read_write(serv->tcpfd, (unsigned char *)packet, qsize + sizeof(u16), RW_WRITE_ONCE)) || - !read_write(serv->tcpfd, (unsigned char *)length, sizeof (*length), RW_READ_ONCE) || - !read_write(serv->tcpfd, payload, (rsize = ntohs(*length)), RW_READ_ONCE)) - { + if ((!data_sent && + (!read_write(serv->tcpfd, (unsigned char *)&length, sizeof(length), RW_WRITE_ONCE) || + !read_write(serv->tcpfd, (unsigned char *)header, qsize, RW_WRITE_ONCE))) || + !read_write(serv->tcpfd, (unsigned char *)&length, sizeof(length), RW_READ_ONCE) || + !expand_buf(recvbuff, (rsize = ntohs(length))) || + !read_write(serv->tcpfd, recvbuff->iov_base, rsize, RW_READ_ONCE)) + { /* We get data then EOF, reopen connection to same server, else try next. This avoids DoS from a server which accepts connections and then closes them. */ @@ -2149,28 +2159,28 @@ static ssize_t tcp_talk(int first, int last, int start, unsigned char *packet, else goto failed; } + else + { + /* If the question section of the reply doesn't match the question we sent, then + someone might be attempting to insert bogus values into the cache by + sending replies containing questions and bogus answers. + Try another server, or give up */ + p = (unsigned char *)(((struct dns_header *)recvbuff->iov_base)+1); + if (extract_name(((struct dns_header *)recvbuff->iov_base), rsize, &p, daemon->namebuff, EXTR_NAME_COMPARE, 4) != 1) + continue; + GETSHORT(rtype, p); + GETSHORT(rclass, p); - /* If the question section of the reply doesn't match the question we sent, then - someone might be attempting to insert bogus values into the cache by - sending replies containing questions and bogus answers. - Try another server, or give up */ - p = (unsigned char *)(header+1); - if (extract_name(header, rsize, &p, daemon->namebuff, EXTR_NAME_COMPARE, 4) != 1) - continue; - GETSHORT(rtype, p); - GETSHORT(rclass, p); - - if (type != rtype || class != rclass) - continue; + if (type != rtype || class != rclass) + continue; + } serv->flags |= SERV_GOT_TCP; *servp = serv; - blockdata_free(saved_question); return rsize; } - blockdata_free(saved_question); return 0; } @@ -2182,19 +2192,16 @@ int tcp_from_udp(time_t now, int status, struct dns_header *header, ssize_t *ple int class, char *name, struct server *server, int *keycount, int *validatecount) { - unsigned char *packet = whine_malloc(65536 + MAXDNAME + RRFIXEDSZ + sizeof(u16)); - struct dns_header *new_header = (struct dns_header *)&packet[2]; int start, first, last, new_status; ssize_t n = *plenp; int log_save = daemon->log_display_id; + struct iovec recvbuff; + + recvbuff.iov_len = 0; + recvbuff.iov_base = NULL; *plenp = 0; - if (!packet) - return STAT_ABANDONED; - - memcpy(new_header, header, n); - /* Set TCP flag in logs. */ daemon->log_display_id = -daemon->log_display_id; @@ -2212,10 +2219,11 @@ int tcp_from_udp(time_t now, int status, struct dns_header *header, ssize_t *ple log_query_mysockaddr(F_NOEXTRA | F_DNSSEC | F_SERVER, name, &server->addr, STAT_ISEQUAL(status, STAT_NEED_KEY) ? "dnssec-query[DNSKEY]" : "dnssec-query[DS]", 0); - if ((n = tcp_talk(first, last, start, packet, n, 0, 0, &server)) == 0) + if ((n = tcp_talk(first, last, start, header, n, &recvbuff, 0, 0, &server)) == 0) new_status = STAT_ABANDONED; else { + struct dns_header *new_header = (struct dns_header *)recvbuff.iov_base; new_status = tcp_key_recurse(now, status, new_header, n, class, daemon->namebuff, daemon->keyname, server, 0, 0, keycount, validatecount); if (STAT_ISEQUAL(status, STAT_OK)) @@ -2252,7 +2260,7 @@ int tcp_from_udp(time_t now, int status, struct dns_header *header, ssize_t *ple } daemon->log_display_id = log_save; - free(packet); + free(recvbuff.iov_base); return new_status; } @@ -2262,9 +2270,12 @@ static int tcp_key_recurse(time_t now, int status, struct dns_header *header, si int have_mark, unsigned int mark, int *keycount, int *validatecount) { int first, last, start, new_status; - unsigned char *packet = NULL; - struct dns_header *new_header = NULL; + struct iovec new_packet; + struct dns_header *query_header = NULL, *new_header; + new_packet.iov_base = NULL; + new_packet.iov_len = 0; + while (1) { size_t m; @@ -2298,34 +2309,21 @@ static int tcp_key_recurse(time_t now, int status, struct dns_header *header, si } /* Can't validate because we need a key/DS whose name now in keyname. - Make query for same, and recurse to validate */ - if (!packet) - { - packet = whine_malloc(65536 + MAXDNAME + RRFIXEDSZ + sizeof(u16)); - new_header = (struct dns_header *)&packet[2]; - } - - if (!packet) - { - new_status = STAT_ABANDONED; - break; - } - - m = dnssec_generate_query(new_header, ((unsigned char *) new_header) + 65536, keyname, class, 0, + Make query for same in UDP packet buffer, recurse to validate*/ + query_header = (struct dns_header *)daemon->packet; + daemon->srv_save = NULL; + + m = dnssec_generate_query(query_header, ((unsigned char *)query_header) + daemon->edns_pktsz, keyname, class, 0, STAT_ISEQUAL(new_status, STAT_NEED_KEY) ? T_DNSKEY : T_DS); - if ((start = dnssec_server(server, keyname, STAT_ISEQUAL(new_status, STAT_NEED_DS), &first, &last)) == -1) + if ((start = dnssec_server(server, keyname, STAT_ISEQUAL(new_status, STAT_NEED_DS), &first, &last)) == -1 || + (m = tcp_talk(first, last, start, query_header, m, &new_packet, have_mark, mark, &server)) == 0) { new_status = STAT_ABANDONED; break; } - if ((m = tcp_talk(first, last, start, packet, m, have_mark, mark, &server)) == 0) - { - new_status = STAT_ABANDONED; - break; - } - + new_header = new_packet.iov_base; log_save = daemon->log_display_id; daemon->log_display_id = -(++daemon->log_id); @@ -2342,8 +2340,7 @@ static int tcp_key_recurse(time_t now, int status, struct dns_header *header, si break; } - if (packet) - free(packet); + free(new_packet.iov_base); return new_status; } @@ -2353,11 +2350,11 @@ static int tcp_key_recurse(time_t now, int status, struct dns_header *header, si /* The daemon forks before calling this: it should deal with one connection, blocking as necessary, and then return. Note, need to be a bit careful about resources for debug mode, when the fork is suppressed: that's - done by the caller. */ -unsigned char *tcp_request(int confd, time_t now, - union mysockaddr *local_addr, struct in_addr netmask, int auth_dns) + done by the caller, which also frees bigbuff. */ +void tcp_request(int confd, time_t now, struct iovec *bigbuff, + union mysockaddr *local_addr, struct in_addr netmask, int auth_dns) { - size_t size = 0, saved_size = 0; + size_t size = 0; int norebind = 0; #ifdef HAVE_CONNTRACK int allowed = 1; @@ -2366,16 +2363,10 @@ unsigned char *tcp_request(int confd, time_t now, int local_auth = 0; #endif int checking_disabled, do_bit = 0, ad_reqd = 0, have_pseudoheader = 0; - struct blockdata *saved_question = NULL; unsigned short qtype; unsigned int gotname = 0; - /* Max TCP packet + slop + size */ - unsigned char *packet = whine_malloc(65536 + MAXDNAME + RRFIXEDSZ + sizeof(u16)); - unsigned char *payload = &packet[2]; - u16 tcp_len; - /* largest field in header is 16-bits, so this is still sufficiently aligned */ - struct dns_header *header = (struct dns_header *)payload; - u16 *length = (u16 *)packet; + u16 tcp_len, out_len; + struct dns_header *header, *out_header; struct server *serv; struct in_addr dst_addr_4; union mysockaddr peer_addr; @@ -2385,9 +2376,12 @@ unsigned char *tcp_request(int confd, time_t now, unsigned int mark = 0; int have_mark = 0; int first, last, filtered, do_stale = 0; - - if (!packet || getpeername(confd, (struct sockaddr *)&peer_addr, &peer_len) == -1) - return packet; + + bigbuff->iov_base = NULL; + bigbuff->iov_len = 0; + + if (getpeername(confd, (struct sockaddr *)&peer_addr, &peer_len) == -1) + return; #ifdef HAVE_CONNTRACK /* Get connection mark of incoming query to set on outgoing connections. */ @@ -2408,7 +2402,7 @@ unsigned char *tcp_request(int confd, time_t now, if (option_bool(OPT_LOCAL_SERVICE)) { struct addrlist *addr; - + if (peer_addr.sa.sa_family == AF_INET6) { for (addr = daemon->interface_addrs; addr; addr = addr->next) @@ -2431,7 +2425,7 @@ unsigned char *tcp_request(int confd, time_t now, { prettyprint_addr(&peer_addr, daemon->addrbuff); my_syslog(LOG_WARNING, _("ignoring query from non-local network %s"), daemon->addrbuff); - return packet; + return; } } @@ -2449,18 +2443,26 @@ unsigned char *tcp_request(int confd, time_t now, if (query_count >= TCP_MAX_QUERIES) break; + /* Now get the query into the normal UDP packet buffer. + Ignore queries long than this. If we're answering locally, + copy the query into the output buffer, but for forwarding, tcp_talk() + wants the query in a a different buffer from the reply. + Note that we overwrote any saved UDP query - this onlt matters in debug mode. */ + daemon->srv_save = NULL; if (!read_write(confd, (unsigned char *)&tcp_len, sizeof(tcp_len), RW_READ) || - !(size = ntohs(tcp_len)) || - !read_write(confd, payload, size, RW_READ)) + !(size = ntohs(tcp_len)) || size > (size_t)daemon->packet_buff_sz || + !read_write(confd, (unsigned char *)daemon->packet, size, RW_READ)) break; - + if (size < (int)sizeof(struct dns_header)) continue; - /* Clear buffer beyond request to avoid risk of - information disclosure. */ - memset(payload + size, 0, 65536 - size); + /* Make sure we have a buffer big enough for the largest answer. */ + expand_buf(bigbuff, 65536 + MAXDNAME + RRFIXEDSZ); + out_header = bigbuff->iov_base; + /* header == query */ + header = (struct dns_header *)daemon->packet; query_count++; /* log_query gets called indirectly all over the place, so @@ -2479,9 +2481,6 @@ unsigned char *tcp_request(int confd, time_t now, ede = EDE_INVALID_DATA; else { - if (saved_question) - blockdata_free(saved_question); - do_bit = 0; if (find_pseudoheader(header, (size_t)size, NULL, &pheader, NULL, NULL)) @@ -2496,9 +2495,12 @@ unsigned char *tcp_request(int confd, time_t now, do_bit = 1; /* do bit */ } - size = add_edns0_config(header, size, ((unsigned char *) header) + 65536, &peer_addr, now, &cacheable); - saved_question = blockdata_alloc((char *)header, (size_t)size); - saved_size = size; + size = add_edns0_config(header, size, ((unsigned char *) header) + daemon->edns_pktsz, &peer_addr, now, &cacheable); + + /* Clear buffer to avoid risk of information disclosure. */ + memset(bigbuff->iov_base, 0, bigbuff->iov_len); + /* Copy query into output buffer for local answering */ + memcpy(out_header, header, size); log_query_mysockaddr((auth_dns ? F_NOERR | F_AUTH : 0) | F_QUERY | F_FORWARD, daemon->namebuff, &peer_addr, NULL, qtype); @@ -2557,10 +2559,10 @@ unsigned char *tcp_request(int confd, time_t now, #endif #ifdef HAVE_AUTH else if (auth_dns) - m = answer_auth(header, ((char *) header) + 65536, (size_t)size, now, &peer_addr, local_auth); + m = answer_auth(out_header, ((char *) out_header) + 65536, (size_t)size, now, &peer_addr, local_auth); #endif else - m = answer_request(header, ((char *) header) + 65536, (size_t)size, + m = answer_request(out_header, ((char *) out_header) + 65536, (size_t)size, dst_addr_4, netmask, now, ad_reqd, do_bit, !cacheable, &stale, &filtered); } } @@ -2568,15 +2570,12 @@ unsigned char *tcp_request(int confd, time_t now, /* Do this by steam now we're not in the select() loop */ check_log_writer(1); - if (m == 0 && ede == EDE_UNSET && saved_question) + if (m == 0 && ede == EDE_UNSET) { struct server *master; int start; int no_cache_dnssec = 0, cache_secure = 0, bogusanswer = 0; - blockdata_retrieve(saved_question, (size_t)saved_size, header); - size = saved_size; - /* save state of "cd" flag in query */ checking_disabled = header->hb4 & HB4_CD; @@ -2605,7 +2604,7 @@ unsigned char *tcp_request(int confd, time_t now, #ifdef HAVE_DNSSEC if (option_bool(OPT_DNSSEC_VALID)) { - size = add_do_bit(header, size, ((unsigned char *) header) + 65536); + size = add_do_bit(header, size, ((unsigned char *) header) + daemon->edns_pktsz); /* For debugging, set Checking Disabled, otherwise, have the upstream check too, this allows it to select auth servers when one is returning bad data. */ @@ -2615,12 +2614,14 @@ unsigned char *tcp_request(int confd, time_t now, #endif /* Loop round available servers until we succeed in connecting to one. */ - if ((m = tcp_talk(first, last, start, packet, size, have_mark, mark, &serv)) == 0) + if ((m = tcp_talk(first, last, start, header, size, bigbuff, have_mark, mark, &serv)) == 0) ede = EDE_NETERR; else { + /* just in case tcp_talk() expanded buffer - should never happen */ + out_header = bigbuff->iov_base; /* get query name again for logging - may have been overwritten */ - if (!extract_name(header, (unsigned int)size, NULL, daemon->namebuff, EXTR_NAME_EXTRACT, 0)) + if (!extract_name(out_header, (unsigned int)size, NULL, daemon->namebuff, EXTR_NAME_EXTRACT, 0)) strcpy(daemon->namebuff, "query"); log_query_mysockaddr(F_SERVER | F_FORWARD, daemon->namebuff, &serv->addr, NULL, 0); @@ -2636,7 +2637,8 @@ unsigned char *tcp_request(int confd, time_t now, { int keycount = daemon->limit[LIMIT_WORK]; /* Limit to number of DNSSEC questions, to catch loops and avoid filling cache. */ int validatecount = daemon->limit[LIMIT_CRYPTO]; - int status = tcp_key_recurse(now, STAT_OK, header, m, 0, daemon->namebuff, daemon->keyname, + /* tcp_key_recurse() may overwrite packetbuf, and thuse *header is now invalid */ + int status = tcp_key_recurse(now, STAT_OK, out_header, m, 0, daemon->namebuff, daemon->keyname, serv, have_mark, mark, &keycount, &validatecount); char *result, *domain = "result"; @@ -2662,7 +2664,7 @@ unsigned char *tcp_request(int confd, time_t now, no_cache_dnssec = 1; bogusanswer = 1; - if (extract_name(header, m, NULL, daemon->namebuff, EXTR_NAME_EXTRACT, 0)) + if (extract_name(out_header, m, NULL, daemon->namebuff, EXTR_NAME_EXTRACT, 0)) domain = daemon->namebuff; } @@ -2686,18 +2688,18 @@ unsigned char *tcp_request(int confd, time_t now, /* restore CD bit to the value in the query */ if (checking_disabled) - header->hb4 |= HB4_CD; + out_header->hb4 |= HB4_CD; else - header->hb4 &= ~HB4_CD; + out_header->hb4 &= ~HB4_CD; /* Never cache answers which are contingent on the source or MAC address EDSN0 option, since the cache is ignorant of such things. */ if (!cacheable) no_cache_dnssec = 1; - m = process_reply(header, now, serv, (unsigned int)m, + m = process_reply(out_header, now, serv, (unsigned int)m, option_bool(OPT_NO_REBIND) && !norebind, no_cache_dnssec, cache_secure, bogusanswer, - ad_reqd, do_bit, !have_pseudoheader, &peer_addr, ((unsigned char *)header) + 65536, ede); + ad_reqd, do_bit, !have_pseudoheader, &peer_addr, ((unsigned char *)out_header) + 65536, ede); /* process_reply() adds pheader itself */ have_pseudoheader = 0; @@ -2712,8 +2714,8 @@ unsigned char *tcp_request(int confd, time_t now, /* In case of local answer or no connections made. */ if (m == 0) { - if (!(m = make_local_answer(flags, gotname, size, header, daemon->namebuff, - ((char *) header) + 65536, first, last, ede))) + if (!(m = make_local_answer(flags, gotname, size, out_header, daemon->namebuff, + ((char *) out_header) + 65536, first, last, ede))) break; } else if (ede == EDE_UNSET) @@ -2729,14 +2731,12 @@ unsigned char *tcp_request(int confd, time_t now, u16 swap = htons((u16)ede); if (ede != EDE_UNSET) - m = add_pseudoheader(header, m, ((unsigned char *) header) + 65536, EDNS0_OPTION_EDE, (unsigned char *)&swap, 2, do_bit, 0); + m = add_pseudoheader(out_header, m, ((unsigned char *) out_header) + 65536, EDNS0_OPTION_EDE, (unsigned char *)&swap, 2, do_bit, 0); else - m = add_pseudoheader(header, m, ((unsigned char *) header) + 65536, 0, NULL, 0, do_bit, 0); + m = add_pseudoheader(out_header, m, ((unsigned char *) out_header) + 65536, 0, NULL, 0, do_bit, 0); } - - check_log_writer(1); - *length = htons(m); + check_log_writer(1); #if defined(HAVE_CONNTRACK) && defined(HAVE_UBUS) #ifdef HAVE_AUTH @@ -2746,7 +2746,9 @@ unsigned char *tcp_request(int confd, time_t now, report_addresses(header, m, mark); #endif - if (!read_write(confd, packet, m + sizeof(u16), RW_WRITE)) + out_len = htons(m); + if (!read_write(confd, (unsigned char *)&out_len, sizeof(out_len), RW_WRITE) | + !read_write(confd, bigbuff->iov_base, m, RW_WRITE)) break; /* If we answered with stale data, this process will now try and get fresh data into @@ -2762,18 +2764,15 @@ unsigned char *tcp_request(int confd, time_t now, daemon->log_source_addr = NULL; } } - - /* If we ran once to get fresh data, confd is already closed. */ + +/* If we ran once to get fresh data, confd is already closed. */ if (!do_stale) { shutdown(confd, SHUT_RDWR); close(confd); } - - blockdata_free(saved_question); + check_log_writer(1); - - return packet; } /* return a UDP socket bound to a random port, have to cope with straying into @@ -3274,7 +3273,7 @@ void resend_query(void) { if (daemon->srv_save) server_send(daemon->srv_save, daemon->fd_save, - daemon->packet, daemon->packet_len, 0); + daemon->packet, daemon->packet_len); } /* A server record is going away, remove references to it */