summaryrefslogtreecommitdiffstats
path: root/contrib
diff options
context:
space:
mode:
authorVsevolod Stakhov <vsevolod@highsecure.ru>2022-01-02 23:53:55 +0000
committerVsevolod Stakhov <vsevolod@highsecure.ru>2022-01-02 23:53:55 +0000
commit3aec3589a45dd71191f47da93656b6b5614903de (patch)
treeed846a6325d6754faf2ad6b6ab0d38e2c3a19a35 /contrib
parentbe5153fa1b8cc23b03e616fc0288b9f1994754d8 (diff)
downloadrspamd-3aec3589a45dd71191f47da93656b6b5614903de.tar.gz
rspamd-3aec3589a45dd71191f47da93656b6b5614903de.zip
[Project] Rdns: Add reaper for inactive TCP connections
Diffstat (limited to 'contrib')
-rw-r--r--contrib/librdns/resolver.c13
-rw-r--r--contrib/librdns/util.c124
-rw-r--r--contrib/librdns/util.h14
3 files changed, 127 insertions, 24 deletions
diff --git a/contrib/librdns/resolver.c b/contrib/librdns/resolver.c
index 520e85588..3197230ed 100644
--- a/contrib/librdns/resolver.c
+++ b/contrib/librdns/resolver.c
@@ -526,8 +526,21 @@ static void
rdns_process_periodic (void *arg)
{
struct rdns_resolver *resolver = (struct rdns_resolver*)arg;
+ struct rdns_server *serv;
UPSTREAM_RESCAN (resolver->servers, time (NULL));
+
+ UPSTREAM_FOREACH (resolver->servers, serv) {
+ for (int i = 0; i < serv->tcp_io_cnt; i ++) {
+ if (IS_CHANNEL_CONNECTED(serv->tcp_io_channels[i])) {
+ /* Disconnect channels with no requests in flight */
+ if (kh_size(serv->tcp_io_channels[i]->requests) == 0) {
+ rdns_debug ("reset inactive TCP connection to %s", serv->name);
+ rdns_ioc_tcp_reset (serv->tcp_io_channels[i]);
+ }
+ }
+ }
+ }
}
static void
diff --git a/contrib/librdns/util.c b/contrib/librdns/util.c
index e33ab709c..61c244199 100644
--- a/contrib/librdns/util.c
+++ b/contrib/librdns/util.c
@@ -515,8 +515,15 @@ rdns_ioc_free (struct rdns_io_channel *ioc)
ioc->resolver->async->del_read (ioc->resolver->async->data,
ioc->async_io);
kh_destroy(rdns_requests_hash, ioc->requests);
- close (ioc->sock);
- free (ioc->saddr);
+
+ if (ioc->sock != -1) {
+ close(ioc->sock);
+ }
+
+ if (ioc->saddr != NULL) {
+ free(ioc->saddr);
+ }
+
free (ioc);
}
@@ -553,28 +560,12 @@ rdns_ioc_new (struct rdns_server *serv,
if (is_tcp) {
/* We also need to connect a TCP channel and set a TCP buffer */
nioc->tcp = (struct rdns_tcp_channel *)(((unsigned char *)nioc) + sizeof(*nioc));
- int r = connect (nioc->sock, nioc->saddr, nioc->slen);
-
- if (r == -1) {
- if (errno != EAGAIN && errno != EINTR && errno != EINPROGRESS) {
- rdns_err ("cannot connect a TCP socket: %s for server %s",
- strerror(errno), serv->name);
- close(nioc->sock);
- free(nioc);
- return NULL;
- }
- else {
- /* We need to wait for write readiness here */
- nioc->async_io = resolver->async->add_write (resolver->async->data,
- nioc->sock, nioc);
- }
- }
- else {
- /* Always be ready to read from a TCP socket */
- nioc->flags |= RDNS_CHANNEL_CONNECTED|RDNS_CHANNEL_ACTIVE;
- nioc->tcp->async_read = resolver->async->add_read(resolver->async->data,
- nioc->sock, nioc);
+ if (!rdns_ioc_tcp_connect(nioc)) {
+ rdns_err ("cannot connect TCP socket to %s: %s", serv->name,
+ strerror (errno));
+ free (nioc);
+ return NULL;
}
nioc->flags |= RDNS_CHANNEL_TCP;
@@ -636,6 +627,93 @@ rdns_request_release (struct rdns_request *req)
REF_RELEASE (req);
}
+void
+rdns_ioc_tcp_reset (struct rdns_io_channel *ioc)
+{
+ struct rdns_resolver *resolver = ioc->resolver;
+
+ if (IS_CHANNEL_CONNECTED(ioc)) {
+ if (ioc->tcp->async_write) {
+ resolver->async->del_write (resolver->async->data, ioc->tcp->async_write);
+ ioc->tcp->async_write = NULL;
+ }
+ if (ioc->tcp->async_read) {
+ resolver->async->del_read (resolver->async->data, ioc->tcp->async_read);
+ ioc->tcp->async_read = NULL;
+ }
+
+ ioc->flags &= ~RDNS_CHANNEL_CONNECTED;
+ }
+
+ if (ioc->sock != -1) {
+ close (ioc->sock);
+ ioc->sock = -1;
+ }
+ if (ioc->saddr) {
+ free (ioc->saddr);
+ ioc->saddr = NULL;
+ }
+}
+
+bool
+rdns_ioc_tcp_connect (struct rdns_io_channel *ioc)
+{
+ struct rdns_resolver *resolver = ioc->resolver;
+
+ if (IS_CHANNEL_CONNECTED(ioc)) {
+ rdns_err ("trying to connect already connected IO channel!");
+ return false;
+ }
+
+ if (ioc->sock == -1) {
+ ioc->sock = rdns_make_client_socket (ioc->srv->name, ioc->srv->port,
+ SOCK_STREAM, &ioc->saddr, &ioc->slen);
+ if (ioc->sock == -1) {
+ rdns_err ("cannot open socket to %s: %s", ioc->srv->name,
+ strerror (errno));
+
+ if (ioc->saddr) {
+ free (ioc->saddr);
+ ioc->saddr = NULL;
+ }
+
+ return false;
+ }
+ }
+
+ int r = connect (ioc->sock, ioc->saddr, ioc->slen);
+
+ if (r == -1) {
+ if (errno != EAGAIN && errno != EINTR && errno != EINPROGRESS) {
+ rdns_err ("cannot connect a TCP socket: %s for server %s",
+ strerror(errno), ioc->srv->name);
+ close (ioc->sock);
+
+ if (ioc->saddr) {
+ free (ioc->saddr);
+ ioc->saddr = NULL;
+ }
+
+ ioc->sock = -1;
+
+ return false;
+ }
+ else {
+ /* We need to wait for write readiness here */
+ ioc->tcp->async_write = resolver->async->add_write (resolver->async->data,
+ ioc->sock, ioc);
+ }
+ }
+ else {
+ /* Always be ready to read from a TCP socket */
+ ioc->flags |= RDNS_CHANNEL_CONNECTED|RDNS_CHANNEL_ACTIVE;
+ ioc->tcp->async_read = resolver->async->add_read(resolver->async->data,
+ ioc->sock, ioc);
+ }
+
+ return true;
+}
+
static bool
rdns_resolver_conf_process_line (struct rdns_resolver *resolver,
const char *line, rdns_resolv_conf_cb cb, void *ud)
diff --git a/contrib/librdns/util.h b/contrib/librdns/util.h
index eea818dee..70ad053a0 100644
--- a/contrib/librdns/util.h
+++ b/contrib/librdns/util.h
@@ -51,13 +51,25 @@ uint16_t rdns_permutor_generate_id (void);
void rdns_ioc_free (struct rdns_io_channel *ioc);
/**
- * C
+ * Creates a new IO channel
*/
struct rdns_io_channel * rdns_ioc_new (struct rdns_server *srv,
struct rdns_resolver *resolver,
bool is_tcp);
/**
+ * Resets inactive/errored TCP chain as recommended by RFC
+ * @param ioc
+ */
+void rdns_ioc_tcp_reset (struct rdns_io_channel *ioc);
+
+/**
+ * Connect TCP IO channel to a server
+ * @param ioc
+ */
+bool rdns_ioc_tcp_connect (struct rdns_io_channel *ioc);
+
+/**
* Free request
* @param req
*/