Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 17 additions & 13 deletions contrib/librdns/resolver.c
Original file line number Diff line number Diff line change
Expand Up @@ -220,17 +220,20 @@ rdns_parse_reply(uint8_t *in, int r, struct rdns_request *req,
* Now we have request and query data is now at the end of header, so compare
* request QR section and reply QR section
*/
unsigned int saved_pos = req->pos;
req->pos = sizeof(struct dns_header);
pos = in + sizeof(struct dns_header);
t = r - sizeof(struct dns_header);
for (i = 0; i < (int) qdcount; i++) {
if ((npos = rdns_request_reply_cmp(req, pos, t)) == NULL) {
rdns_info("DNS request with id %d is for different query, ignoring", (int) req->id);
req->pos = saved_pos;
return false;
}
t -= npos - pos;
pos = npos;
}
req->pos = saved_pos;
/*
* Now pos is in answer section, so we should extract data and form reply
*/
Expand Down Expand Up @@ -481,19 +484,6 @@ rdns_reschedule_req_over_tcp(struct rdns_request *req, struct rdns_server *serv)
return false;
}

oc->write_buf = ((unsigned char *) oc) + sizeof(*oc);
memcpy(oc->write_buf, req->packet, req->pos);
oc->next_write_size = htons(req->pos);

DL_APPEND(ioc->tcp->output_chain, oc);

if (ioc->tcp->async_write == NULL) {
ioc->tcp->async_write = resolver->async->add_write(
resolver->async->data,
ioc->sock, ioc);
}

req->state = RDNS_REQUEST_TCP;
/* Switch IO channel from UDP to TCP */

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bug: by moving the channel switch before allocating oc, the failure path returns false after we have already removed the request from the UDP hash, changed req->io, and potentially regenerated the id. Because we exit before assigning kh_value, re-arming the timer, or releasing old_ioc, the request is left detached while the old channel keeps its ref. Please defer the switch until after calloc succeeds (as before) or add explicit rollback on error.

rdns_request_remove_from_hash(req);
req->io = ioc;
Expand All @@ -515,6 +505,20 @@ rdns_reschedule_req_over_tcp(struct rdns_request *req, struct rdns_server *serv)
}
}

oc->write_buf = ((unsigned char *) oc) + sizeof(*oc);
memcpy(oc->write_buf, req->packet, req->pos);
oc->next_write_size = htons(req->pos);

DL_APPEND(ioc->tcp->output_chain, oc);

if (ioc->tcp->async_write == NULL) {
ioc->tcp->async_write = resolver->async->add_write(
resolver->async->data,
ioc->sock, ioc);
}

req->state = RDNS_REQUEST_TCP;

req->async_event = resolver->async->add_timer(resolver->async->data,
req->timeout, req);

Expand Down