"Fossies" - the Fresh Open Source Software Archive  

Source code changes of the file "xfrd-tcp.c" between
nsd-4.3.6.tar.gz and nsd-4.3.7.tar.gz

About: NSD is an authoritative only, high performance, simple name server daemon.

xfrd-tcp.c  (nsd-4.3.6):xfrd-tcp.c  (nsd-4.3.7)
skipping to change at line 27 skipping to change at line 27
#include "nsd.h" #include "nsd.h"
#include "xfrd-tcp.h" #include "xfrd-tcp.h"
#include "buffer.h" #include "buffer.h"
#include "packet.h" #include "packet.h"
#include "dname.h" #include "dname.h"
#include "options.h" #include "options.h"
#include "namedb.h" #include "namedb.h"
#include "xfrd.h" #include "xfrd.h"
#include "xfrd-disk.h" #include "xfrd-disk.h"
#include "util.h" #include "util.h"
#ifdef HAVE_TLS_1_3
#include <openssl/ssl.h>
#include <openssl/err.h>
#endif
#ifdef HAVE_TLS_1_3
void log_crypto_err(const char* str); /* in server.c */
static SSL_CTX*
create_ssl_context()
{
SSL_CTX *ctx;
ctx = SSL_CTX_new(TLS_client_method());
if (!ctx) {
log_msg(LOG_ERR, "xfrd tls: Unable to create SSL ctxt");
}
else if (SSL_CTX_set_default_verify_paths(ctx) != 1) {
SSL_CTX_free(ctx);
log_msg(LOG_ERR, "xfrd tls: Unable to set default SSL verify path
s");
return NULL;
}
/* Only trust 1.3 as per the specification */
else if (!SSL_CTX_set_min_proto_version(ctx, TLS1_3_VERSION)) {
SSL_CTX_free(ctx);
log_msg(LOG_ERR, "xfrd tls: Unable to set minimum TLS version 1.3
");
return NULL;
}
return ctx;
}
static int
tls_verify_callback(int preverify_ok, X509_STORE_CTX *ctx)
{
int err = X509_STORE_CTX_get_error(ctx);
int depth = X509_STORE_CTX_get_error_depth(ctx);
// report the specific cert error here - will need custom verify code if
// SPKI pins are supported
if (!preverify_ok)
log_msg(LOG_ERR, "xfrd tls: TLS verify failed - (%d) depth: %d er
ror: %s",
err,
depth,
X509_verify_cert_error_string(err));
return preverify_ok;
}
static int
setup_ssl(struct xfrd_tcp_pipeline* tp, struct xfrd_tcp_set* tcp_set,
const char* auth_domain_name)
{
if (!tcp_set->ssl_ctx) {
log_msg(LOG_ERR, "xfrd tls: No TLS CTX, cannot set up XFR-over-TL
S");
return 0;
}
DEBUG(DEBUG_XFRD,1, (LOG_INFO, "xfrd: setting up TLS for tls_auth domain
name %s",
auth_domain_name));
tp->ssl = SSL_new((SSL_CTX*)tcp_set->ssl_ctx);
if(!tp->ssl) {
log_msg(LOG_ERR, "xfrd tls: Unable to create TLS object");
return 0;
}
SSL_set_connect_state(tp->ssl);
(void)SSL_set_mode(tp->ssl, SSL_MODE_AUTO_RETRY);
if(!SSL_set_fd(tp->ssl, tp->tcp_w->fd)) {
log_msg(LOG_ERR, "xfrd tls: Unable to set TLS fd");
SSL_free(tp->ssl);
tp->ssl = NULL;
return 0;
}
SSL_set_verify(tp->ssl, SSL_VERIFY_PEER, tls_verify_callback);
if(!SSL_set1_host(tp->ssl, auth_domain_name)) {
log_msg(LOG_ERR, "xfrd tls: TLS setting of hostname %s failed",
auth_domain_name);
SSL_free(tp->ssl);
tp->ssl = NULL;
return 0;
}
return 1;
}
static int
ssl_handshake(struct xfrd_tcp_pipeline* tp)
{
int ret;
ERR_clear_error();
ret = SSL_do_handshake(tp->ssl);
if(ret == 1) {
DEBUG(DEBUG_XFRD, 1, (LOG_INFO, "xfrd: TLS handshake successful")
);
tp->handshake_done = 1;
return 1;
}
tp->handshake_want = SSL_get_error(tp->ssl, ret);
if(tp->handshake_want == SSL_ERROR_WANT_READ
|| tp->handshake_want == SSL_ERROR_WANT_WRITE)
return 1;
return 0;
}
#endif
/* sort tcppipe, first on IP address, for an IPaddresss, sort on num_unused */ /* sort tcppipe, first on IP address, for an IPaddresss, sort on num_unused */
static int static int
xfrd_pipe_cmp(const void* a, const void* b) xfrd_pipe_cmp(const void* a, const void* b)
{ {
const struct xfrd_tcp_pipeline* x = (struct xfrd_tcp_pipeline*)a; const struct xfrd_tcp_pipeline* x = (struct xfrd_tcp_pipeline*)a;
const struct xfrd_tcp_pipeline* y = (struct xfrd_tcp_pipeline*)b; const struct xfrd_tcp_pipeline* y = (struct xfrd_tcp_pipeline*)b;
int r; int r;
if(x == y) if(x == y)
return 0; return 0;
if(y->ip_len != x->ip_len) if(y->key.ip_len != x->key.ip_len)
/* subtraction works because nonnegative and small numbers */ /* subtraction works because nonnegative and small numbers */
return (int)y->ip_len - (int)x->ip_len; return (int)y->key.ip_len - (int)x->key.ip_len;
r = memcmp(&x->ip, &y->ip, x->ip_len); r = memcmp(&x->key.ip, &y->key.ip, x->key.ip_len);
if(r != 0) if(r != 0)
return r; return r;
/* sort that num_unused is sorted ascending, */ /* sort that num_unused is sorted ascending, */
if(x->num_unused != y->num_unused) { if(x->key.num_unused != y->key.num_unused) {
return (x->num_unused < y->num_unused) ? -1 : 1; return (x->key.num_unused < y->key.num_unused) ? -1 : 1;
} }
/* different pipelines are different still, even with same numunused*/ /* different pipelines are different still, even with same numunused*/
return (uintptr_t)x < (uintptr_t)y ? -1 : 1; return (uintptr_t)x < (uintptr_t)y ? -1 : 1;
} }
struct xfrd_tcp_set* xfrd_tcp_set_create(struct region* region) struct xfrd_tcp_set* xfrd_tcp_set_create(struct region* region, const char *tls_ cert_bundle)
{ {
int i; int i;
struct xfrd_tcp_set* tcp_set = region_alloc(region, struct xfrd_tcp_set* tcp_set = region_alloc(region,
sizeof(struct xfrd_tcp_set)); sizeof(struct xfrd_tcp_set));
memset(tcp_set, 0, sizeof(struct xfrd_tcp_set)); memset(tcp_set, 0, sizeof(struct xfrd_tcp_set));
tcp_set->tcp_count = 0; tcp_set->tcp_count = 0;
tcp_set->tcp_waiting_first = 0; tcp_set->tcp_waiting_first = 0;
tcp_set->tcp_waiting_last = 0; tcp_set->tcp_waiting_last = 0;
#ifdef HAVE_TLS_1_3
/* Set up SSL context */
tcp_set->ssl_ctx = create_ssl_context();
if (tcp_set->ssl_ctx == NULL)
log_msg(LOG_ERR, "xfrd: XFR-over-TLS not available");
else if (tls_cert_bundle && tls_cert_bundle[0] && SSL_CTX_load_verify_loc
ations(
tcp_set->ssl_ctx, tls_cert_bundle, NULL) != 1) {
log_msg(LOG_ERR, "xfrd tls: Unable to set the certificate bundle
file %s",
tls_cert_bundle);
}
#else
log_msg(LOG_INFO, "xfrd: No TLS 1.3 support - XFR-over-TLS not available"
);
#endif
for(i=0; i<XFRD_MAX_TCP; i++) for(i=0; i<XFRD_MAX_TCP; i++)
tcp_set->tcp_state[i] = xfrd_tcp_pipeline_create(region); tcp_set->tcp_state[i] = xfrd_tcp_pipeline_create(region);
tcp_set->pipetree = rbtree_create(region, &xfrd_pipe_cmp); tcp_set->pipetree = rbtree_create(region, &xfrd_pipe_cmp);
return tcp_set; return tcp_set;
} }
struct xfrd_tcp_pipeline* struct xfrd_tcp_pipeline*
xfrd_tcp_pipeline_create(region_type* region) xfrd_tcp_pipeline_create(region_type* region)
{ {
int i; int i;
struct xfrd_tcp_pipeline* tp = (struct xfrd_tcp_pipeline*) struct xfrd_tcp_pipeline* tp = (struct xfrd_tcp_pipeline*)
region_alloc_zero(region, sizeof(*tp)); region_alloc_zero(region, sizeof(*tp));
tp->num_unused = ID_PIPE_NUM; tp->key.num_unused = ID_PIPE_NUM;
assert(sizeof(tp->unused)/sizeof(tp->unused[0]) == ID_PIPE_NUM); assert(sizeof(tp->unused)/sizeof(tp->unused[0]) == ID_PIPE_NUM);
for(i=0; i<ID_PIPE_NUM; i++) for(i=0; i<ID_PIPE_NUM; i++)
tp->unused[i] = (uint16_t)i; tp->unused[i] = (uint16_t)i;
tp->tcp_r = xfrd_tcp_create(region, QIOBUFSZ); tp->tcp_r = xfrd_tcp_create(region, QIOBUFSZ);
tp->tcp_w = xfrd_tcp_create(region, 512); tp->tcp_w = xfrd_tcp_create(region, 512);
return tp; return tp;
} }
void void
xfrd_setup_packet(buffer_type* packet, xfrd_setup_packet(buffer_type* packet,
skipping to change at line 145 skipping to change at line 260
} }
} }
socklen_t socklen_t
#ifdef INET6 #ifdef INET6
xfrd_acl_sockaddr_to(acl_options_type* acl, struct sockaddr_storage *to) xfrd_acl_sockaddr_to(acl_options_type* acl, struct sockaddr_storage *to)
#else #else
xfrd_acl_sockaddr_to(acl_options_type* acl, struct sockaddr_in *to) xfrd_acl_sockaddr_to(acl_options_type* acl, struct sockaddr_in *to)
#endif /* INET6 */ #endif /* INET6 */
{ {
#ifdef HAVE_TLS_1_3
unsigned int port = acl->port?acl->port:(acl->tls_auth_options?
(unsigned)atoi(TLS_PORT):(unsigne
d)atoi(TCP_PORT));
#else
unsigned int port = acl->port?acl->port:(unsigned)atoi(TCP_PORT); unsigned int port = acl->port?acl->port:(unsigned)atoi(TCP_PORT);
#endif
#ifdef INET6 #ifdef INET6
return xfrd_acl_sockaddr(acl, port, to); return xfrd_acl_sockaddr(acl, port, to);
#else #else
return xfrd_acl_sockaddr(acl, port, to, "to"); return xfrd_acl_sockaddr(acl, port, to, "to");
#endif /* INET6 */ #endif /* INET6 */
} }
socklen_t socklen_t
#ifdef INET6 #ifdef INET6
xfrd_acl_sockaddr_frm(acl_options_type* acl, struct sockaddr_storage *frm) xfrd_acl_sockaddr_frm(acl_options_type* acl, struct sockaddr_storage *frm)
skipping to change at line 218 skipping to change at line 338
} }
static struct xfrd_tcp_pipeline* static struct xfrd_tcp_pipeline*
pipeline_find(struct xfrd_tcp_set* set, xfrd_zone_type* zone) pipeline_find(struct xfrd_tcp_set* set, xfrd_zone_type* zone)
{ {
rbnode_type* sme = NULL; rbnode_type* sme = NULL;
struct xfrd_tcp_pipeline* r; struct xfrd_tcp_pipeline* r;
/* smaller buf than a full pipeline with 64kb ID array, only need /* smaller buf than a full pipeline with 64kb ID array, only need
* the front part with the key info, this front part contains the * the front part with the key info, this front part contains the
* members that the compare function uses. */ * members that the compare function uses. */
enum { keysize = sizeof(struct xfrd_tcp_pipeline) - struct xfrd_tcp_pipeline_key k, *key=&k;
ID_PIPE_NUM*(sizeof(struct xfrd_zone*) + sizeof(uint16_t)) };
/* void* type for alignment of the struct,
* divide the keysize by ptr-size and then add one to round up */
void* buf[ (keysize / sizeof(void*)) + 1 ];
struct xfrd_tcp_pipeline* key = (struct xfrd_tcp_pipeline*)buf;
key->node.key = key; key->node.key = key;
key->ip_len = xfrd_acl_sockaddr_to(zone->master, &key->ip); key->ip_len = xfrd_acl_sockaddr_to(zone->master, &key->ip);
key->num_unused = ID_PIPE_NUM; key->num_unused = ID_PIPE_NUM;
/* lookup existing tcp transfer to the master with highest unused */ /* lookup existing tcp transfer to the master with highest unused */
if(rbtree_find_less_equal(set->pipetree, key, &sme)) { if(rbtree_find_less_equal(set->pipetree, key, &sme)) {
/* exact match, strange, fully unused tcp cannot be open */ /* exact match, strange, fully unused tcp cannot be open */
assert(0); assert(0);
} }
if(!sme) if(!sme)
return NULL; return NULL;
r = (struct xfrd_tcp_pipeline*)sme->key; r = (struct xfrd_tcp_pipeline*)sme->key;
/* <= key pointed at, is the master correct ? */ /* <= key pointed at, is the master correct ? */
if(r->ip_len != key->ip_len) if(r->key.ip_len != key->ip_len)
return NULL; return NULL;
if(memcmp(&r->ip, &key->ip, key->ip_len) != 0) if(memcmp(&r->key.ip, &key->ip, key->ip_len) != 0)
return NULL; return NULL;
/* correct master, is there a slot free for this transfer? */ /* correct master, is there a slot free for this transfer? */
if(r->num_unused == 0) if(r->key.num_unused == 0)
return NULL; return NULL;
return r; return r;
} }
/* remove zone from tcp waiting list */ /* remove zone from tcp waiting list */
static void static void
tcp_zone_waiting_list_popfirst(struct xfrd_tcp_set* set, xfrd_zone_type* zone) tcp_zone_waiting_list_popfirst(struct xfrd_tcp_set* set, xfrd_zone_type* zone)
{ {
assert(zone->tcp_waiting); assert(zone->tcp_waiting);
set->tcp_waiting_first = zone->tcp_waiting_next; set->tcp_waiting_first = zone->tcp_waiting_next;
skipping to change at line 289 skipping to change at line 404
if(tp->tcp_send_first) if(tp->tcp_send_first)
tp->tcp_send_first->tcp_send_prev = NULL; tp->tcp_send_first->tcp_send_prev = NULL;
else tp->tcp_send_last = NULL; else tp->tcp_send_last = NULL;
zone->in_tcp_send = 0; zone->in_tcp_send = 0;
} }
/* remove zone from tcp pipe ID map */ /* remove zone from tcp pipe ID map */
static void static void
tcp_pipe_id_remove(struct xfrd_tcp_pipeline* tp, xfrd_zone_type* zone) tcp_pipe_id_remove(struct xfrd_tcp_pipeline* tp, xfrd_zone_type* zone)
{ {
assert(tp->num_unused < ID_PIPE_NUM && tp->num_unused >= 0); assert(tp->key.num_unused < ID_PIPE_NUM && tp->key.num_unused >= 0);
assert(tp->id[zone->query_id] == zone); assert(tp->id[zone->query_id] == zone);
tp->id[zone->query_id] = NULL; tp->id[zone->query_id] = NULL;
tp->unused[tp->num_unused] = zone->query_id; tp->unused[tp->key.num_unused] = zone->query_id;
/* must remove and re-add for sort order in tree */ /* must remove and re-add for sort order in tree */
(void)rbtree_delete(xfrd->tcp_set->pipetree, &tp->node); (void)rbtree_delete(xfrd->tcp_set->pipetree, &tp->key.node);
tp->num_unused++; tp->key.num_unused++;
(void)rbtree_insert(xfrd->tcp_set->pipetree, &tp->node); (void)rbtree_insert(xfrd->tcp_set->pipetree, &tp->key.node);
} }
/* stop the tcp pipe (and all its zones need to retry) */ /* stop the tcp pipe (and all its zones need to retry) */
static void static void
xfrd_tcp_pipe_stop(struct xfrd_tcp_pipeline* tp) xfrd_tcp_pipe_stop(struct xfrd_tcp_pipeline* tp)
{ {
int i, conn = -1; int i, conn = -1;
assert(tp->num_unused < ID_PIPE_NUM); /* at least one 'in-use' */ assert(tp->key.num_unused < ID_PIPE_NUM); /* at least one 'in-use' */
assert(ID_PIPE_NUM - tp->num_unused > tp->num_skip); /* at least one 'non assert(ID_PIPE_NUM - tp->key.num_unused > tp->key.num_skip); /* at least
skip' */ one 'nonskip' */
/* need to retry for all the zones connected to it */ /* need to retry for all the zones connected to it */
/* these could use different lists and go to a different nextmaster*/ /* these could use different lists and go to a different nextmaster*/
for(i=0; i<ID_PIPE_NUM; i++) { for(i=0; i<ID_PIPE_NUM; i++) {
if(tp->id[i] && tp->id[i] != TCP_NULL_SKIP) { if(tp->id[i] && tp->id[i] != TCP_NULL_SKIP) {
xfrd_zone_type* zone = tp->id[i]; xfrd_zone_type* zone = tp->id[i];
conn = zone->tcp_conn; conn = zone->tcp_conn;
zone->tcp_conn = -1; zone->tcp_conn = -1;
zone->tcp_waiting = 0; zone->tcp_waiting = 0;
tcp_pipe_sendlist_remove(tp, zone); tcp_pipe_sendlist_remove(tp, zone);
tcp_pipe_id_remove(tp, zone); tcp_pipe_id_remove(tp, zone);
skipping to change at line 335 skipping to change at line 450
tcp_pipe_reset_timeout(struct xfrd_tcp_pipeline* tp) tcp_pipe_reset_timeout(struct xfrd_tcp_pipeline* tp)
{ {
int fd = tp->handler.ev_fd; int fd = tp->handler.ev_fd;
struct timeval tv; struct timeval tv;
tv.tv_sec = xfrd->tcp_set->tcp_timeout; tv.tv_sec = xfrd->tcp_set->tcp_timeout;
tv.tv_usec = 0; tv.tv_usec = 0;
if(tp->handler_added) if(tp->handler_added)
event_del(&tp->handler); event_del(&tp->handler);
memset(&tp->handler, 0, sizeof(tp->handler)); memset(&tp->handler, 0, sizeof(tp->handler));
event_set(&tp->handler, fd, EV_PERSIST|EV_TIMEOUT|EV_READ| event_set(&tp->handler, fd, EV_PERSIST|EV_TIMEOUT|EV_READ|
(tp->tcp_send_first?EV_WRITE:0), xfrd_handle_tcp_pipe, tp); #ifdef HAVE_TLS_1_3
( tp->ssl
? ( tp->handshake_done ? ( tp->tcp_send_first ? EV_WRITE : 0 )
: tp->handshake_want == SSL_ERROR_WANT_WRITE ? EV_WRITE : 0 )
: tp->tcp_send_first ? EV_WRITE : 0 ),
#else
( tp->tcp_send_first ? EV_WRITE : 0 ),
#endif
xfrd_handle_tcp_pipe, tp);
if(event_base_set(xfrd->event_base, &tp->handler) != 0) if(event_base_set(xfrd->event_base, &tp->handler) != 0)
log_msg(LOG_ERR, "xfrd tcp: event_base_set failed"); log_msg(LOG_ERR, "xfrd tcp: event_base_set failed");
if(event_add(&tp->handler, &tv) != 0) if(event_add(&tp->handler, &tv) != 0)
log_msg(LOG_ERR, "xfrd tcp: event_add failed"); log_msg(LOG_ERR, "xfrd tcp: event_add failed");
tp->handler_added = 1; tp->handler_added = 1;
} }
/* handle event from fd of tcp pipe */ /* handle event from fd of tcp pipe */
void void
xfrd_handle_tcp_pipe(int ATTR_UNUSED(fd), short event, void* arg) xfrd_handle_tcp_pipe(int ATTR_UNUSED(fd), short event, void* arg)
skipping to change at line 375 skipping to change at line 498
} }
} }
/* add a zone to the pipeline, it starts to want to write its query */ /* add a zone to the pipeline, it starts to want to write its query */
static void static void
pipeline_setup_new_zone(struct xfrd_tcp_set* set, struct xfrd_tcp_pipeline* tp, pipeline_setup_new_zone(struct xfrd_tcp_set* set, struct xfrd_tcp_pipeline* tp,
xfrd_zone_type* zone) xfrd_zone_type* zone)
{ {
/* assign the ID */ /* assign the ID */
int idx; int idx;
assert(tp->num_unused > 0); assert(tp->key.num_unused > 0);
/* we pick a random ID, even though it is TCP anyway */ /* we pick a random ID, even though it is TCP anyway */
idx = random_generate(tp->num_unused); idx = random_generate(tp->key.num_unused);
zone->query_id = tp->unused[idx]; zone->query_id = tp->unused[idx];
tp->unused[idx] = tp->unused[tp->num_unused-1]; tp->unused[idx] = tp->unused[tp->key.num_unused-1];
tp->id[zone->query_id] = zone; tp->id[zone->query_id] = zone;
/* decrement unused counter, and fixup tree */ /* decrement unused counter, and fixup tree */
(void)rbtree_delete(set->pipetree, &tp->node); (void)rbtree_delete(set->pipetree, &tp->key.node);
tp->num_unused--; tp->key.num_unused--;
(void)rbtree_insert(set->pipetree, &tp->node); (void)rbtree_insert(set->pipetree, &tp->key.node);
/* add to sendlist, at end */ /* add to sendlist, at end */
zone->tcp_send_next = NULL; zone->tcp_send_next = NULL;
zone->tcp_send_prev = tp->tcp_send_last; zone->tcp_send_prev = tp->tcp_send_last;
zone->in_tcp_send = 1; zone->in_tcp_send = 1;
if(tp->tcp_send_last) if(tp->tcp_send_last)
tp->tcp_send_last->tcp_send_next = zone; tp->tcp_send_last->tcp_send_next = zone;
else tp->tcp_send_first = zone; else tp->tcp_send_first = zone;
tp->tcp_send_last = zone; tp->tcp_send_last = zone;
skipping to change at line 440 skipping to change at line 563
if(zone->zone_handler.ev_fd != -1) if(zone->zone_handler.ev_fd != -1)
xfrd_udp_release(zone); xfrd_udp_release(zone);
if(!xfrd_tcp_open(set, tp, zone)) { if(!xfrd_tcp_open(set, tp, zone)) {
zone->tcp_conn = -1; zone->tcp_conn = -1;
set->tcp_count --; set->tcp_count --;
xfrd_set_refresh_now(zone); xfrd_set_refresh_now(zone);
return; return;
} }
/* ip and ip_len set by tcp_open */ /* ip and ip_len set by tcp_open */
tp->node.key = tp; tp->key.node.key = tp;
tp->num_unused = ID_PIPE_NUM; tp->key.num_unused = ID_PIPE_NUM;
tp->num_skip = 0; tp->key.num_skip = 0;
tp->tcp_send_first = NULL; tp->tcp_send_first = NULL;
tp->tcp_send_last = NULL; tp->tcp_send_last = NULL;
memset(tp->id, 0, sizeof(tp->id)); memset(tp->id, 0, sizeof(tp->id));
for(i=0; i<ID_PIPE_NUM; i++) { for(i=0; i<ID_PIPE_NUM; i++) {
tp->unused[i] = i; tp->unused[i] = i;
} }
/* insert into tree */ /* insert into tree */
(void)rbtree_insert(set->pipetree, &tp->node); (void)rbtree_insert(set->pipetree, &tp->key.node);
xfrd_deactivate_zone(zone); xfrd_deactivate_zone(zone);
xfrd_unset_timer(zone); xfrd_unset_timer(zone);
pipeline_setup_new_zone(set, tp, zone); pipeline_setup_new_zone(set, tp, zone);
return; return;
} }
/* check for a pipeline to the same master with unused ID */ /* check for a pipeline to the same master with unused ID */
if((tp = pipeline_find(set, zone))!= NULL) { if((tp = pipeline_find(set, zone))!= NULL) {
int i; int i;
if(zone->zone_handler.ev_fd != -1) if(zone->zone_handler.ev_fd != -1)
xfrd_udp_release(zone); xfrd_udp_release(zone);
skipping to change at line 555 skipping to change at line 678
(void*)&xfrd->nsd->outgoing_tcp_mss, (void*)&xfrd->nsd->outgoing_tcp_mss,
sizeof(xfrd->nsd->outgoing_tcp_mss)) < 0) { sizeof(xfrd->nsd->outgoing_tcp_mss)) < 0) {
log_msg(LOG_ERR, "xfrd: setsockopt(TCP_MAXSEG)" log_msg(LOG_ERR, "xfrd: setsockopt(TCP_MAXSEG)"
"failed: %s", strerror(errno)); "failed: %s", strerror(errno));
} }
#else #else
log_msg(LOG_ERR, "setsockopt(TCP_MAXSEG) unsupported"); log_msg(LOG_ERR, "setsockopt(TCP_MAXSEG) unsupported");
#endif #endif
} }
tp->ip_len = xfrd_acl_sockaddr_to(zone->master, &tp->ip); tp->key.ip_len = xfrd_acl_sockaddr_to(zone->master, &tp->key.ip);
/* bind it */ /* bind it */
if (!xfrd_bind_local_interface(fd, zone->zone_options->pattern-> if (!xfrd_bind_local_interface(fd, zone->zone_options->pattern->
outgoing_interface, zone->master, 1)) { outgoing_interface, zone->master, 1)) {
close(fd); close(fd);
xfrd_set_refresh_now(zone); xfrd_set_refresh_now(zone);
return 0; return 0;
} }
conn = connect(fd, (struct sockaddr*)&tp->ip, tp->ip_len); conn = connect(fd, (struct sockaddr*)&tp->key.ip, tp->key.ip_len);
if (conn == -1 && errno != EINPROGRESS) { if (conn == -1 && errno != EINPROGRESS) {
log_msg(LOG_ERR, "xfrd: connect %s failed: %s", log_msg(LOG_ERR, "xfrd: connect %s failed: %s",
zone->master->ip_address_spec, strerror(errno)); zone->master->ip_address_spec, strerror(errno));
close(fd); close(fd);
xfrd_set_refresh_now(zone); xfrd_set_refresh_now(zone);
return 0; return 0;
} }
tp->tcp_r->fd = fd; tp->tcp_r->fd = fd;
tp->tcp_w->fd = fd; tp->tcp_w->fd = fd;
/* Check if an tls_auth name is configured which means we should try to
establish an SSL connection */
if (zone->master->tls_auth_options &&
zone->master->tls_auth_options->auth_domain_name) {
#ifdef HAVE_TLS_1_3
if (!setup_ssl(tp, set, zone->master->tls_auth_options->auth_doma
in_name)) {
log_msg(LOG_ERR, "xfrd: Cannot setup TLS on pipeline for
%s to %s",
zone->apex_str, zone->master->ip_address_
spec);
close(fd);
xfrd_set_refresh_now(zone);
return 0;
}
tp->handshake_done = 0;
if(!ssl_handshake(tp)) {
if(tp->handshake_want == SSL_ERROR_SYSCALL) {
log_msg(LOG_ERR, "xfrd: TLS handshake failed "
"for %s to %s: %s", zone->apex_str,
zone->master->ip_address_spec,
strerror(errno));
} else if(tp->handshake_want == SSL_ERROR_SSL) {
char errmsg[1024];
snprintf(errmsg, sizeof(errmsg), "xfrd: "
"TLS handshake failed for %s to %s",
zone->apex_str,
zone->master->ip_address_spec);
log_crypto_err(errmsg);
} else {
log_msg(LOG_ERR, "xfrd: TLS handshake failed "
"for %s to %s with %d", zone->apex_str,
zone->master->ip_address_spec,
tp->handshake_want);
}
close(fd);
xfrd_set_refresh_now(zone);
return 0;
}
#else
log_msg(LOG_ERR, "xfrd: TLS 1.3 is not available, XFR-over-TLS is
"
"not supported for %s to %s",
zone->apex_str, zone->master->i
p_address_spec);
close(fd);
xfrd_set_refresh_now(zone);
return 0;
#endif
}
/* set the tcp pipe event */ /* set the tcp pipe event */
if(tp->handler_added) if(tp->handler_added)
event_del(&tp->handler); event_del(&tp->handler);
memset(&tp->handler, 0, sizeof(tp->handler)); memset(&tp->handler, 0, sizeof(tp->handler));
event_set(&tp->handler, fd, EV_PERSIST|EV_TIMEOUT|EV_READ|EV_WRITE, event_set(&tp->handler, fd, EV_PERSIST|EV_TIMEOUT|EV_READ|
xfrd_handle_tcp_pipe, tp); #ifdef HAVE_TLS_1_3
( !tp->ssl
|| tp->handshake_done
|| tp->handshake_want == SSL_ERROR_WANT_WRITE ? EV_WRITE : 0),
#else
EV_WRITE,
#endif
xfrd_handle_tcp_pipe, tp);
if(event_base_set(xfrd->event_base, &tp->handler) != 0) if(event_base_set(xfrd->event_base, &tp->handler) != 0)
log_msg(LOG_ERR, "xfrd tcp: event_base_set failed"); log_msg(LOG_ERR, "xfrd tcp: event_base_set failed");
tv.tv_sec = set->tcp_timeout; tv.tv_sec = set->tcp_timeout;
tv.tv_usec = 0; tv.tv_usec = 0;
if(event_add(&tp->handler, &tv) != 0) if(event_add(&tp->handler, &tv) != 0)
log_msg(LOG_ERR, "xfrd tcp: event_add failed"); log_msg(LOG_ERR, "xfrd tcp: event_add failed");
tp->handler_added = 1; tp->handler_added = 1;
return 1; return 1;
} }
skipping to change at line 619 skipping to change at line 796
zone->query_id); zone->query_id);
zone->query_type = TYPE_AXFR; zone->query_type = TYPE_AXFR;
} else { } else {
DEBUG(DEBUG_XFRD,1, (LOG_INFO, "request incremental zone " DEBUG(DEBUG_XFRD,1, (LOG_INFO, "request incremental zone "
"transfer (IXFR) for %s to %s", "transfer (IXFR) for %s to %s",
zone->apex_str, zone->master->ip_address_spec)); zone->apex_str, zone->master->ip_address_spec));
xfrd_setup_packet(tcp->packet, TYPE_IXFR, CLASS_IN, zone->apex, xfrd_setup_packet(tcp->packet, TYPE_IXFR, CLASS_IN, zone->apex,
zone->query_id); zone->query_id);
zone->query_type = TYPE_IXFR; zone->query_type = TYPE_IXFR;
NSCOUNT_SET(tcp->packet, 1); NSCOUNT_SET(tcp->packet, 1);
xfrd_write_soa_buffer(tcp->packet, zone->apex, &zone->soa_disk); xfrd_write_soa_buffer(tcp->packet, zone->apex, &zone->soa_disk);
} }
/* old transfer needs to be removed still? */ /* old transfer needs to be removed still? */
if(zone->msg_seq_nr) if(zone->msg_seq_nr)
xfrd_unlink_xfrfile(xfrd->nsd, zone->xfrfilenumber); xfrd_unlink_xfrfile(xfrd->nsd, zone->xfrfilenumber);
zone->msg_seq_nr = 0; zone->msg_seq_nr = 0;
zone->msg_rr_count = 0; zone->msg_rr_count = 0;
if(zone->master->key_options && zone->master->key_options->tsig_key) { if(zone->master->key_options && zone->master->key_options->tsig_key) {
xfrd_tsig_sign_request(tcp->packet, &zone->tsig, zone->master); xfrd_tsig_sign_request(tcp->packet, &zone->tsig, zone->master);
} }
skipping to change at line 644 skipping to change at line 821
} }
static void static void
tcp_conn_ready_for_reading(struct xfrd_tcp* tcp) tcp_conn_ready_for_reading(struct xfrd_tcp* tcp)
{ {
tcp->total_bytes = 0; tcp->total_bytes = 0;
tcp->msglen = 0; tcp->msglen = 0;
buffer_clear(tcp->packet); buffer_clear(tcp->packet);
} }
#ifdef HAVE_TLS_1_3
static int
conn_write_ssl(struct xfrd_tcp* tcp, SSL* ssl)
{
int request_length;
ssize_t sent;
if(tcp->total_bytes < sizeof(tcp->msglen)) {
uint16_t sendlen = htons(tcp->msglen);
// send
request_length = sizeof(tcp->msglen) - tcp->total_bytes;
ERR_clear_error();
sent = SSL_write(ssl, (const char*)&sendlen + tcp->total_bytes,
request_length);
switch(SSL_get_error(ssl,sent)) {
case SSL_ERROR_NONE:
break;
default:
log_msg(LOG_ERR, "xfrd: generic write problem wit
h tls");
}
if(sent == -1) {
if(errno == EAGAIN || errno == EINTR) {
/* write would block, try later */
return 0;
} else {
return -1;
}
}
tcp->total_bytes += sent;
if(sent > (ssize_t)sizeof(tcp->msglen))
buffer_skip(tcp->packet, sent-sizeof(tcp->msglen));
if(tcp->total_bytes < sizeof(tcp->msglen)) {
/* incomplete write, resume later */
return 0;
}
assert(tcp->total_bytes >= sizeof(tcp->msglen));
}
assert(tcp->total_bytes < tcp->msglen + sizeof(tcp->msglen));
request_length = buffer_remaining(tcp->packet);
ERR_clear_error();
sent = SSL_write(ssl, buffer_current(tcp->packet), request_length);
switch(SSL_get_error(ssl,sent)) {
case SSL_ERROR_NONE:
break;
default:
log_msg(LOG_ERR, "xfrd: generic write problem with tls");
}
if(sent == -1) {
if(errno == EAGAIN || errno == EINTR) {
/* write would block, try later */
return 0;
} else {
return -1;
}
}
buffer_skip(tcp->packet, sent);
tcp->total_bytes += sent;
if(tcp->total_bytes < tcp->msglen + sizeof(tcp->msglen)) {
/* more to write when socket becomes writable again */
return 0;
}
assert(tcp->total_bytes == tcp->msglen + sizeof(tcp->msglen));
return 1;
}
#endif
int conn_write(struct xfrd_tcp* tcp) int conn_write(struct xfrd_tcp* tcp)
{ {
ssize_t sent; ssize_t sent;
if(tcp->total_bytes < sizeof(tcp->msglen)) { if(tcp->total_bytes < sizeof(tcp->msglen)) {
uint16_t sendlen = htons(tcp->msglen); uint16_t sendlen = htons(tcp->msglen);
#ifdef HAVE_WRITEV #ifdef HAVE_WRITEV
struct iovec iov[2]; struct iovec iov[2];
iov[0].iov_base = (uint8_t*)&sendlen + tcp->total_bytes; iov[0].iov_base = (uint8_t*)&sendlen + tcp->total_bytes;
iov[0].iov_len = sizeof(sendlen) - tcp->total_bytes; iov[0].iov_len = sizeof(sendlen) - tcp->total_bytes;
skipping to change at line 740 skipping to change at line 990
if(error == EINPROGRESS || error == EWOULDBLOCK) if(error == EINPROGRESS || error == EWOULDBLOCK)
return; /* try again later */ return; /* try again later */
if(error != 0) { if(error != 0) {
log_msg(LOG_ERR, "%s: Could not tcp connect to %s: %s", log_msg(LOG_ERR, "%s: Could not tcp connect to %s: %s",
zone->apex_str, zone->master->ip_address_spec, zone->apex_str, zone->master->ip_address_spec,
strerror(error)); strerror(error));
xfrd_tcp_pipe_stop(tp); xfrd_tcp_pipe_stop(tp);
return; return;
} }
} }
ret = conn_write(tcp); #ifdef HAVE_TLS_1_3
if (tp->ssl) {
if(tp->handshake_done) {
ret = conn_write_ssl(tcp, tp->ssl);
} else if(ssl_handshake(tp)) {
tcp_pipe_reset_timeout(tp); /* reschedule */
return;
} else {
if(tp->handshake_want == SSL_ERROR_SYSCALL) {
log_msg(LOG_ERR, "xfrd: TLS handshake failed: %s"
,
strerror(errno));
} else if(tp->handshake_want == SSL_ERROR_SSL) {
log_crypto_err("xfrd: TLS handshake failed");
} else {
log_msg(LOG_ERR, "xfrd: TLS handshake failed "
"with value: %d", tp->handshake_want);
}
xfrd_tcp_pipe_stop(tp);
return;
}
} else
#endif
ret = conn_write(tcp);
if(ret == -1) { if(ret == -1) {
log_msg(LOG_ERR, "xfrd: failed writing tcp %s", strerror(errno)); log_msg(LOG_ERR, "xfrd: failed writing tcp %s", strerror(errno));
xfrd_tcp_pipe_stop(tp); xfrd_tcp_pipe_stop(tp);
return; return;
} }
if(tcp->total_bytes != 0 && !tp->connection_established) if(tcp->total_bytes != 0 && !tp->connection_established)
tp->connection_established = 1; tp->connection_established = 1;
if(ret == 0) { if(ret == 0) {
return; /* write again later */ return; /* write again later */
} }
skipping to change at line 762 skipping to change at line 1037
/* remove first zone from sendlist */ /* remove first zone from sendlist */
tcp_pipe_sendlist_popfirst(tp, zone); tcp_pipe_sendlist_popfirst(tp, zone);
/* see if other zone wants to write; init; let it write (now) */ /* see if other zone wants to write; init; let it write (now) */
/* and use a loop, because 64k stack calls is a too much */ /* and use a loop, because 64k stack calls is a too much */
while(tp->tcp_send_first) { while(tp->tcp_send_first) {
/* setup to write for this zone */ /* setup to write for this zone */
xfrd_tcp_setup_write_packet(tp, tp->tcp_send_first); xfrd_tcp_setup_write_packet(tp, tp->tcp_send_first);
/* attempt to write for this zone (if success, continue loop)*/ /* attempt to write for this zone (if success, continue loop)*/
ret = conn_write(tcp); #ifdef HAVE_TLS_1_3
if (tp->ssl)
ret = conn_write_ssl(tcp, tp->ssl);
else
#endif
ret = conn_write(tcp);
if(ret == -1) { if(ret == -1) {
log_msg(LOG_ERR, "xfrd: failed writing tcp %s", strerror( errno)); log_msg(LOG_ERR, "xfrd: failed writing tcp %s", strerror( errno));
xfrd_tcp_pipe_stop(tp); xfrd_tcp_pipe_stop(tp);
return; return;
} }
if(ret == 0) if(ret == 0)
return; /* write again later */ return; /* write again later */
tcp_pipe_sendlist_popfirst(tp, tp->tcp_send_first); tcp_pipe_sendlist_popfirst(tp, tp->tcp_send_first);
} }
/* if sendlist empty, remove WRITE from event */ /* if sendlist empty, remove WRITE from event */
/* listen to READ, and not WRITE events */ /* listen to READ, and not WRITE events */
assert(tp->tcp_send_first == NULL); assert(tp->tcp_send_first == NULL);
tcp_pipe_reset_timeout(tp); tcp_pipe_reset_timeout(tp);
} }
#ifdef HAVE_TLS_1_3
static int
conn_read_ssl(struct xfrd_tcp* tcp, SSL* ssl)
{
ssize_t received;
/* receive leading packet length bytes */
if(tcp->total_bytes < sizeof(tcp->msglen)) {
ERR_clear_error();
received = SSL_read(ssl,
(char*) &tcp->msglen + tcp->total
_bytes,
sizeof(tcp->msglen) - tcp->total_
bytes);
if (received <= 0) {
int err = SSL_get_error(ssl, received);
if(err == SSL_ERROR_WANT_READ && errno == EAGAIN) {
return 0;
}
if(err == SSL_ERROR_ZERO_RETURN) {
/* EOF */
return 0;
}
log_msg(LOG_ERR, "ssl_read returned error %d with receive
d %zd", err, received);
}
if(received == -1) {
if(errno == EAGAIN || errno == EINTR) {
/* read would block, try later */
return 0;
} else {
#ifdef ECONNRESET
if (verbosity >= 2 || errno != ECONNRESET)
#endif /* ECONNRESET */
log_msg(LOG_ERR, "tls read sz: %s", strer
ror(errno));
return -1;
}
} else if(received == 0) {
/* EOF */
return -1;
}
tcp->total_bytes += received;
if(tcp->total_bytes < sizeof(tcp->msglen)) {
/* not complete yet, try later */
return 0;
}
assert(tcp->total_bytes == sizeof(tcp->msglen));
tcp->msglen = ntohs(tcp->msglen);
if(tcp->msglen == 0) {
buffer_set_limit(tcp->packet, tcp->msglen);
return 1;
}
if(tcp->msglen > buffer_capacity(tcp->packet)) {
log_msg(LOG_ERR, "buffer too small, dropping connection")
;
return 0;
}
buffer_set_limit(tcp->packet, tcp->msglen);
}
assert(buffer_remaining(tcp->packet) > 0);
ERR_clear_error();
received = SSL_read(ssl, buffer_current(tcp->packet),
buffer_remaining(tcp->packet));
if (received <= 0) {
int err = SSL_get_error(ssl, received);
if(err == SSL_ERROR_ZERO_RETURN) {
/* EOF */
return 0;
}
log_msg(LOG_ERR, "ssl_read returned error %d with received %zd",
err, received);
}
if(received == -1) {
if(errno == EAGAIN || errno == EINTR) {
/* read would block, try later */
return 0;
} else {
#ifdef ECONNRESET
if (verbosity >= 2 || errno != ECONNRESET)
#endif /* ECONNRESET */
log_msg(LOG_ERR, "tcp read %s", strerror(errno));
return -1;
}
} else if(received == 0) {
/* EOF */
return -1;
}
tcp->total_bytes += received;
buffer_skip(tcp->packet, received);
if(buffer_remaining(tcp->packet) > 0) {
/* not complete yet, wait for more */
return 0;
}
/* completed */
assert(buffer_position(tcp->packet) == tcp->msglen);
return 1;
}
#endif
int int
conn_read(struct xfrd_tcp* tcp) conn_read(struct xfrd_tcp* tcp)
{ {
ssize_t received; ssize_t received;
/* receive leading packet length bytes */ /* receive leading packet length bytes */
if(tcp->total_bytes < sizeof(tcp->msglen)) { if(tcp->total_bytes < sizeof(tcp->msglen)) {
received = read(tcp->fd, received = read(tcp->fd,
(char*) &tcp->msglen + tcp->total_bytes, (char*) &tcp->msglen + tcp->total_bytes,
sizeof(tcp->msglen) - tcp->total_bytes); sizeof(tcp->msglen) - tcp->total_bytes);
if(received == -1) { if(received == -1) {
skipping to change at line 864 skipping to change at line 1245
return 1; return 1;
} }
void void
xfrd_tcp_read(struct xfrd_tcp_pipeline* tp) xfrd_tcp_read(struct xfrd_tcp_pipeline* tp)
{ {
xfrd_zone_type* zone; xfrd_zone_type* zone;
struct xfrd_tcp* tcp = tp->tcp_r; struct xfrd_tcp* tcp = tp->tcp_r;
int ret; int ret;
enum xfrd_packet_result pkt_result; enum xfrd_packet_result pkt_result;
#ifdef HAVE_TLS_1_3
if(tp->ssl) {
if(tp->handshake_done) {
ret = conn_read_ssl(tcp, tp->ssl);
ret = conn_read(tcp); } else if(ssl_handshake(tp)) {
tcp_pipe_reset_timeout(tp); /* reschedule */
return;
} else {
if(tp->handshake_want == SSL_ERROR_SYSCALL) {
log_msg(LOG_ERR, "xfrd: TLS handshake failed: %s"
,
strerror(errno));
} else if(tp->handshake_want == SSL_ERROR_SSL) {
log_crypto_err("xfrd: TLS handshake failed");
} else {
log_msg(LOG_ERR, "xfrd: TLS handshake failed "
"with value: %d", tp->handshake_want);
}
xfrd_tcp_pipe_stop(tp);
return;
}
} else
#endif
ret = conn_read(tcp);
if(ret == -1) { if(ret == -1) {
log_msg(LOG_ERR, "xfrd: failed writing tcp %s", strerror(errno));
xfrd_tcp_pipe_stop(tp); xfrd_tcp_pipe_stop(tp);
return; return;
} }
if(ret == 0) if(ret == 0)
return; return;
/* completed msg */ /* completed msg */
buffer_flip(tcp->packet); buffer_flip(tcp->packet);
/* see which ID number it is, if skip, handle skip, NULL: warn */ /* see which ID number it is, if skip, handle skip, NULL: warn */
if(tcp->msglen < QHEADERSZ) { if(tcp->msglen < QHEADERSZ) {
/* too short for DNS header, skip it */ /* too short for DNS header, skip it */
skipping to change at line 904 skipping to change at line 1310
pkt_result = xfrd_handle_received_xfr_packet(zone, tcp->packet); pkt_result = xfrd_handle_received_xfr_packet(zone, tcp->packet);
/* setup for reading the next packet on this connection */ /* setup for reading the next packet on this connection */
tcp_conn_ready_for_reading(tcp); tcp_conn_ready_for_reading(tcp);
switch(pkt_result) { switch(pkt_result) {
case xfrd_packet_more: case xfrd_packet_more:
/* wait for next packet */ /* wait for next packet */
break; break;
case xfrd_packet_newlease: case xfrd_packet_newlease:
/* set to skip if more packets with this ID */ /* set to skip if more packets with this ID */
tp->id[zone->query_id] = TCP_NULL_SKIP; tp->id[zone->query_id] = TCP_NULL_SKIP;
tp->num_skip++; tp->key.num_skip++;
/* fall through to remove zone from tp */ /* fall through to remove zone from tp */
/* fallthrough */ /* fallthrough */
case xfrd_packet_transfer: case xfrd_packet_transfer:
if(zone->zone_options->pattern->multi_master_check) { if(zone->zone_options->pattern->multi_master_check) {
xfrd_tcp_release(xfrd->tcp_set, zone); xfrd_tcp_release(xfrd->tcp_set, zone);
xfrd_make_request(zone); xfrd_make_request(zone);
break; break;
} }
xfrd_tcp_release(xfrd->tcp_set, zone); xfrd_tcp_release(xfrd->tcp_set, zone);
assert(zone->round_num == -1); assert(zone->round_num == -1);
skipping to change at line 927 skipping to change at line 1333
xfrd_disable_ixfr(zone); xfrd_disable_ixfr(zone);
xfrd_tcp_release(xfrd->tcp_set, zone); xfrd_tcp_release(xfrd->tcp_set, zone);
/* query next server */ /* query next server */
xfrd_make_request(zone); xfrd_make_request(zone);
break; break;
case xfrd_packet_bad: case xfrd_packet_bad:
case xfrd_packet_tcp: case xfrd_packet_tcp:
default: default:
/* set to skip if more packets with this ID */ /* set to skip if more packets with this ID */
tp->id[zone->query_id] = TCP_NULL_SKIP; tp->id[zone->query_id] = TCP_NULL_SKIP;
tp->num_skip++; tp->key.num_skip++;
xfrd_tcp_release(xfrd->tcp_set, zone); xfrd_tcp_release(xfrd->tcp_set, zone);
/* query next server */ /* query next server */
xfrd_make_request(zone); xfrd_make_request(zone);
break; break;
} }
} }
void void
xfrd_tcp_release(struct xfrd_tcp_set* set, xfrd_zone_type* zone) xfrd_tcp_release(struct xfrd_tcp_set* set, xfrd_zone_type* zone)
{ {
skipping to change at line 953 skipping to change at line 1359
assert(zone->tcp_waiting == 0); assert(zone->tcp_waiting == 0);
zone->tcp_conn = -1; zone->tcp_conn = -1;
zone->tcp_waiting = 0; zone->tcp_waiting = 0;
/* remove from tcp_send list */ /* remove from tcp_send list */
tcp_pipe_sendlist_remove(tp, zone); tcp_pipe_sendlist_remove(tp, zone);
/* remove it from the ID list */ /* remove it from the ID list */
if(tp->id[zone->query_id] != TCP_NULL_SKIP) if(tp->id[zone->query_id] != TCP_NULL_SKIP)
tcp_pipe_id_remove(tp, zone); tcp_pipe_id_remove(tp, zone);
DEBUG(DEBUG_XFRD,1, (LOG_INFO, "xfrd: released tcp pipe now %d unused", DEBUG(DEBUG_XFRD,1, (LOG_INFO, "xfrd: released tcp pipe now %d unused",
tp->num_unused)); tp->key.num_unused));
/* if pipe was full, but no more, then see if waiting element is /* if pipe was full, but no more, then see if waiting element is
* for the same master, and can fill the unused ID */ * for the same master, and can fill the unused ID */
if(tp->num_unused == 1 && set->tcp_waiting_first) { if(tp->key.num_unused == 1 && set->tcp_waiting_first) {
#ifdef INET6 #ifdef INET6
struct sockaddr_storage to; struct sockaddr_storage to;
#else #else
struct sockaddr_in to; struct sockaddr_in to;
#endif #endif
socklen_t to_len = xfrd_acl_sockaddr_to( socklen_t to_len = xfrd_acl_sockaddr_to(
set->tcp_waiting_first->master, &to); set->tcp_waiting_first->master, &to);
if(to_len == tp->ip_len && memcmp(&to, &tp->ip, to_len) == 0) { if(to_len == tp->key.ip_len && memcmp(&to, &tp->key.ip, to_len) = = 0) {
/* use this connection for the waiting zone */ /* use this connection for the waiting zone */
zone = set->tcp_waiting_first; zone = set->tcp_waiting_first;
assert(zone->tcp_conn == -1); assert(zone->tcp_conn == -1);
zone->tcp_conn = conn; zone->tcp_conn = conn;
tcp_zone_waiting_list_popfirst(set, zone); tcp_zone_waiting_list_popfirst(set, zone);
if(zone->zone_handler.ev_fd != -1) if(zone->zone_handler.ev_fd != -1)
xfrd_udp_release(zone); xfrd_udp_release(zone);
xfrd_unset_timer(zone); xfrd_unset_timer(zone);
pipeline_setup_new_zone(set, tp, zone); pipeline_setup_new_zone(set, tp, zone);
return; return;
} }
/* waiting zone did not go to same server */ /* waiting zone did not go to same server */
} }
/* if all unused, or only skipped leftover, close the pipeline */ /* if all unused, or only skipped leftover, close the pipeline */
if(tp->num_unused >= ID_PIPE_NUM || tp->num_skip >= ID_PIPE_NUM - tp->num _unused) if(tp->key.num_unused >= ID_PIPE_NUM || tp->key.num_skip >= ID_PIPE_NUM - tp->key.num_unused)
xfrd_tcp_pipe_release(set, tp, conn); xfrd_tcp_pipe_release(set, tp, conn);
} }
void void
xfrd_tcp_pipe_release(struct xfrd_tcp_set* set, struct xfrd_tcp_pipeline* tp, xfrd_tcp_pipe_release(struct xfrd_tcp_set* set, struct xfrd_tcp_pipeline* tp,
int conn) int conn)
{ {
DEBUG(DEBUG_XFRD,1, (LOG_INFO, "xfrd: tcp pipe released")); DEBUG(DEBUG_XFRD,1, (LOG_INFO, "xfrd: tcp pipe released"));
/* one handler per tcp pipe */ /* one handler per tcp pipe */
if(tp->handler_added) if(tp->handler_added)
event_del(&tp->handler); event_del(&tp->handler);
tp->handler_added = 0; tp->handler_added = 0;
#ifdef HAVE_TLS_1_3
/* close SSL */
if (tp->ssl) {
DEBUG(DEBUG_XFRD, 1, (LOG_INFO, "xfrd: Shutting down TLS"));
SSL_shutdown(tp->ssl);
SSL_free(tp->ssl);
tp->ssl = NULL;
}
#endif
/* fd in tcp_r and tcp_w is the same, close once */ /* fd in tcp_r and tcp_w is the same, close once */
if(tp->tcp_r->fd != -1) if(tp->tcp_r->fd != -1)
close(tp->tcp_r->fd); close(tp->tcp_r->fd);
tp->tcp_r->fd = -1; tp->tcp_r->fd = -1;
tp->tcp_w->fd = -1; tp->tcp_w->fd = -1;
/* remove from pipetree */ /* remove from pipetree */
(void)rbtree_delete(xfrd->tcp_set->pipetree, &tp->node); (void)rbtree_delete(xfrd->tcp_set->pipetree, &tp->key.node);
/* a waiting zone can use the free tcp slot (to another server) */ /* a waiting zone can use the free tcp slot (to another server) */
/* if that zone fails to set-up or connect, we try to start the next /* if that zone fails to set-up or connect, we try to start the next
* waiting zone in the list */ * waiting zone in the list */
while(set->tcp_count == XFRD_MAX_TCP && set->tcp_waiting_first) { while(set->tcp_count == XFRD_MAX_TCP && set->tcp_waiting_first) {
int i; int i;
/* pop first waiting process */ /* pop first waiting process */
xfrd_zone_type* zone = set->tcp_waiting_first; xfrd_zone_type* zone = set->tcp_waiting_first;
/* start it */ /* start it */
skipping to change at line 1027 skipping to change at line 1443
if(zone->zone_handler.ev_fd != -1) if(zone->zone_handler.ev_fd != -1)
xfrd_udp_release(zone); xfrd_udp_release(zone);
if(!xfrd_tcp_open(set, tp, zone)) { if(!xfrd_tcp_open(set, tp, zone)) {
zone->tcp_conn = -1; zone->tcp_conn = -1;
xfrd_set_refresh_now(zone); xfrd_set_refresh_now(zone);
/* try to start the next zone (if any) */ /* try to start the next zone (if any) */
continue; continue;
} }
/* re-init this tcppipe */ /* re-init this tcppipe */
/* ip and ip_len set by tcp_open */ /* ip and ip_len set by tcp_open */
tp->node.key = tp; tp->key.node.key = tp;
tp->num_unused = ID_PIPE_NUM; tp->key.num_unused = ID_PIPE_NUM;
tp->num_skip = 0; tp->key.num_skip = 0;
tp->tcp_send_first = NULL; tp->tcp_send_first = NULL;
tp->tcp_send_last = NULL; tp->tcp_send_last = NULL;
memset(tp->id, 0, sizeof(tp->id)); memset(tp->id, 0, sizeof(tp->id));
for(i=0; i<ID_PIPE_NUM; i++) { for(i=0; i<ID_PIPE_NUM; i++) {
tp->unused[i] = i; tp->unused[i] = i;
} }
/* insert into tree */ /* insert into tree */
(void)rbtree_insert(set->pipetree, &tp->node); (void)rbtree_insert(set->pipetree, &tp->key.node);
/* setup write */ /* setup write */
xfrd_unset_timer(zone); xfrd_unset_timer(zone);
pipeline_setup_new_zone(set, tp, zone); pipeline_setup_new_zone(set, tp, zone);
/* started a task, no need for cleanups, so return */ /* started a task, no need for cleanups, so return */
return; return;
} }
/* no task to start, cleanup */ /* no task to start, cleanup */
assert(!set->tcp_waiting_first); assert(!set->tcp_waiting_first);
set->tcp_count --; set->tcp_count --;
assert(set->tcp_count >= 0); assert(set->tcp_count >= 0);
 End of changes. 46 change blocks. 
54 lines changed or deleted 494 lines changed or added

Home  |  About  |  Features  |  All  |  Newest  |  Dox  |  Diffs  |  RSS Feeds  |  Screenshots  |  Comments  |  Imprint  |  Privacy  |  HTTP(S)