]> source.dussan.org Git - rspamd.git/commitdiff
[Project] Rdns: Fix various ownership issues rdns-tcp-rework 4033/head
authorVsevolod Stakhov <vsevolod@highsecure.ru>
Wed, 5 Jan 2022 11:05:57 +0000 (11:05 +0000)
committerVsevolod Stakhov <vsevolod@highsecure.ru>
Wed, 5 Jan 2022 11:05:57 +0000 (11:05 +0000)
contrib/librdns/dns_private.h
contrib/librdns/resolver.c
contrib/librdns/util.c

index 359334c8d677a6caad6f6ecffa773a012825a533..adb753fd464dfd957b5903b653d04268b15d49fc 100644 (file)
@@ -154,7 +154,7 @@ enum rdns_io_channel_flags {
 struct rdns_tcp_output_chain {
        uint16_t next_write_size; /* Network byte order! */
        uint16_t cur_write; /* Cur bytes written including `next_write_size` */
-       struct rdns_request *req;
+       unsigned char *write_buf;
        struct rdns_tcp_output_chain *prev, *next;
 };
 
index 4193d6d28ac8adaf023f4afad6bc5090484eeeaf..cd6a8f97d6dfd92cc792a9b179df0c947a829eeb 100644 (file)
@@ -394,8 +394,6 @@ rdns_process_tcp_read (int fd, struct rdns_io_channel *ioc)
                                                        req->resolver->ups->data);
                                }
 
-                               rdns_request_unschedule (req);
-                               req->state = RDNS_REQUEST_REPLIED;
                                req->func (rep, req->arg);
                                REF_RELEASE (req);
                        }
@@ -458,7 +456,7 @@ rdns_reschedule_req_over_tcp (struct rdns_request *req, struct rdns_server *serv
 
                struct rdns_tcp_output_chain *oc;
 
-               oc = calloc(1, sizeof(*oc));
+               oc = calloc(1, sizeof(*oc) + req->packet_len);
 
                if (oc == NULL) {
                        rdns_err("failed to allocate output buffer for TCP ioc: %s",
@@ -466,7 +464,8 @@ rdns_reschedule_req_over_tcp (struct rdns_request *req, struct rdns_server *serv
                        return false;
                }
 
-               oc->req = req;
+               oc->write_buf = ((unsigned char *)oc) + sizeof(*oc);
+               memcpy(oc->write_buf, req->packet, req->packet_len);
                oc->next_write_size = htons(req->packet_len);
 
                DL_APPEND(ioc->tcp->output_chain, oc);
@@ -479,6 +478,7 @@ rdns_reschedule_req_over_tcp (struct rdns_request *req, struct rdns_server *serv
 
                req->state = RDNS_REQUEST_TCP;
                /* Switch IO channel from UDP to TCP */
+               rdns_request_remove_from_hash (req);
                req->io = ioc;
 
                khiter_t k;
@@ -502,11 +502,8 @@ rdns_reschedule_req_over_tcp (struct rdns_request *req, struct rdns_server *serv
                                req->timeout, req);
 
                kh_value(req->io->requests, k) = req;
-               REF_RETAIN(ioc);
                REF_RELEASE(old_ioc);
-
-               /* We do extra ref as we push a request into a TCP hash table */
-               REF_RETAIN(req);
+               REF_RETAIN(ioc);
 
                return true;
        }
@@ -852,33 +849,34 @@ rdns_write_output_chain (struct rdns_io_channel *ioc, struct rdns_tcp_output_cha
        ssize_t r;
        struct iovec iov[2];
        int niov, already_written;
+       int packet_len = ntohs (oc->next_write_size);
 
        switch (oc->cur_write) {
        case 0:
                /* Size + DNS request in full */
                iov[0].iov_base = &oc->next_write_size;
                iov[0].iov_len = sizeof (oc->next_write_size);
-               iov[1].iov_base = oc->req->packet;
-               iov[1].iov_len = oc->req->packet_len;
+               iov[1].iov_base = oc->write_buf;
+               iov[1].iov_len = packet_len;
                niov = 2;
                break;
        case 1:
                /* Partial Size + DNS request in full */
                iov[0].iov_base = ((unsigned char *)&oc->next_write_size) + 1;
                iov[0].iov_len = 1;
-               iov[1].iov_base = oc->req->packet;
-               iov[1].iov_len = oc->req->packet_len;
+               iov[1].iov_base = oc->write_buf;
+               iov[1].iov_len = packet_len;
                niov = 2;
                break;
        default:
                /* Merely DNS packet */
                already_written = oc->cur_write - 2;
-               if (oc->req->packet_len <= already_written) {
+               if (packet_len <= already_written) {
                        errno = EINVAL;
                        return -1;
                }
-               iov[0].iov_base = oc->req->packet + already_written;
-               iov[0].iov_len = oc->req->packet_len - already_written;
+               iov[0].iov_base = oc->write_buf + already_written;
+               iov[0].iov_len = packet_len - already_written;
                niov = 1;
                break;
        }
@@ -918,9 +916,7 @@ rdns_process_tcp_write (int fd, struct rdns_io_channel *ioc)
                else if (ntohs(oc->next_write_size) < oc->cur_write) {
                        /* Packet has been fully written, remove it */
                        DL_DELETE(ioc->tcp->output_chain, oc);
-                       /* Data in output buffer belongs to request */
-                       REF_RELEASE(oc->req);
-                       free (oc);
+                       free (oc); /* It also frees write buf */
                        ioc->tcp->cur_output_chains --;
                }
                else {
index b7e1a2011ca857522816a45dcd2c22ea1ec1e0d0..12ad08b16f6328e901ab82fd92a5604b8e5e7d4d 100644 (file)
@@ -50,7 +50,7 @@ rdns_request_remove_from_hash (struct rdns_request *req)
                k = kh_get(rdns_requests_hash, req->io->requests, req->id);
 
                if (k != kh_end(req->io->requests)) {
-                       kh_del(rdns_requests_hash, req->io->requests, req->id);
+                       kh_del(rdns_requests_hash, req->io->requests, k);
                }
        }
 }
@@ -507,6 +507,11 @@ rdns_request_free (struct rdns_request *req)
                        }
                }
                if (req->state == RDNS_REQUEST_TCP) {
+                       if (req->async_event) {
+                               req->async->del_timer (req->async->data,
+                                               req->async_event);
+                       }
+
                        rdns_request_remove_from_hash(req);
                }
 #ifdef TWEETNACL
@@ -644,6 +649,8 @@ rdns_request_unschedule (struct rdns_request *req)
                }
        }
        else if (req->state == RDNS_REQUEST_TCP) {
+               rdns_request_remove_from_hash(req);
+
                req->async->del_timer(req->async->data,
                                req->async_event);
 
@@ -683,7 +690,6 @@ rdns_ioc_tcp_reset (struct rdns_io_channel *ioc)
 
                struct rdns_tcp_output_chain *oc, *tmp;
                DL_FOREACH_SAFE(ioc->tcp->output_chain, oc, tmp) {
-                       REF_RELEASE(oc->req);
                        DL_DELETE (ioc->tcp->output_chain, oc);
                        free (oc);
                }