Skip to content

Commit 81d5461

Browse files
committed
Use dedicated thread
Signed-off-by: Salil Chandra <schandra107@bloomberg.net>
1 parent ece473e commit 81d5461

1 file changed

Lines changed: 93 additions & 12 deletions

File tree

net/net_evbuffer.c

Lines changed: 93 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -824,6 +824,8 @@ struct accept_info {
824824
char *origin;
825825
int has_is_physrep;
826826
int is_physrep;
827+
struct accept_info *hostcheck_next; /* hostcheck thread queue link */
828+
int hostcheck_ok; /* result of the peer-hostname check */
827829
};
828830

829831
static int pending_connections; /* accepted, but not processed first-byte */
@@ -2564,6 +2566,80 @@ static void net_accept_ssl_error(void *data)
25642566
accept_info_free(a);
25652567
}
25662568

2569+
/* Continue accepting a connection once the peer's claimed hostname has been
2570+
verified against its source address (see validate_host / hostcheck_fn).
2571+
Runs on the main event base. Returns 0 on success (or once SSL setup has
2572+
been handed off), -1 to reject. */
2573+
static int validate_host_finish(struct accept_info *a)
2574+
{
2575+
check_base_thd();
2576+
if (a->c.flags & CONNECT_MSG_SSL) {
2577+
if (!SSL_IS_ABLE(gbl_rep_ssl_mode)) {
2578+
logmsg(LOGMSG_ERROR, "Peer requested SSL, but I don't have an SSL key pair.\n");
2579+
return -1;
2580+
}
2581+
a->origin = get_hostname_by_fileno(a->fd);
2582+
a->ssl_data = ssl_data_new(a->fd, a->origin);
2583+
accept_ssl_evbuffer(a->ssl_data, base, net_accept_ssl_error, net_accept_ssl_success, a);
2584+
return 0;
2585+
} else if (SSL_IS_REQUIRED(gbl_rep_ssl_mode)) {
2586+
logmsg(LOGMSG_ERROR, "Replicant SSL connections are required.\n");
2587+
return -1;
2588+
}
2589+
return accept_host(a);
2590+
}
2591+
2592+
/* Verifying that a peer's source address matches its claimed hostname can
2593+
require blocking DNS resolution (getaddrinfo), which must not run on the
2594+
event loop. Connections that need the check are handed to a dedicated
2595+
thread, which resolves the hostname and then resumes acceptance back on the
2596+
main event base - mirroring newsql's gethostname thread. */
2597+
extern int gbl_rep_verify_peer_hostname;
2598+
2599+
static pthread_t hostcheck_thd;
2600+
static pthread_mutex_t hostcheck_lk = PTHREAD_MUTEX_INITIALIZER;
2601+
static pthread_cond_t hostcheck_cond = PTHREAD_COND_INITIALIZER;
2602+
static struct accept_info *hostcheck_head;
2603+
static struct accept_info *hostcheck_tail;
2604+
2605+
/* Back on the event base: act on the resolver's verdict. */
2606+
static void hostcheck_resume(int dummyfd, short what, void *data)
2607+
{
2608+
struct accept_info *a = data;
2609+
if (!a->hostcheck_ok) {
2610+
logmsg(LOGMSG_ERROR, "%s fd:%d rejecting connection from node:%d host:%s: source address does not match\n",
2611+
__func__, a->fd, a->c.from_nodenum, a->from_host_interned);
2612+
accept_info_free(a);
2613+
return;
2614+
}
2615+
if (validate_host_finish(a) != 0) {
2616+
accept_info_free(a);
2617+
}
2618+
}
2619+
2620+
/* Dedicated thread: forward-resolve claimed hostnames off the event loop. */
2621+
static void *hostcheck_fn(void *unused)
2622+
{
2623+
comdb2_name_thread("hostcheck");
2624+
while (1) {
2625+
Pthread_mutex_lock(&hostcheck_lk);
2626+
while (hostcheck_head == NULL) {
2627+
Pthread_cond_wait(&hostcheck_cond, &hostcheck_lk);
2628+
}
2629+
struct accept_info *a = hostcheck_head;
2630+
hostcheck_head = a->hostcheck_next;
2631+
if (hostcheck_head == NULL) {
2632+
hostcheck_tail = NULL;
2633+
}
2634+
a->hostcheck_next = NULL;
2635+
Pthread_mutex_unlock(&hostcheck_lk);
2636+
2637+
a->hostcheck_ok = (net_validate_connect_host(a->from_host_interned, &a->ss) == 0);
2638+
evtimer_once(base, hostcheck_resume, a); /* resume on the main event base */
2639+
}
2640+
return NULL;
2641+
}
2642+
25672643
static int validate_host(struct accept_info *a)
25682644
{
25692645
if (strcmp(a->from_host, gbl_myhostname) == 0) {
@@ -2626,20 +2702,24 @@ static int validate_host(struct accept_info *a)
26262702
return -1;
26272703
}
26282704
}
2629-
if (a->c.flags & CONNECT_MSG_SSL) {
2630-
if (!SSL_IS_ABLE(gbl_rep_ssl_mode)) {
2631-
logmsg(LOGMSG_ERROR, "Peer requested SSL, but I don't have an SSL key pair.\n");
2632-
return -1;
2633-
}
2634-
a->origin = get_hostname_by_fileno(a->fd);
2635-
a->ssl_data = ssl_data_new(a->fd, a->origin);
2636-
accept_ssl_evbuffer(a->ssl_data, base, net_accept_ssl_error, net_accept_ssl_success, a);
2705+
/* Confirm the connection's source address really belongs to the claimed
2706+
hostname, so a rogue node can't impersonate a trusted peer just by
2707+
putting its hostname in the connect message. The check may block on DNS
2708+
resolution, so hand it to the hostcheck thread and resume acceptance in
2709+
validate_host_finish() once it completes. */
2710+
if (gbl_rep_verify_peer_hostname) {
2711+
a->hostcheck_next = NULL;
2712+
Pthread_mutex_lock(&hostcheck_lk);
2713+
if (hostcheck_tail)
2714+
hostcheck_tail->hostcheck_next = a;
2715+
else
2716+
hostcheck_head = a;
2717+
hostcheck_tail = a;
2718+
Pthread_cond_signal(&hostcheck_cond); /* -> hostcheck_fn */
2719+
Pthread_mutex_unlock(&hostcheck_lk);
26372720
return 0;
2638-
} else if (SSL_IS_REQUIRED(gbl_rep_ssl_mode)) {
2639-
logmsg(LOGMSG_ERROR, "Replicant SSL connections are required.\n");
2640-
return -1;
26412721
}
2642-
return accept_host(a);
2722+
return validate_host_finish(a);
26432723
}
26442724

26452725
static int process_long_hostname(struct accept_info *a)
@@ -3590,6 +3670,7 @@ static void setup_bases(void)
35903670
{
35913671
event_set_fatal_callback(libevent_fatal_cb);
35923672
init_base(&base_thd, &base, "main", NULL);
3673+
Pthread_create(&hostcheck_thd, NULL, hostcheck_fn, NULL); /* off-loads peer-hostname DNS checks */
35933674
if (dedicated_timer) {
35943675
gettimeofday(&timer_tick, NULL);
35953676
init_base(&timer_thd, &timer_base, "timer", &timer_tick);

0 commit comments

Comments
 (0)