mirror of
https://github.com/NLnetLabs/unbound.git
synced 2024-09-21 14:47:09 +00:00
Merge branch 'master' into infra-keep-probing
This commit is contained in:
commit
3d1383bed3
@ -534,6 +534,8 @@ perform_setup(struct daemon* daemon, struct config_file* cfg, int debug_mode,
|
||||
LOGIN_SETALL & ~LOGIN_SETUSER & ~LOGIN_SETGROUP) != 0)
|
||||
log_warn("unable to setusercontext %s: %s",
|
||||
cfg->username, strerror(errno));
|
||||
#else
|
||||
(void)pwd;
|
||||
#endif /* HAVE_SETUSERCONTEXT */
|
||||
}
|
||||
#endif /* HAVE_GETPWNAM */
|
||||
|
@ -92,6 +92,34 @@ void* fstrm_create_control_frame_stop(size_t* len)
|
||||
return control;
|
||||
}
|
||||
|
||||
void* fstrm_create_control_frame_ready(char* contenttype, size_t* len)
|
||||
{
|
||||
uint32_t* control;
|
||||
size_t n;
|
||||
/* start bidirectional stream:
|
||||
* 4 bytes 0 escape
|
||||
* 4 bytes bigendian length of frame
|
||||
* 4 bytes bigendian type READY
|
||||
* 4 bytes bigendian frame option content type
|
||||
* 4 bytes bigendian length of string
|
||||
* string of content type.
|
||||
*/
|
||||
/* len includes the escape and framelength */
|
||||
n = 4+4+4+4+4+strlen(contenttype);
|
||||
control = malloc(n);
|
||||
if(!control) {
|
||||
return NULL;
|
||||
}
|
||||
control[0] = 0;
|
||||
control[1] = htonl(4+4+4+strlen(contenttype));
|
||||
control[2] = htonl(FSTRM_CONTROL_FRAME_READY);
|
||||
control[3] = htonl(FSTRM_CONTROL_FIELD_TYPE_CONTENT_TYPE);
|
||||
control[4] = htonl(strlen(contenttype));
|
||||
memmove(&control[5], contenttype, strlen(contenttype));
|
||||
*len = n;
|
||||
return control;
|
||||
}
|
||||
|
||||
void* fstrm_create_control_frame_accept(char* contenttype, size_t* len)
|
||||
{
|
||||
uint32_t* control;
|
||||
|
@ -127,6 +127,21 @@
|
||||
*/
|
||||
void* fstrm_create_control_frame_start(char* contenttype, size_t* len);
|
||||
|
||||
/**
|
||||
* This creates an FSTRM control frame of type READY.
|
||||
* @param contenttype: a zero delimited string with the content type.
|
||||
* eg. use the constant DNSTAP_CONTENT_TYPE, which is defined as
|
||||
* "protobuf:dnstap.Dnstap", for a dnstap frame stream.
|
||||
* @param len: if a buffer is returned this is the length of that buffer.
|
||||
* @return NULL on malloc failure. Returns a malloced buffer with the
|
||||
* protocol message. The buffer starts with the 4 bytes of 0 that indicate
|
||||
* a control frame. The buffer should be sent without preceding it with
|
||||
* the 'len' variable (like data frames are), but straight the content of the
|
||||
* buffer, because the lengths are included in the buffer. This is so that
|
||||
* the zero control indicator can be included before the control frame length.
|
||||
*/
|
||||
void* fstrm_create_control_frame_ready(char* contenttype, size_t* len);
|
||||
|
||||
/**
|
||||
* This creates an FSTRM control frame of type STOP.
|
||||
* @param len: if a buffer is returned this is the length of that buffer.
|
||||
|
@ -48,6 +48,7 @@
|
||||
#include "util/ub_event.h"
|
||||
#include "util/net_help.h"
|
||||
#include "services/outside_network.h"
|
||||
#include "sldns/sbuffer.h"
|
||||
#ifdef HAVE_SYS_UN_H
|
||||
#include <sys/un.h>
|
||||
#endif
|
||||
@ -68,6 +69,9 @@
|
||||
/** the msec to wait for reconnect slow, to stop busy spinning on reconnect */
|
||||
#define DTIO_RECONNECT_TIMEOUT_SLOW 1000
|
||||
|
||||
/** maximum length of received frame */
|
||||
#define DTIO_RECV_FRAME_MAX_LEN 1000
|
||||
|
||||
struct stop_flush_info;
|
||||
/** DTIO command channel commands */
|
||||
enum {
|
||||
@ -85,9 +89,13 @@ static int dtio_add_output_event_write(struct dt_io_thread* dtio);
|
||||
static void dtio_reconnect_enable(struct dt_io_thread* dtio);
|
||||
/** stop from stop_flush event loop */
|
||||
static void dtio_stop_flush_exit(struct stop_flush_info* info);
|
||||
/** setup a start control message */
|
||||
static int dtio_control_start_send(struct dt_io_thread* dtio);
|
||||
#ifdef HAVE_SSL
|
||||
/** enable briefly waiting for a read event, for SSL negotiation */
|
||||
static int dtio_enable_brief_read(struct dt_io_thread* dtio);
|
||||
/** enable briefly waiting for a write event, for SSL negotiation */
|
||||
static int dtio_enable_brief_write(struct dt_io_thread* dtio);
|
||||
#endif
|
||||
|
||||
struct dt_msg_queue*
|
||||
@ -261,6 +269,7 @@ int dt_io_thread_apply_cfg(struct dt_io_thread* dtio, struct config_file *cfg)
|
||||
} else {
|
||||
dtio->upstream_is_unix = 1;
|
||||
}
|
||||
dtio->is_bidirectional = cfg->dnstap_bidirectional;
|
||||
|
||||
if(dtio->upstream_is_unix) {
|
||||
if(!cfg->dnstap_socket_path ||
|
||||
@ -551,6 +560,20 @@ static void dtio_cur_msg_free(struct dt_io_thread* dtio)
|
||||
dtio->cur_msg_len_done = 0;
|
||||
}
|
||||
|
||||
/** delete the buffer and counters used to read frame */
|
||||
static void dtio_read_frame_free(struct dt_frame_read_buf* rb)
|
||||
{
|
||||
if(rb->buf) {
|
||||
free(rb->buf);
|
||||
rb->buf = NULL;
|
||||
}
|
||||
rb->buf_count = 0;
|
||||
rb->buf_cap = 0;
|
||||
rb->frame_len = 0;
|
||||
rb->frame_len_done = 0;
|
||||
rb->control_frame = 0;
|
||||
}
|
||||
|
||||
/** del the output file descriptor event for listening */
|
||||
static void dtio_del_output_event(struct dt_io_thread* dtio)
|
||||
{
|
||||
@ -594,6 +617,11 @@ static void dtio_close_output(struct dt_io_thread* dtio)
|
||||
if(dtio->cur_msg) {
|
||||
dtio_cur_msg_free(dtio);
|
||||
}
|
||||
|
||||
dtio->ready_frame_sent = 0;
|
||||
dtio->accept_frame_received = 0;
|
||||
dtio_read_frame_free(&dtio->read_frame);
|
||||
|
||||
dtio_reconnect_enable(dtio);
|
||||
}
|
||||
|
||||
@ -855,6 +883,94 @@ static int dtio_write_more(struct dt_io_thread* dtio)
|
||||
return 1;
|
||||
}
|
||||
|
||||
/** Receive bytes from dtio->fd, store in buffer. Returns 0: closed,
|
||||
* -1: continue, >0: number of bytes read into buffer */
|
||||
static ssize_t receive_bytes(struct dt_io_thread* dtio, void* buf, size_t len) {
|
||||
ssize_t r;
|
||||
r = recv(dtio->fd, (void*)buf, len, 0);
|
||||
if(r == -1) {
|
||||
char* to = dtio->socket_path;
|
||||
if(!to) to = dtio->ip_str;
|
||||
if(!to) to = "";
|
||||
#ifndef USE_WINSOCK
|
||||
if(errno == EINTR || errno == EAGAIN)
|
||||
return -1; /* try later */
|
||||
#else
|
||||
if(WSAGetLastError() == WSAEINPROGRESS) {
|
||||
return -1; /* try later */
|
||||
} else if(WSAGetLastError() == WSAEWOULDBLOCK) {
|
||||
ub_winsock_tcp_wouldblock(
|
||||
(dtio->stop_flush_event?
|
||||
dtio->stop_flush_event:dtio->event),
|
||||
UB_EV_READ);
|
||||
return -1; /* try later */
|
||||
}
|
||||
#endif
|
||||
if(dtio->reconnect_timeout > DTIO_RECONNECT_TIMEOUT_MIN &&
|
||||
verbosity < 4)
|
||||
return 0; /* no log retries on low verbosity */
|
||||
log_err("dnstap io: output closed, recv %s: %s", to,
|
||||
strerror(errno));
|
||||
/* and close below */
|
||||
return 0;
|
||||
}
|
||||
if(r == 0) {
|
||||
if(dtio->reconnect_timeout > DTIO_RECONNECT_TIMEOUT_MIN &&
|
||||
verbosity < 4)
|
||||
return 0; /* no log retries on low verbosity */
|
||||
verbose(VERB_DETAIL, "dnstap io: output closed by the other side");
|
||||
/* and close below */
|
||||
return 0;
|
||||
}
|
||||
/* something was received */
|
||||
return r;
|
||||
}
|
||||
|
||||
#ifdef HAVE_SSL
|
||||
/** Receive bytes over TLS from dtio->fd, store in buffer. Returns 0: closed,
|
||||
* -1: continue, >0: number of bytes read into buffer */
|
||||
static int ssl_read_bytes(struct dt_io_thread* dtio, void* buf, size_t len)
|
||||
{
|
||||
int r;
|
||||
ERR_clear_error();
|
||||
r = SSL_read(dtio->ssl, buf, len);
|
||||
if(r <= 0) {
|
||||
int want = SSL_get_error(dtio->ssl, r);
|
||||
if(want == SSL_ERROR_ZERO_RETURN) {
|
||||
if(dtio->reconnect_timeout > DTIO_RECONNECT_TIMEOUT_MIN &&
|
||||
verbosity < 4)
|
||||
return 0; /* no log retries on low verbosity */
|
||||
verbose(VERB_DETAIL, "dnstap io: output closed by the "
|
||||
"other side");
|
||||
return 0;
|
||||
} else if(want == SSL_ERROR_WANT_READ) {
|
||||
/* continue later */
|
||||
return -1;
|
||||
} else if(want == SSL_ERROR_WANT_WRITE) {
|
||||
(void)dtio_enable_brief_write(dtio);
|
||||
return -1;
|
||||
} else if(want == SSL_ERROR_SYSCALL) {
|
||||
#ifdef ECONNRESET
|
||||
if(dtio->reconnect_timeout > DTIO_RECONNECT_TIMEOUT_MIN &&
|
||||
errno == ECONNRESET && verbosity < 4)
|
||||
return 0; /* silence reset by peer */
|
||||
#endif
|
||||
if(errno != 0)
|
||||
log_err("SSL_read syscall: %s",
|
||||
strerror(errno));
|
||||
verbose(VERB_DETAIL, "dnstap io: output closed by the "
|
||||
"other side");
|
||||
return 0;
|
||||
}
|
||||
log_crypto_err("could not SSL_read");
|
||||
verbose(VERB_DETAIL, "dnstap io: output closed by the "
|
||||
"other side");
|
||||
return 0;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
#endif /* HAVE_SSL */
|
||||
|
||||
/** check if the output fd has been closed,
|
||||
* it returns false if the stream is closed. */
|
||||
static int dtio_check_close(struct dt_io_thread* dtio)
|
||||
@ -864,44 +980,17 @@ static int dtio_check_close(struct dt_io_thread* dtio)
|
||||
* packets is okay for the framestream protocol. And also, the
|
||||
* read call can return that the stream has been closed by the
|
||||
* other side. */
|
||||
ssize_t r;
|
||||
uint8_t buf[1024];
|
||||
int r = -1;
|
||||
|
||||
|
||||
if(dtio->fd == -1) return 0;
|
||||
while(1) {
|
||||
r = recv(dtio->fd, (void*)buf, sizeof(buf), 0);
|
||||
if(r == -1) {
|
||||
char* to = dtio->socket_path;
|
||||
if(!to) to = dtio->ip_str;
|
||||
if(!to) to = "";
|
||||
#ifndef USE_WINSOCK
|
||||
if(errno == EINTR || errno == EAGAIN)
|
||||
return 1; /* try later */
|
||||
#else
|
||||
if(WSAGetLastError() == WSAEINPROGRESS) {
|
||||
return 1; /* try later */
|
||||
} else if(WSAGetLastError() == WSAEWOULDBLOCK) {
|
||||
ub_winsock_tcp_wouldblock(
|
||||
(dtio->stop_flush_event?
|
||||
dtio->stop_flush_event:dtio->event),
|
||||
UB_EV_READ);
|
||||
return 1; /* try later */
|
||||
}
|
||||
#endif
|
||||
if(dtio->reconnect_timeout > DTIO_RECONNECT_TIMEOUT_MIN && verbosity < 4)
|
||||
break; /* no log retries on low verbosity */
|
||||
log_err("dnstap io: output closed, recv %s: %s", to,
|
||||
strerror(errno));
|
||||
/* and close below */
|
||||
break;
|
||||
}
|
||||
if(r == 0) {
|
||||
if(dtio->reconnect_timeout > DTIO_RECONNECT_TIMEOUT_MIN && verbosity < 4)
|
||||
break; /* no log retries on low verbosity */
|
||||
verbose(VERB_DETAIL, "dnstap io: output closed by the other side");
|
||||
/* and close below */
|
||||
break;
|
||||
}
|
||||
/* something was received, ignore it */
|
||||
|
||||
while(r != 0) {
|
||||
/* not interested in buffer content, overwrite */
|
||||
r = receive_bytes(dtio, (void*)buf, sizeof(buf));
|
||||
if(r == -1)
|
||||
return 1;
|
||||
}
|
||||
/* the other end has been closed */
|
||||
/* close the channel */
|
||||
@ -910,6 +999,143 @@ static int dtio_check_close(struct dt_io_thread* dtio)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** Read accept frame. Returns -1: continue reading, 0: closed,
|
||||
* 1: valid accept received. */
|
||||
static int dtio_read_accept_frame(struct dt_io_thread* dtio)
|
||||
{
|
||||
int r;
|
||||
size_t read_frame_done;
|
||||
while(dtio->read_frame.frame_len_done < 4) {
|
||||
#ifdef HAVE_SSL
|
||||
if(dtio->ssl) {
|
||||
r = ssl_read_bytes(dtio,
|
||||
(uint8_t*)&dtio->read_frame.frame_len+
|
||||
dtio->read_frame.frame_len_done,
|
||||
4-dtio->read_frame.frame_len_done);
|
||||
} else {
|
||||
#endif
|
||||
r = receive_bytes(dtio,
|
||||
(uint8_t*)&dtio->read_frame.frame_len+
|
||||
dtio->read_frame.frame_len_done,
|
||||
4-dtio->read_frame.frame_len_done);
|
||||
#ifdef HAVE_SSL
|
||||
}
|
||||
#endif
|
||||
if(r == -1)
|
||||
return -1; /* continue reading */
|
||||
if(r == 0) {
|
||||
/* connection closed */
|
||||
goto close_connection;
|
||||
}
|
||||
dtio->read_frame.frame_len_done += r;
|
||||
if(dtio->read_frame.frame_len_done < 4)
|
||||
return -1; /* continue reading */
|
||||
|
||||
if(dtio->read_frame.frame_len == 0) {
|
||||
dtio->read_frame.frame_len_done = 0;
|
||||
dtio->read_frame.control_frame = 1;
|
||||
continue;
|
||||
}
|
||||
dtio->read_frame.frame_len = ntohl(dtio->read_frame.frame_len);
|
||||
if(dtio->read_frame.frame_len > DTIO_RECV_FRAME_MAX_LEN) {
|
||||
verbose(VERB_OPS, "dnstap: received frame exceeds max "
|
||||
"length of %d bytes, closing connection",
|
||||
DTIO_RECV_FRAME_MAX_LEN);
|
||||
goto close_connection;
|
||||
}
|
||||
dtio->read_frame.buf = calloc(1, dtio->read_frame.frame_len);
|
||||
dtio->read_frame.buf_cap = dtio->read_frame.frame_len;
|
||||
if(!dtio->read_frame.buf) {
|
||||
log_err("dnstap io: out of memory (creating read "
|
||||
"buffer)");
|
||||
goto close_connection;
|
||||
}
|
||||
}
|
||||
if(dtio->read_frame.buf_count < dtio->read_frame.frame_len) {
|
||||
#ifdef HAVE_SSL
|
||||
if(dtio->ssl) {
|
||||
r = ssl_read_bytes(dtio, dtio->read_frame.buf+
|
||||
dtio->read_frame.buf_count,
|
||||
dtio->read_frame.buf_cap-
|
||||
dtio->read_frame.buf_count);
|
||||
} else {
|
||||
#endif
|
||||
r = receive_bytes(dtio, dtio->read_frame.buf+
|
||||
dtio->read_frame.buf_count,
|
||||
dtio->read_frame.buf_cap-
|
||||
dtio->read_frame.buf_count);
|
||||
#ifdef HAVE_SSL
|
||||
}
|
||||
#endif
|
||||
if(r == -1)
|
||||
return -1; /* continue reading */
|
||||
if(r == 0) {
|
||||
/* connection closed */
|
||||
goto close_connection;
|
||||
}
|
||||
dtio->read_frame.buf_count += r;
|
||||
if(dtio->read_frame.buf_count < dtio->read_frame.frame_len)
|
||||
return -1; /* continue reading */
|
||||
}
|
||||
|
||||
/* Complete frame received, check if this is a valid ACCEPT control
|
||||
* frame. */
|
||||
if(dtio->read_frame.frame_len < 4) {
|
||||
verbose(VERB_OPS, "dnstap: invalid data received");
|
||||
goto close_connection;
|
||||
}
|
||||
if(sldns_read_uint32(dtio->read_frame.buf) !=
|
||||
FSTRM_CONTROL_FRAME_ACCEPT) {
|
||||
verbose(VERB_ALGO, "dnstap: invalid control type received, "
|
||||
"ignored");
|
||||
dtio->ready_frame_sent = 0;
|
||||
dtio->accept_frame_received = 0;
|
||||
dtio_read_frame_free(&dtio->read_frame);
|
||||
return -1;
|
||||
}
|
||||
read_frame_done = 4; /* control frame type */
|
||||
|
||||
/* Iterate over control fields, ignore unknown types.
|
||||
* Need to be able to read at least 8 bytes (control field type +
|
||||
* length). */
|
||||
while(read_frame_done+8 < dtio->read_frame.frame_len) {
|
||||
uint32_t type = sldns_read_uint32(dtio->read_frame.buf +
|
||||
read_frame_done);
|
||||
uint32_t len = sldns_read_uint32(dtio->read_frame.buf +
|
||||
read_frame_done + 4);
|
||||
if(type == FSTRM_CONTROL_FIELD_TYPE_CONTENT_TYPE) {
|
||||
if(len == strlen(DNSTAP_CONTENT_TYPE) &&
|
||||
read_frame_done+8+len <=
|
||||
dtio->read_frame.frame_len &&
|
||||
memcmp(dtio->read_frame.buf + read_frame_done +
|
||||
+ 8, DNSTAP_CONTENT_TYPE, len) == 0) {
|
||||
if(!dtio_control_start_send(dtio)) {
|
||||
verbose(VERB_OPS, "dnstap io: out of "
|
||||
"memory while sending START frame");
|
||||
goto close_connection;
|
||||
}
|
||||
dtio->accept_frame_received = 1;
|
||||
return 1;
|
||||
} else {
|
||||
/* unknow content type */
|
||||
verbose(VERB_ALGO, "dnstap: ACCEPT frame "
|
||||
"contains unknown content type, "
|
||||
"closing connection");
|
||||
goto close_connection;
|
||||
}
|
||||
}
|
||||
/* unknown option, try next */
|
||||
read_frame_done += 8+len;
|
||||
}
|
||||
|
||||
|
||||
close_connection:
|
||||
dtio_del_output_event(dtio);
|
||||
dtio_reconnect_slow(dtio, DTIO_RECONNECT_TIMEOUT_SLOW);
|
||||
dtio_close_output(dtio);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** add the output file descriptor event for listening, read only */
|
||||
static int dtio_add_output_event_read(struct dt_io_thread* dtio)
|
||||
{
|
||||
@ -1002,6 +1228,24 @@ static int dtio_disable_brief_read(struct dt_io_thread* dtio)
|
||||
}
|
||||
#endif /* HAVE_SSL */
|
||||
|
||||
#ifdef HAVE_SSL
|
||||
/** enable the brief write condition */
|
||||
static int dtio_enable_brief_write(struct dt_io_thread* dtio)
|
||||
{
|
||||
dtio->ssl_brief_write = 1;
|
||||
return dtio_add_output_event_write(dtio);
|
||||
}
|
||||
#endif /* HAVE_SSL */
|
||||
|
||||
#ifdef HAVE_SSL
|
||||
/** disable the brief write condition */
|
||||
static int dtio_disable_brief_write(struct dt_io_thread* dtio)
|
||||
{
|
||||
dtio->ssl_brief_write = 0;
|
||||
return dtio_add_output_event_read(dtio);
|
||||
}
|
||||
#endif /* HAVE_SSL */
|
||||
|
||||
#ifdef HAVE_SSL
|
||||
/** check peer verification after ssl handshake connection, false if closed*/
|
||||
static int dtio_ssl_check_peer(struct dt_io_thread* dtio)
|
||||
@ -1175,8 +1419,13 @@ void dtio_output_cb(int ATTR_UNUSED(fd), short bits, void* arg)
|
||||
}
|
||||
#endif
|
||||
|
||||
if((bits&UB_EV_READ)) {
|
||||
if(!dtio_check_close(dtio))
|
||||
if((bits&UB_EV_READ || dtio->ssl_brief_write)) {
|
||||
if(dtio->ssl_brief_write)
|
||||
(void)dtio_disable_brief_write(dtio);
|
||||
if(dtio->ready_frame_sent && !dtio->accept_frame_received) {
|
||||
if(dtio_read_accept_frame(dtio) <= 0)
|
||||
return;
|
||||
} else if(!dtio_check_close(dtio))
|
||||
return;
|
||||
}
|
||||
|
||||
@ -1208,6 +1457,15 @@ void dtio_output_cb(int ATTR_UNUSED(fd), short bits, void* arg)
|
||||
|
||||
/* done with the current message */
|
||||
dtio_cur_msg_free(dtio);
|
||||
|
||||
/* If this is a bidirectional stream the first message will be
|
||||
* the READY control frame. We can only continue writing after
|
||||
* receiving an ACCEPT control frame. */
|
||||
if(dtio->is_bidirectional && !dtio->ready_frame_sent) {
|
||||
dtio->ready_frame_sent = 1;
|
||||
(void)dtio_add_output_event_read(dtio);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1240,6 +1498,13 @@ void dtio_cmd_cb(int fd, short ATTR_UNUSED(bits), void* arg)
|
||||
verbose(VERB_ALGO, "dnstap io: cmd channel cmd quit");
|
||||
} else if(r == 1 && cmd == DTIO_COMMAND_WAKEUP) {
|
||||
verbose(VERB_ALGO, "dnstap io: cmd channel cmd wakeup");
|
||||
|
||||
if(dtio->is_bidirectional && !dtio->accept_frame_received) {
|
||||
verbose(VERB_ALGO, "dnstap io: cmd wakeup ignored, "
|
||||
"waiting for ACCEPT control frame");
|
||||
return;
|
||||
}
|
||||
|
||||
/* reregister event */
|
||||
if(!dtio_add_output_event_write(dtio))
|
||||
return;
|
||||
@ -1561,6 +1826,25 @@ static int dtio_control_start_send(struct dt_io_thread* dtio)
|
||||
return 1;
|
||||
}
|
||||
|
||||
/** setup a ready control message */
|
||||
static int dtio_control_ready_send(struct dt_io_thread* dtio)
|
||||
{
|
||||
log_assert(dtio->cur_msg == NULL && dtio->cur_msg_len == 0);
|
||||
dtio->cur_msg = fstrm_create_control_frame_ready(DNSTAP_CONTENT_TYPE,
|
||||
&dtio->cur_msg_len);
|
||||
if(!dtio->cur_msg) {
|
||||
return 0;
|
||||
}
|
||||
/* setup to send the control message */
|
||||
/* set that the buffer needs to be sent, but the length
|
||||
* of that buffer is already written, that way the buffer can
|
||||
* start with 0 length and then the length of the control frame
|
||||
* in it */
|
||||
dtio->cur_msg_done = 0;
|
||||
dtio->cur_msg_len_done = 4;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/** open the output file descriptor for af_local */
|
||||
static int dtio_open_output_local(struct dt_io_thread* dtio)
|
||||
{
|
||||
@ -1693,7 +1977,8 @@ static void dtio_open_output(struct dt_io_thread* dtio)
|
||||
}
|
||||
dtio->check_nb_connect = 1;
|
||||
|
||||
/* the EV_READ is to catch channel close, write to write packets */
|
||||
/* the EV_READ is to read ACCEPT control messages, and catch channel
|
||||
* close. EV_WRITE is to write packets */
|
||||
ev = ub_event_new(dtio->event_base, dtio->fd,
|
||||
UB_EV_READ | UB_EV_WRITE | UB_EV_PERSIST, &dtio_output_cb,
|
||||
dtio);
|
||||
@ -1712,7 +1997,8 @@ static void dtio_open_output(struct dt_io_thread* dtio)
|
||||
dtio->event = ev;
|
||||
|
||||
/* setup protocol control message to start */
|
||||
if(!dtio_control_start_send(dtio)) {
|
||||
if((!dtio->is_bidirectional && !dtio_control_start_send(dtio)) ||
|
||||
(dtio->is_bidirectional && !dtio_control_ready_send(dtio)) ) {
|
||||
log_err("dnstap io: out of memory");
|
||||
ub_event_free(dtio->event);
|
||||
dtio->event = NULL;
|
||||
|
@ -88,6 +88,27 @@ struct dt_msg_entry {
|
||||
size_t len;
|
||||
};
|
||||
|
||||
/**
|
||||
* Containing buffer and counter for reading DNSTAP frames.
|
||||
*/
|
||||
struct dt_frame_read_buf {
|
||||
/** Buffer containing frame, except length counter(s). */
|
||||
void* buf;
|
||||
/** Number of bytes written to buffer. */
|
||||
size_t buf_count;
|
||||
/** Capacity of the buffer. */
|
||||
size_t buf_cap;
|
||||
|
||||
/** Frame length field. Will contain the 2nd length field for control
|
||||
* frames. */
|
||||
uint32_t frame_len;
|
||||
/** Number of bytes that have been written to the frame_length field. */
|
||||
size_t frame_len_done;
|
||||
|
||||
/** Set to 1 if this is a control frame, 0 otherwise (ie data frame). */
|
||||
int control_frame;
|
||||
};
|
||||
|
||||
/**
|
||||
* IO thread that reads from the queues and writes them.
|
||||
*/
|
||||
@ -130,6 +151,9 @@ struct dt_io_thread {
|
||||
* This happens during negotiation, we then do not want to write,
|
||||
* but wait for a read event. */
|
||||
int ssl_brief_read;
|
||||
/** true if SSL_read is waiting for a write event. Set back to 0 after
|
||||
* single write event is handled. */
|
||||
int ssl_brief_write;
|
||||
|
||||
/** the buffer that currently getting written, or NULL if no
|
||||
* (partial) message written now */
|
||||
@ -171,6 +195,16 @@ struct dt_io_thread {
|
||||
* and client certificates can be used for authentication. */
|
||||
int upstream_is_tls;
|
||||
|
||||
/** Perform bidirectional Frame Streams handshake before sending
|
||||
* messages. */
|
||||
int is_bidirectional;
|
||||
/** Set if the READY control frame has been sent. */
|
||||
int ready_frame_sent;
|
||||
/** Set if valid ACCEPT frame is received. */
|
||||
int accept_frame_received;
|
||||
/** (partially) read frame */
|
||||
struct dt_frame_read_buf read_frame;
|
||||
|
||||
/** the file path for unix socket (or NULL) */
|
||||
char* socket_path;
|
||||
/** the ip address and port number (or NULL) */
|
||||
|
@ -770,10 +770,11 @@ void tap_data_free(struct tap_data* data)
|
||||
|
||||
/** reply with ACCEPT control frame to bidirectional client,
|
||||
* returns 0 on error */
|
||||
static int reply_with_accept(int fd)
|
||||
static int reply_with_accept(struct tap_data* data)
|
||||
{
|
||||
#ifdef USE_DNSTAP
|
||||
/* len includes the escape and framelength */
|
||||
int r;
|
||||
size_t len = 0;
|
||||
void* acceptframe = fstrm_create_control_frame_accept(
|
||||
DNSTAP_CONTENT_TYPE, &len);
|
||||
@ -782,26 +783,39 @@ static int reply_with_accept(int fd)
|
||||
return 0;
|
||||
}
|
||||
|
||||
fd_set_block(fd);
|
||||
if(send(fd, acceptframe, len, 0) == -1) {
|
||||
fd_set_block(data->fd);
|
||||
if(data->ssl) {
|
||||
if((r=SSL_write(data->ssl, acceptframe, len)) <= 0) {
|
||||
if(SSL_get_error(data->ssl, r) == SSL_ERROR_ZERO_RETURN)
|
||||
log_err("SSL_write, peer closed connection");
|
||||
else
|
||||
log_err("could not SSL_write");
|
||||
fd_set_nonblock(data->fd);
|
||||
free(acceptframe);
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
if(send(data->fd, acceptframe, len, 0) == -1) {
|
||||
#ifndef USE_WINSOCK
|
||||
log_err("send failed: %s", strerror(errno));
|
||||
log_err("send failed: %s", strerror(errno));
|
||||
#else
|
||||
log_err("send failed: %s", wsa_strerror(WSAGetLastError()));
|
||||
log_err("send failed: %s",
|
||||
wsa_strerror(WSAGetLastError()));
|
||||
#endif
|
||||
fd_set_nonblock(fd);
|
||||
free(acceptframe);
|
||||
return 0;
|
||||
fd_set_nonblock(data->fd);
|
||||
free(acceptframe);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
if(verbosity) log_info("sent control frame(accept) content-type:(%s)",
|
||||
DNSTAP_CONTENT_TYPE);
|
||||
|
||||
fd_set_nonblock(fd);
|
||||
fd_set_nonblock(data->fd);
|
||||
free(acceptframe);
|
||||
return 1;
|
||||
#else
|
||||
log_err("no dnstap compiled, no reply");
|
||||
(void)fd;
|
||||
(void)data;
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
@ -1033,7 +1047,7 @@ void dtio_tap_callback(int fd, short ATTR_UNUSED(bits), void* arg)
|
||||
FSTRM_CONTROL_FRAME_READY) {
|
||||
data->is_bidirectional = 1;
|
||||
if(verbosity) log_info("bidirectional stream");
|
||||
if(!reply_with_accept(fd)) {
|
||||
if(!reply_with_accept(data)) {
|
||||
tap_data_free(data);
|
||||
}
|
||||
} else if(data->len >= 4 && sldns_read_uint32(data->frame) ==
|
||||
|
@ -1,3 +1,13 @@
|
||||
16 July 2020: Wouter
|
||||
- Fix check conf test for referencing installation paths.
|
||||
- Fix unused variable warning for clang analyzer.
|
||||
|
||||
16 July 2020: George
|
||||
- Introduce 'include-toplevel:' configuration option.
|
||||
|
||||
16 July 2020: Ralph
|
||||
- Add bidirectional frame streams support.
|
||||
|
||||
8 July 2020: Wouter
|
||||
- Fix add missing DSA header, for compilation without deprecated
|
||||
OpenSSL APIs.
|
||||
|
@ -5,9 +5,13 @@
|
||||
#
|
||||
# this is a comment.
|
||||
|
||||
#Use this to include other text into the file.
|
||||
# Use this anywhere in the file to include other text into this file.
|
||||
#include: "otherfile.conf"
|
||||
|
||||
# Use this anywhere in the file to include other text, that explicitly starts a
|
||||
# clause, into this file. Text after this directive needs to start a clause.
|
||||
#include-toplevel: "otherfile.conf"
|
||||
|
||||
# The server clause sets the main parameters.
|
||||
server:
|
||||
# whitespace is not necessary, but looks cleaner.
|
||||
@ -1049,6 +1053,8 @@ remote-control:
|
||||
# upstream log destination, by socket path, TCP or TLS destination.
|
||||
# dnstap:
|
||||
# dnstap-enable: no
|
||||
# # if set to yes frame streams will be used in bidirectional mode
|
||||
# dnstap-bidirectional: yes
|
||||
# dnstap-socket-path: "@DNSTAP_SOCKET_PATH@"
|
||||
# # if "" use the unix socket in dnstap-socket-path, otherwise,
|
||||
# # set it to "IPaddress[@port]" of the destination.
|
||||
|
@ -77,6 +77,12 @@ for the included files works, relative pathnames for the included names work
|
||||
if the directory where the daemon is started equals its chroot/working
|
||||
directory or is specified before the include statement with directory: dir.
|
||||
Wildcards can be used to include multiple files, see \fIglob\fR(7).
|
||||
.P
|
||||
For a more structural include option, the
|
||||
.B include\-toplevel:
|
||||
directive can be used. This closes whatever clause is currently active (if any)
|
||||
and forces the use of clauses in the included files and right after this
|
||||
directive.
|
||||
.SS "Server Options"
|
||||
These options are part of the
|
||||
.B server:
|
||||
@ -2189,6 +2195,10 @@ If dnstap is enabled. Default no. If yes, it connects to the dnstap server
|
||||
and if any of the dnstap-log-..-messages options is enabled it sends logs
|
||||
for those messages to the server.
|
||||
.TP
|
||||
.B dnstap-bidirectional: \fI<yes or no>
|
||||
Use frame streams in bidirectional mode to transfer DNSTAP messages. Default is
|
||||
yes.
|
||||
.TP
|
||||
.B dnstap-socket-path: \fI<file name>
|
||||
Sets the unix socket file name for connecting to the server that is
|
||||
listening on that socket. Default is "@DNSTAP_SOCKET_PATH@".
|
||||
|
1
testdata/04-checkconf.tdir/bad.badfwd
vendored
1
testdata/04-checkconf.tdir/bad.badfwd
vendored
@ -2,6 +2,7 @@ server:
|
||||
# to make sure the check doesn't fail on username or chrootdir.
|
||||
username: ""
|
||||
chroot: ""
|
||||
directory: ""
|
||||
|
||||
forward-zone:
|
||||
name: "example.com"
|
||||
|
3
testdata/04-checkconf.tdir/bad.include-toplevel.1
vendored
Normal file
3
testdata/04-checkconf.tdir/bad.include-toplevel.1
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
include-toplevel: include.withoutclauses.*
|
||||
server:
|
||||
identity: "top 1"
|
5
testdata/04-checkconf.tdir/bad.include-toplevel.2
vendored
Normal file
5
testdata/04-checkconf.tdir/bad.include-toplevel.2
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
include-toplevel: include.withclauses.*
|
||||
server:
|
||||
identity: "top 1"
|
||||
include: include.withoutclauses.*
|
||||
include-toplevel: include.withoutclauses.*
|
6
testdata/04-checkconf.tdir/bad.include-toplevel.3
vendored
Normal file
6
testdata/04-checkconf.tdir/bad.include-toplevel.3
vendored
Normal file
@ -0,0 +1,6 @@
|
||||
include-toplevel: include.withclauses.*
|
||||
server:
|
||||
identity: "top 1"
|
||||
include: include.withoutclauses.*
|
||||
include-toplevel: include.withclauses.*
|
||||
include: include.withoutclauses.*
|
7
testdata/04-checkconf.tdir/bad.include-toplevel.4
vendored
Normal file
7
testdata/04-checkconf.tdir/bad.include-toplevel.4
vendored
Normal file
@ -0,0 +1,7 @@
|
||||
include-toplevel: include.withclauses.*
|
||||
server:
|
||||
identity: "top 1"
|
||||
include: include.withoutclauses.*
|
||||
include-toplevel: include.withclauses.*
|
||||
include: include.withclauses.*
|
||||
include-toplevel: include.withoutclauses.*
|
8
testdata/04-checkconf.tdir/bad.include-toplevel.5
vendored
Normal file
8
testdata/04-checkconf.tdir/bad.include-toplevel.5
vendored
Normal file
@ -0,0 +1,8 @@
|
||||
include-toplevel: include.withclauses.*
|
||||
server:
|
||||
identity: "top 1"
|
||||
include: include.withoutclauses.*
|
||||
include-toplevel: include.withsomeclauses.*
|
||||
include: include.withclauses.*
|
||||
include-toplevel: include.withclauses.*
|
||||
server: identity: "top 2"
|
10
testdata/04-checkconf.tdir/bad.include-toplevel.6
vendored
Normal file
10
testdata/04-checkconf.tdir/bad.include-toplevel.6
vendored
Normal file
@ -0,0 +1,10 @@
|
||||
include-toplevel: include.withclauses.*
|
||||
include-toplevel: include.withclauses.*
|
||||
server:
|
||||
identity: "top 1"
|
||||
include: include.withoutclauses.*
|
||||
include-toplevel: include.withclauses.*
|
||||
include: include.withclauses.*
|
||||
include-toplevel: include.withclauses.*
|
||||
server: identity: "top 2"
|
||||
include-toplevel: include.includetop.withoutclauses.*
|
11
testdata/04-checkconf.tdir/bad.include-toplevel.7
vendored
Normal file
11
testdata/04-checkconf.tdir/bad.include-toplevel.7
vendored
Normal file
@ -0,0 +1,11 @@
|
||||
include-toplevel: include.withclauses.*
|
||||
include-toplevel: include.withclauses.*
|
||||
server:
|
||||
identity: "top 1"
|
||||
include: include.withoutclauses.*
|
||||
include-toplevel: include.withclauses.*
|
||||
include: include.withclauses.*
|
||||
include-toplevel: include.withclauses.*
|
||||
server: identity: "top 2"
|
||||
include-toplevel: include.includetop.withclauses.*
|
||||
include-toplevel: include.include.withoutclauses.*
|
2
testdata/04-checkconf.tdir/bad.user
vendored
2
testdata/04-checkconf.tdir/bad.user
vendored
@ -1,2 +1,4 @@
|
||||
server:
|
||||
username: blabla_noexist_user
|
||||
chroot: ""
|
||||
directory: ""
|
||||
|
16
testdata/04-checkconf.tdir/good.include-toplevel
vendored
Normal file
16
testdata/04-checkconf.tdir/good.include-toplevel
vendored
Normal file
@ -0,0 +1,16 @@
|
||||
include-toplevel: include.withclauses.*
|
||||
include-toplevel: include.withclauses.*
|
||||
server:
|
||||
identity: "top 1"
|
||||
include: include.withoutclauses.*
|
||||
include-toplevel: include.withclauses.*
|
||||
include: include.withclauses.*
|
||||
include-toplevel: include.withclauses.*
|
||||
server: identity: "top 2"
|
||||
include-toplevel: include.includetop.withclauses.*
|
||||
include-toplevel: include.include.withclauses.*
|
||||
include-toplevel: include.include.withclauses.*
|
||||
server:
|
||||
chroot: ""
|
||||
directory: ""
|
||||
username: ""
|
1
testdata/04-checkconf.tdir/include.include.withclauses.1
vendored
Normal file
1
testdata/04-checkconf.tdir/include.include.withclauses.1
vendored
Normal file
@ -0,0 +1 @@
|
||||
include: include.withclauses.*
|
1
testdata/04-checkconf.tdir/include.include.withclauses.2
vendored
Normal file
1
testdata/04-checkconf.tdir/include.include.withclauses.2
vendored
Normal file
@ -0,0 +1 @@
|
||||
include: include.withclauses.*
|
1
testdata/04-checkconf.tdir/include.include.withclauses.3
vendored
Normal file
1
testdata/04-checkconf.tdir/include.include.withclauses.3
vendored
Normal file
@ -0,0 +1 @@
|
||||
include: include.withclauses.*
|
1
testdata/04-checkconf.tdir/include.include.withoutclauses.1
vendored
Normal file
1
testdata/04-checkconf.tdir/include.include.withoutclauses.1
vendored
Normal file
@ -0,0 +1 @@
|
||||
include: include.withoutclauses.*
|
1
testdata/04-checkconf.tdir/include.include.withoutclauses.2
vendored
Normal file
1
testdata/04-checkconf.tdir/include.include.withoutclauses.2
vendored
Normal file
@ -0,0 +1 @@
|
||||
include: include.withoutclauses.*
|
1
testdata/04-checkconf.tdir/include.include.withoutclauses.3
vendored
Normal file
1
testdata/04-checkconf.tdir/include.include.withoutclauses.3
vendored
Normal file
@ -0,0 +1 @@
|
||||
include: include.withoutclauses.*
|
1
testdata/04-checkconf.tdir/include.includetop.withclauses.1
vendored
Normal file
1
testdata/04-checkconf.tdir/include.includetop.withclauses.1
vendored
Normal file
@ -0,0 +1 @@
|
||||
include-toplevel: include.withclauses.*
|
1
testdata/04-checkconf.tdir/include.includetop.withclauses.2
vendored
Normal file
1
testdata/04-checkconf.tdir/include.includetop.withclauses.2
vendored
Normal file
@ -0,0 +1 @@
|
||||
include-toplevel: include.withclauses.*
|
1
testdata/04-checkconf.tdir/include.includetop.withclauses.3
vendored
Normal file
1
testdata/04-checkconf.tdir/include.includetop.withclauses.3
vendored
Normal file
@ -0,0 +1 @@
|
||||
include-toplevel: include.withclauses.*
|
1
testdata/04-checkconf.tdir/include.includetop.withoutclauses.1
vendored
Normal file
1
testdata/04-checkconf.tdir/include.includetop.withoutclauses.1
vendored
Normal file
@ -0,0 +1 @@
|
||||
include-toplevel: include.withoutclauses.*
|
1
testdata/04-checkconf.tdir/include.includetop.withoutclauses.2
vendored
Normal file
1
testdata/04-checkconf.tdir/include.includetop.withoutclauses.2
vendored
Normal file
@ -0,0 +1 @@
|
||||
include-toplevel: include.withoutclauses.*
|
1
testdata/04-checkconf.tdir/include.includetop.withoutclauses.3
vendored
Normal file
1
testdata/04-checkconf.tdir/include.includetop.withoutclauses.3
vendored
Normal file
@ -0,0 +1 @@
|
||||
include-toplevel: include.withoutclauses.*
|
1
testdata/04-checkconf.tdir/include.withclauses.1
vendored
Normal file
1
testdata/04-checkconf.tdir/include.withclauses.1
vendored
Normal file
@ -0,0 +1 @@
|
||||
server: identity: "withclauses1"
|
1
testdata/04-checkconf.tdir/include.withclauses.2
vendored
Normal file
1
testdata/04-checkconf.tdir/include.withclauses.2
vendored
Normal file
@ -0,0 +1 @@
|
||||
server: identity: "withclauses2"
|
1
testdata/04-checkconf.tdir/include.withclauses.3
vendored
Normal file
1
testdata/04-checkconf.tdir/include.withclauses.3
vendored
Normal file
@ -0,0 +1 @@
|
||||
server: identity: "withclauses3"
|
1
testdata/04-checkconf.tdir/include.withoutclauses.1
vendored
Normal file
1
testdata/04-checkconf.tdir/include.withoutclauses.1
vendored
Normal file
@ -0,0 +1 @@
|
||||
identity: "withoutclauses1"
|
1
testdata/04-checkconf.tdir/include.withoutclauses.2
vendored
Normal file
1
testdata/04-checkconf.tdir/include.withoutclauses.2
vendored
Normal file
@ -0,0 +1 @@
|
||||
identity: "withoutclauses2"
|
1
testdata/04-checkconf.tdir/include.withoutclauses.3
vendored
Normal file
1
testdata/04-checkconf.tdir/include.withoutclauses.3
vendored
Normal file
@ -0,0 +1 @@
|
||||
identity: "withoutclauses3"
|
1
testdata/04-checkconf.tdir/include.withsomeclauses.1
vendored
Normal file
1
testdata/04-checkconf.tdir/include.withsomeclauses.1
vendored
Normal file
@ -0,0 +1 @@
|
||||
server: identity: "withsomeclauses1"
|
1
testdata/04-checkconf.tdir/include.withsomeclauses.2
vendored
Normal file
1
testdata/04-checkconf.tdir/include.withsomeclauses.2
vendored
Normal file
@ -0,0 +1 @@
|
||||
identity: "withsomeclauses2"
|
1
testdata/04-checkconf.tdir/include.withsomeclauses.3
vendored
Normal file
1
testdata/04-checkconf.tdir/include.withsomeclauses.3
vendored
Normal file
@ -0,0 +1 @@
|
||||
identity: "withsomeclauses3"
|
@ -299,6 +299,7 @@ config_create(void)
|
||||
if(!(cfg->dnstap_socket_path = strdup(DNSTAP_SOCKET_PATH)))
|
||||
goto error_exit;
|
||||
#endif
|
||||
cfg->dnstap_bidirectional = 1;
|
||||
cfg->dnstap_tls = 1;
|
||||
cfg->disable_dnssec_lame_check = 0;
|
||||
cfg->ip_ratelimit = 0;
|
||||
@ -641,6 +642,7 @@ int config_set_option(struct config_file* cfg, const char* opt,
|
||||
#endif
|
||||
#ifdef USE_DNSTAP
|
||||
else S_YNO("dnstap-enable:", dnstap)
|
||||
else S_YNO("dnstap-bidirectional:", dnstap_bidirectional)
|
||||
else S_STR("dnstap-socket-path:", dnstap_socket_path)
|
||||
else S_STR("dnstap-ip:", dnstap_ip)
|
||||
else S_YNO("dnstap-tls:", dnstap_tls)
|
||||
@ -1058,6 +1060,7 @@ config_get_option(struct config_file* cfg, const char* opt,
|
||||
#endif
|
||||
#ifdef USE_DNSTAP
|
||||
else O_YNO(opt, "dnstap-enable", dnstap)
|
||||
else O_YNO(opt, "dnstap-bidirectional", dnstap_bidirectional)
|
||||
else O_STR(opt, "dnstap-socket-path", dnstap_socket_path)
|
||||
else O_STR(opt, "dnstap-ip", dnstap_ip)
|
||||
else O_YNO(opt, "dnstap-tls", dnstap_tls)
|
||||
|
@ -483,6 +483,8 @@ struct config_file {
|
||||
|
||||
/** true to enable dnstap support */
|
||||
int dnstap;
|
||||
/** using bidirectional frame streams if true */
|
||||
int dnstap_bidirectional;
|
||||
/** dnstap socket path */
|
||||
char* dnstap_socket_path;
|
||||
/** dnstap IP */
|
||||
|
5302
util/configlexer.c
5302
util/configlexer.c
File diff suppressed because it is too large
Load Diff
@ -45,11 +45,13 @@ struct inc_state {
|
||||
int line;
|
||||
YY_BUFFER_STATE buffer;
|
||||
struct inc_state* next;
|
||||
int inc_toplevel;
|
||||
};
|
||||
static struct inc_state* config_include_stack = NULL;
|
||||
static int inc_depth = 0;
|
||||
static int inc_prev = 0;
|
||||
static int num_args = 0;
|
||||
static int inc_toplevel = 0;
|
||||
|
||||
void init_cfg_parse(void)
|
||||
{
|
||||
@ -57,14 +59,15 @@ void init_cfg_parse(void)
|
||||
inc_depth = 0;
|
||||
inc_prev = 0;
|
||||
num_args = 0;
|
||||
inc_toplevel = 0;
|
||||
}
|
||||
|
||||
static void config_start_include(const char* filename)
|
||||
static void config_start_include(const char* filename, int toplevel)
|
||||
{
|
||||
FILE *input;
|
||||
struct inc_state* s;
|
||||
char* nm;
|
||||
if(inc_depth++ > 100000) {
|
||||
if(inc_depth+1 > 100000) {
|
||||
ub_c_error_msg("too many include files");
|
||||
return;
|
||||
}
|
||||
@ -96,17 +99,20 @@ static void config_start_include(const char* filename)
|
||||
return;
|
||||
}
|
||||
LEXOUT(("switch_to_include_file(%s)\n", filename));
|
||||
inc_depth++;
|
||||
s->filename = cfg_parser->filename;
|
||||
s->line = cfg_parser->line;
|
||||
s->buffer = YY_CURRENT_BUFFER;
|
||||
s->inc_toplevel = inc_toplevel;
|
||||
s->next = config_include_stack;
|
||||
config_include_stack = s;
|
||||
cfg_parser->filename = nm;
|
||||
cfg_parser->line = 1;
|
||||
inc_toplevel = toplevel;
|
||||
yy_switch_to_buffer(yy_create_buffer(input, YY_BUF_SIZE));
|
||||
}
|
||||
|
||||
static void config_start_include_glob(const char* filename)
|
||||
static void config_start_include_glob(const char* filename, int toplevel)
|
||||
{
|
||||
|
||||
/* check for wildcards */
|
||||
@ -139,19 +145,19 @@ static void config_start_include_glob(const char* filename)
|
||||
globfree(&g);
|
||||
if(r == GLOB_NOMATCH)
|
||||
return; /* no matches for pattern */
|
||||
config_start_include(filename); /* let original deal with it */
|
||||
config_start_include(filename, toplevel); /* let original deal with it */
|
||||
return;
|
||||
}
|
||||
/* process files found, if any */
|
||||
for(i=(int)g.gl_pathc-1; i>=0; i--) {
|
||||
config_start_include(g.gl_pathv[i]);
|
||||
config_start_include(g.gl_pathv[i], toplevel);
|
||||
}
|
||||
globfree(&g);
|
||||
return;
|
||||
}
|
||||
#endif /* HAVE_GLOB */
|
||||
|
||||
config_start_include(filename);
|
||||
config_start_include(filename, toplevel);
|
||||
}
|
||||
|
||||
static void config_end_include(void)
|
||||
@ -165,6 +171,7 @@ static void config_end_include(void)
|
||||
yy_delete_buffer(YY_CURRENT_BUFFER);
|
||||
yy_switch_to_buffer(s->buffer);
|
||||
config_include_stack = s->next;
|
||||
inc_toplevel = s->inc_toplevel;
|
||||
free(s);
|
||||
}
|
||||
|
||||
@ -199,7 +206,7 @@ COLON \:
|
||||
DQANY [^\"\n\r\\]|\\.
|
||||
SQANY [^\'\n\r\\]|\\.
|
||||
|
||||
%x quotedstring singlequotedstr include include_quoted val
|
||||
%x quotedstring singlequotedstr include include_quoted val include_toplevel include_toplevel_quoted
|
||||
|
||||
%%
|
||||
<INITIAL,val>{SPACE}* {
|
||||
@ -435,6 +442,7 @@ access-control-view{COLON} { YDVAR(2, VAR_ACCESS_CONTROL_VIEW) }
|
||||
local-zone-override{COLON} { YDVAR(3, VAR_LOCAL_ZONE_OVERRIDE) }
|
||||
dnstap{COLON} { YDVAR(0, VAR_DNSTAP) }
|
||||
dnstap-enable{COLON} { YDVAR(1, VAR_DNSTAP_ENABLE) }
|
||||
dnstap-bidirectional{COLON} { YDVAR(1, VAR_DNSTAP_BIDIRECTIONAL) }
|
||||
dnstap-socket-path{COLON} { YDVAR(1, VAR_DNSTAP_SOCKET_PATH) }
|
||||
dnstap-ip{COLON} { YDVAR(1, VAR_DNSTAP_IP) }
|
||||
dnstap-tls{COLON} { YDVAR(1, VAR_DNSTAP_TLS) }
|
||||
@ -566,7 +574,7 @@ tcp-connection-limit{COLON} { YDVAR(2, VAR_TCP_CONNECTION_LIMIT) }
|
||||
<include>\" { LEXOUT(("IQS ")); BEGIN(include_quoted); }
|
||||
<include>{UNQUOTEDLETTER}* {
|
||||
LEXOUT(("Iunquotedstr(%s) ", yytext));
|
||||
config_start_include_glob(yytext);
|
||||
config_start_include_glob(yytext, 0);
|
||||
BEGIN(inc_prev);
|
||||
}
|
||||
<include_quoted><<EOF>> {
|
||||
@ -579,7 +587,7 @@ tcp-connection-limit{COLON} { YDVAR(2, VAR_TCP_CONNECTION_LIMIT) }
|
||||
<include_quoted>\" {
|
||||
LEXOUT(("IQE "));
|
||||
yytext[yyleng - 1] = '\0';
|
||||
config_start_include_glob(yytext);
|
||||
config_start_include_glob(yytext, 0);
|
||||
BEGIN(inc_prev);
|
||||
}
|
||||
<INITIAL,val><<EOF>> {
|
||||
@ -588,11 +596,47 @@ tcp-connection-limit{COLON} { YDVAR(2, VAR_TCP_CONNECTION_LIMIT) }
|
||||
if (!config_include_stack) {
|
||||
yyterminate();
|
||||
} else {
|
||||
int prev_toplevel = inc_toplevel;
|
||||
fclose(yyin);
|
||||
config_end_include();
|
||||
if(prev_toplevel) return (VAR_FORCE_TOPLEVEL);
|
||||
}
|
||||
}
|
||||
|
||||
/* include-toplevel: directive */
|
||||
<INITIAL,val>include-toplevel{COLON} {
|
||||
LEXOUT(("v(%s) ", yytext)); inc_prev = YYSTATE; BEGIN(include_toplevel);
|
||||
}
|
||||
<include_toplevel><<EOF>> {
|
||||
yyerror("EOF inside include_toplevel directive");
|
||||
BEGIN(inc_prev);
|
||||
}
|
||||
<include_toplevel>{SPACE}* { LEXOUT(("ITSP ")); /* ignore */ }
|
||||
<include_toplevel>{NEWLINE} { LEXOUT(("NL\n")); cfg_parser->line++; }
|
||||
<include_toplevel>\" { LEXOUT(("ITQS ")); BEGIN(include_toplevel_quoted); }
|
||||
<include_toplevel>{UNQUOTEDLETTER}* {
|
||||
LEXOUT(("ITunquotedstr(%s) ", yytext));
|
||||
config_start_include_glob(yytext, 1);
|
||||
BEGIN(inc_prev);
|
||||
return (VAR_FORCE_TOPLEVEL);
|
||||
}
|
||||
<include_toplevel_quoted><<EOF>> {
|
||||
yyerror("EOF inside quoted string");
|
||||
BEGIN(inc_prev);
|
||||
}
|
||||
<include_toplevel_quoted>{DQANY}* { LEXOUT(("ITSTR(%s) ", yytext)); yymore(); }
|
||||
<include_toplevel_quoted>{NEWLINE} {
|
||||
yyerror("newline before \" in include name");
|
||||
cfg_parser->line++; BEGIN(inc_prev);
|
||||
}
|
||||
<include_toplevel_quoted>\" {
|
||||
LEXOUT(("ITQE "));
|
||||
yytext[yyleng - 1] = '\0';
|
||||
config_start_include_glob(yytext, 1);
|
||||
BEGIN(inc_prev);
|
||||
return (VAR_FORCE_TOPLEVEL);
|
||||
}
|
||||
|
||||
<val>{UNQUOTEDLETTER}* { LEXOUT(("unquotedstr(%s) ", yytext));
|
||||
if(--num_args == 0) { BEGIN(INITIAL); }
|
||||
yylval.str = strdup(yytext); return STRING_ARG; }
|
||||
|
4144
util/configparser.c
4144
util/configparser.c
File diff suppressed because it is too large
Load Diff
1126
util/configparser.h
1126
util/configparser.h
File diff suppressed because it is too large
Load Diff
@ -69,6 +69,7 @@ extern struct config_parser_state* cfg_parser;
|
||||
|
||||
%token SPACE LETTER NEWLINE COMMENT COLON ANY ZONESTR
|
||||
%token <str> STRING_ARG
|
||||
%token VAR_FORCE_TOPLEVEL
|
||||
%token VAR_SERVER VAR_VERBOSITY VAR_NUM_THREADS VAR_PORT
|
||||
%token VAR_OUTGOING_RANGE VAR_INTERFACE VAR_PREFER_IP4
|
||||
%token VAR_DO_IP4 VAR_DO_IP6 VAR_PREFER_IP6 VAR_DO_UDP VAR_DO_TCP
|
||||
@ -119,7 +120,7 @@ extern struct config_parser_state* cfg_parser;
|
||||
%token VAR_DNSTAP VAR_DNSTAP_ENABLE VAR_DNSTAP_SOCKET_PATH VAR_DNSTAP_IP
|
||||
%token VAR_DNSTAP_TLS VAR_DNSTAP_TLS_SERVER_NAME VAR_DNSTAP_TLS_CERT_BUNDLE
|
||||
%token VAR_DNSTAP_TLS_CLIENT_KEY_FILE VAR_DNSTAP_TLS_CLIENT_CERT_FILE
|
||||
%token VAR_DNSTAP_SEND_IDENTITY VAR_DNSTAP_SEND_VERSION
|
||||
%token VAR_DNSTAP_SEND_IDENTITY VAR_DNSTAP_SEND_VERSION VAR_DNSTAP_BIDIRECTIONAL
|
||||
%token VAR_DNSTAP_IDENTITY VAR_DNSTAP_VERSION
|
||||
%token VAR_DNSTAP_LOG_RESOLVER_QUERY_MESSAGES
|
||||
%token VAR_DNSTAP_LOG_RESOLVER_RESPONSE_MESSAGES
|
||||
@ -183,16 +184,21 @@ toplevelvar: serverstart contents_server | stubstart contents_stub |
|
||||
rcstart contents_rc | dtstart contents_dt | viewstart contents_view |
|
||||
dnscstart contents_dnsc | cachedbstart contents_cachedb |
|
||||
ipsetstart contents_ipset | authstart contents_auth |
|
||||
rpzstart contents_rpz | dynlibstart contents_dl
|
||||
rpzstart contents_rpz | dynlibstart contents_dl |
|
||||
force_toplevel
|
||||
;
|
||||
force_toplevel: VAR_FORCE_TOPLEVEL
|
||||
{
|
||||
OUTYY(("\nP(force-toplevel)\n"));
|
||||
}
|
||||
;
|
||||
|
||||
/* server: declaration */
|
||||
serverstart: VAR_SERVER
|
||||
{
|
||||
OUTYY(("\nP(server:)\n"));
|
||||
OUTYY(("\nP(server:)\n"));
|
||||
}
|
||||
;
|
||||
contents_server: contents_server content_server
|
||||
contents_server: contents_server content_server
|
||||
| ;
|
||||
content_server: server_num_threads | server_verbosity | server_port |
|
||||
server_outgoing_range | server_do_ip4 |
|
||||
@ -2768,7 +2774,7 @@ dtstart: VAR_DNSTAP
|
||||
;
|
||||
contents_dt: contents_dt content_dt
|
||||
| ;
|
||||
content_dt: dt_dnstap_enable | dt_dnstap_socket_path |
|
||||
content_dt: dt_dnstap_enable | dt_dnstap_socket_path | dt_dnstap_bidirectional |
|
||||
dt_dnstap_ip | dt_dnstap_tls | dt_dnstap_tls_server_name |
|
||||
dt_dnstap_tls_cert_bundle |
|
||||
dt_dnstap_tls_client_key_file | dt_dnstap_tls_client_cert_file |
|
||||
@ -2790,6 +2796,16 @@ dt_dnstap_enable: VAR_DNSTAP_ENABLE STRING_ARG
|
||||
free($2);
|
||||
}
|
||||
;
|
||||
dt_dnstap_bidirectional: VAR_DNSTAP_BIDIRECTIONAL STRING_ARG
|
||||
{
|
||||
OUTYY(("P(dt_dnstap_bidirectional:%s)\n", $2));
|
||||
if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0)
|
||||
yyerror("expected yes or no.");
|
||||
else cfg_parser->cfg->dnstap_bidirectional =
|
||||
(strcmp($2, "yes")==0);
|
||||
free($2);
|
||||
}
|
||||
;
|
||||
dt_dnstap_socket_path: VAR_DNSTAP_SOCKET_PATH STRING_ARG
|
||||
{
|
||||
OUTYY(("P(dt_dnstap_socket_path:%s)\n", $2));
|
||||
|
Loading…
Reference in New Issue
Block a user