diff options
author | Vsevolod Stakhov <vsevolod@highsecure.ru> | 2022-01-07 14:12:05 +0000 |
---|---|---|
committer | Vsevolod Stakhov <vsevolod@highsecure.ru> | 2022-01-07 14:12:05 +0000 |
commit | c790a8db04ff2bd26e7a7606aa31d59647567531 (patch) | |
tree | 9fe6a53979e090266d0e61aecc1895e1934ed98e /contrib | |
parent | d3a1896577a0c8da2dc1d8908f99cbdbc0c23350 (diff) | |
download | rspamd-c790a8db04ff2bd26e7a7606aa31d59647567531.tar.gz rspamd-c790a8db04ff2bd26e7a7606aa31d59647567531.zip |
[Fix] Add guards to avoid race condition on TCP connection
Diffstat (limited to 'contrib')
-rw-r--r-- | contrib/librdns/dns_private.h | 1 | ||||
-rw-r--r-- | contrib/librdns/resolver.c | 1 | ||||
-rw-r--r-- | contrib/librdns/util.c | 18 |
3 files changed, 18 insertions, 2 deletions
diff --git a/contrib/librdns/dns_private.h b/contrib/librdns/dns_private.h index adb753fd4..c240debea 100644 --- a/contrib/librdns/dns_private.h +++ b/contrib/librdns/dns_private.h @@ -142,6 +142,7 @@ enum rdns_io_channel_flags { RDNS_CHANNEL_CONNECTED = 1u << 0u, RDNS_CHANNEL_ACTIVE = 1u << 1u, RDNS_CHANNEL_TCP = 1u << 2u, + RDNS_CHANNEL_TCP_CONNECTING = 1u << 3u, }; #define IS_CHANNEL_CONNECTED(ioc) (((ioc)->flags & RDNS_CHANNEL_CONNECTED) != 0) diff --git a/contrib/librdns/resolver.c b/contrib/librdns/resolver.c index cd6a8f97d..9f5ca9872 100644 --- a/contrib/librdns/resolver.c +++ b/contrib/librdns/resolver.c @@ -431,6 +431,7 @@ static void rdns_process_tcp_connect (int fd, struct rdns_io_channel *ioc) { ioc->flags |= RDNS_CHANNEL_CONNECTED|RDNS_CHANNEL_ACTIVE; + ioc->flags &= ~RDNS_CHANNEL_TCP_CONNECTING; if (ioc->tcp->async_read == NULL) { ioc->tcp->async_read = ioc->resolver->async->add_read(ioc->resolver->async->data, diff --git a/contrib/librdns/util.c b/contrib/librdns/util.c index 1ff8b1858..0f5533d53 100644 --- a/contrib/librdns/util.c +++ b/contrib/librdns/util.c @@ -730,6 +730,12 @@ rdns_ioc_tcp_connect (struct rdns_io_channel *ioc) return false; } + if (ioc->flags & RDNS_CHANNEL_TCP_CONNECTING) { + /* Already connecting channel, ignore connect request */ + + return true; + } + if (ioc->sock == -1) { ioc->sock = rdns_make_client_socket (ioc->srv->name, ioc->srv->port, SOCK_STREAM, &ioc->saddr, &ioc->slen); @@ -765,13 +771,21 @@ rdns_ioc_tcp_connect (struct rdns_io_channel *ioc) } else { /* We need to wait for write readiness here */ - ioc->tcp->async_write = resolver->async->add_write (resolver->async->data, - ioc->sock, ioc); + if (ioc->tcp->async_write != NULL) { + rdns_err("internal rdns error: write event is already registered on connect"); + } + else { + ioc->tcp->async_write = resolver->async->add_write(resolver->async->data, + ioc->sock, ioc); + } + /* Prevent double connect attempts */ + ioc->flags |= RDNS_CHANNEL_TCP_CONNECTING; } } else { /* Always be ready to read from a TCP socket */ ioc->flags |= RDNS_CHANNEL_CONNECTED|RDNS_CHANNEL_ACTIVE; + ioc->flags &= ~RDNS_CHANNEL_TCP_CONNECTING; ioc->tcp->async_read = resolver->async->add_read(resolver->async->data, ioc->sock, ioc); } |