diff --git a/src/dnsmasq.c b/src/dnsmasq.c index 74938ff..0f73782 100644 --- a/src/dnsmasq.c +++ b/src/dnsmasq.c @@ -1683,7 +1683,7 @@ static int set_dns_listeners(time_t now) /* will we be able to get memory? */ if (daemon->port != 0) - get_new_frec(now, &wait, 0); + get_new_frec(now, &wait, NULL); for (serverfdp = daemon->sfds; serverfdp; serverfdp = serverfdp->next) poll_listen(serverfdp->fd, POLLIN); diff --git a/src/dnsmasq.h b/src/dnsmasq.h index b47ef74..68e6287 100644 --- a/src/dnsmasq.h +++ b/src/dnsmasq.h @@ -1324,7 +1324,7 @@ void receive_query(struct listener *listen, time_t now); unsigned char *tcp_request(int confd, time_t now, union mysockaddr *local_addr, struct in_addr netmask, int auth_dns); void server_gone(struct server *server); -struct frec *get_new_frec(time_t now, int *wait, int force); +struct frec *get_new_frec(time_t now, int *wait, struct frec *force); int send_from(int fd, int nowild, char *packet, size_t len, union mysockaddr *to, union all_addr *source, unsigned int iface); diff --git a/src/forward.c b/src/forward.c index 746af1c..fde554d 100644 --- a/src/forward.c +++ b/src/forward.c @@ -348,7 +348,7 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr, type &= ~SERV_DO_DNSSEC; if (daemon->servers && !flags) - forward = get_new_frec(now, NULL, 0); + forward = get_new_frec(now, NULL, NULL); /* table full - flags == 0, return REFUSED */ if (forward) @@ -1039,7 +1039,9 @@ void reply_query(int fd, int family, time_t now) /* Find the original query that started it all.... */ for (orig = forward; orig->dependent; orig = orig->dependent); - if (--orig->work_counter == 0 || !(new = get_new_frec(now, NULL, 1))) + /* Make sure we don't expire and free the orig frec during the + allocation of a new one. */ + if (--orig->work_counter == 0 || !(new = get_new_frec(now, NULL, orig))) status = STAT_ABANDONED; else { @@ -2251,9 +2253,10 @@ static void free_frec(struct frec *f) else return *wait zero if one available, or *wait is delay to when the oldest in-use record will expire. Impose an absolute limit of 4*TIMEOUT before we wipe things (for random sockets). - If force is set, always return a result, even if we have - to allocate above the limit. */ -struct frec *get_new_frec(time_t now, int *wait, int force) + If force is non-NULL, always return a result, even if we have + to allocate above the limit, and never free the record pointed + to by the force argument. */ +struct frec *get_new_frec(time_t now, int *wait, struct frec *force) { struct frec *f, *oldest, *target; int count; @@ -2270,7 +2273,7 @@ struct frec *get_new_frec(time_t now, int *wait, int force) /* Don't free DNSSEC sub-queries here, as we may end up with dangling references to them. They'll go when their "real" query is freed. */ - if (!f->dependent) + if (!f->dependent && f != force) #endif { if (difftime(now, f->time) >= 4*TIMEOUT)