Merge branch 'master' into infra-keep-probing

This commit is contained in:
W.C.A. Wijngaards 2020-07-16 16:00:06 +02:00
commit 3d1383bed3
47 changed files with 5999 additions and 5267 deletions

View File

@ -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 */

View File

@ -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;

View File

@ -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.

View File

@ -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;

View File

@ -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) */

View File

@ -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) ==

View File

@ -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.

View File

@ -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.

View File

@ -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@".

View File

@ -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"

View File

@ -0,0 +1,3 @@
include-toplevel: include.withoutclauses.*
server:
identity: "top 1"

View File

@ -0,0 +1,5 @@
include-toplevel: include.withclauses.*
server:
identity: "top 1"
include: include.withoutclauses.*
include-toplevel: include.withoutclauses.*

View File

@ -0,0 +1,6 @@
include-toplevel: include.withclauses.*
server:
identity: "top 1"
include: include.withoutclauses.*
include-toplevel: include.withclauses.*
include: include.withoutclauses.*

View 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.*

View 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"

View 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.*

View 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.*

View File

@ -1,2 +1,4 @@
server:
username: blabla_noexist_user
chroot: ""
directory: ""

View 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: ""

View File

@ -0,0 +1 @@
include: include.withclauses.*

View File

@ -0,0 +1 @@
include: include.withclauses.*

View File

@ -0,0 +1 @@
include: include.withclauses.*

View File

@ -0,0 +1 @@
include: include.withoutclauses.*

View File

@ -0,0 +1 @@
include: include.withoutclauses.*

View File

@ -0,0 +1 @@
include: include.withoutclauses.*

View File

@ -0,0 +1 @@
include-toplevel: include.withclauses.*

View File

@ -0,0 +1 @@
include-toplevel: include.withclauses.*

View File

@ -0,0 +1 @@
include-toplevel: include.withclauses.*

View File

@ -0,0 +1 @@
include-toplevel: include.withoutclauses.*

View File

@ -0,0 +1 @@
include-toplevel: include.withoutclauses.*

View File

@ -0,0 +1 @@
include-toplevel: include.withoutclauses.*

View File

@ -0,0 +1 @@
server: identity: "withclauses1"

View File

@ -0,0 +1 @@
server: identity: "withclauses2"

View File

@ -0,0 +1 @@
server: identity: "withclauses3"

View File

@ -0,0 +1 @@
identity: "withoutclauses1"

View File

@ -0,0 +1 @@
identity: "withoutclauses2"

View File

@ -0,0 +1 @@
identity: "withoutclauses3"

View File

@ -0,0 +1 @@
server: identity: "withsomeclauses1"

View File

@ -0,0 +1 @@
identity: "withsomeclauses2"

View File

@ -0,0 +1 @@
identity: "withsomeclauses3"

View File

@ -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)

View File

@ -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 */

File diff suppressed because it is too large Load Diff

View File

@ -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; }

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -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));