From 8f14388cb43be382a43619b7c0abe7308d4a3505 Mon Sep 17 00:00:00 2001 From: "W.C.A. Wijngaards" Date: Tue, 18 Feb 2020 17:04:08 +0100 Subject: [PATCH] dnstap io, move control frame ready, accept and log to dnstap_fstrm code. --- dnstap/dnstap_fstrm.c | 112 +++++++++++++++++++++++++++++++++ dnstap/dnstap_fstrm.h | 37 +++++++++++ dnstap/unbound-dnstap-socket.c | 95 ++++++---------------------- 3 files changed, 168 insertions(+), 76 deletions(-) diff --git a/dnstap/dnstap_fstrm.c b/dnstap/dnstap_fstrm.c index be4acace8..aac98e567 100644 --- a/dnstap/dnstap_fstrm.c +++ b/dnstap/dnstap_fstrm.c @@ -43,6 +43,7 @@ #include "config.h" #include "dnstap/dnstap_fstrm.h" +#include "sldns/sbuffer.h" void* fstrm_create_control_frame_start(char* contenttype, size_t* len) { @@ -89,3 +90,114 @@ void* fstrm_create_control_frame_stop(size_t* len) *len = n; return control; } + +void* fstrm_create_control_frame_accept(char* contenttype, size_t* len) +{ + uint32_t* control; + size_t n; + /* control frame on reply: + * 4 bytes 0 escape + * 4 bytes bigendian length of frame + * 4 bytes bigendian type ACCEPT + * 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_ACCEPT); + 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_finish(size_t* len) +{ + uint32_t* control; + size_t n; + /* control frame on reply: + * 4 bytes 0 escape + * 4 bytes bigendian length of frame + * 4 bytes bigendian type FINISH + */ + /* len includes the escape and framelength */ + n = 4+4+4; + control = malloc(n); + if(!control) { + return NULL; + } + control[0] = 0; + control[1] = htonl(4); + control[2] = htonl(FSTRM_CONTROL_FRAME_FINISH); + *len = n; + return control; +} + +char* fstrm_describe_control(void* pkt, size_t len) +{ + uint32_t frametype = 0; + char buf[512]; + size_t at = 0, remain; + uint8_t* pos; + + buf[0]=0; + if(len < 4) { + snprintf(buf, sizeof(buf), "malformed control frame, " + "too short, len=%u", (unsigned int)len); + return strdup(buf); + } + frametype = sldns_read_uint32(pkt); + if(frametype == FSTRM_CONTROL_FRAME_ACCEPT) { + at+=snprintf(buf+at, sizeof(buf)-at, "accept"); + } else if(frametype == FSTRM_CONTROL_FRAME_START) { + at+=snprintf(buf+at, sizeof(buf)-at, "start"); + } else if(frametype == FSTRM_CONTROL_FRAME_STOP) { + at+=snprintf(buf+at, sizeof(buf)-at, "stop"); + } else if(frametype == FSTRM_CONTROL_FRAME_READY) { + at+=snprintf(buf+at, sizeof(buf)-at, "ready"); + } else if(frametype == FSTRM_CONTROL_FRAME_FINISH) { + at+=snprintf(buf+at, sizeof(buf)-at, "finish"); + } else { + at+=snprintf(buf+at, sizeof(buf)-at, "type%d", + (int)frametype); + } + + /* show the content type options */ + pos = pkt + 4; + remain = len - 4; + while(remain >= 8) { + uint32_t field_type = sldns_read_uint32(pos); + uint32_t field_len = sldns_read_uint32(pos+4); + if(remain < field_len) { + at+=snprintf(buf+at, sizeof(buf)-at, "malformed_field"); + break; + } + if(field_type == FSTRM_CONTROL_FIELD_TYPE_CONTENT_TYPE) { + at+=snprintf(buf+at, sizeof(buf)-at, " content-type("); + if(at+field_len < sizeof(buf)) { + memmove(buf+at, pos+8, field_len); + at += field_len; + } + at+=snprintf(buf+at, sizeof(buf)-at, ")"); + } else { + at+=snprintf(buf+at, sizeof(buf)-at, + " field(type %u, length %u)", + (unsigned int)field_type, + (unsigned int)field_len); + } + pos += 8 + field_len; + remain -= (8 + field_len); + } + if(remain > 0) + at+=snprintf(buf+at, sizeof(buf)-at, " trailing-bytes" + "(length %u)", (unsigned int)remain); + return strdup(buf); +} diff --git a/dnstap/dnstap_fstrm.h b/dnstap/dnstap_fstrm.h index 3b70547f1..f0cf93628 100644 --- a/dnstap/dnstap_fstrm.h +++ b/dnstap/dnstap_fstrm.h @@ -139,4 +139,41 @@ void* fstrm_create_control_frame_start(char* contenttype, size_t* len); */ void* fstrm_create_control_frame_stop(size_t* len); +/** + * This creates an FSTRM control frame of type ACCEPT. + * @param contenttype: a zero delimited string with the content type. + * for dnstap streams use DNSTAP_CONTENT_TYPE. + * @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_accept(char* contenttype, size_t* len); + +/** + * This creates an FSTRM control frame of type FINISH. + * @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_finish(size_t* len); + +/** + * Return string that describes a control packet. For debug, logs. + * Like 'start content-type(protobuf:dnstap.Dnstap)' or 'stop'. + * @param pkt: the packet data, that is the data after the 4 zero start + * bytes and 4 length bytes. + * @param len: the length of the control packet data, in pkt. This is the + * ntohl of the 4 bytes length preceding the data. + * @return zero delimited string, malloced. Or NULL on malloc failure. + */ +char* fstrm_describe_control(void* pkt, size_t len); + #endif /* DNSTAP_FSTRM_H */ diff --git a/dnstap/unbound-dnstap-socket.c b/dnstap/unbound-dnstap-socket.c index e26e12ede..0605d4d7c 100644 --- a/dnstap/unbound-dnstap-socket.c +++ b/dnstap/unbound-dnstap-socket.c @@ -409,54 +409,15 @@ static int tap_socket_list_addevs(struct tap_socket_list* list, /** log control frame contents */ static void log_control_frame(uint8_t* pkt, size_t len) { - uint32_t frametype = 0; - char buf[256]; - size_t at = 0, remain; - uint8_t* pos; + char* desc; if(verbosity == 0) return; - if(len < 4) { - log_err("malformed control frame, too short, len=%d", (int)len); + desc = fstrm_describe_control(pkt, len); + if(!desc) { + log_err("out of memory"); return; } - buf[0]=0; - frametype = sldns_read_uint32(pkt); - if(frametype == FSTRM_CONTROL_FRAME_ACCEPT) { - at+=snprintf(buf+at, sizeof(buf)-at, "accept"); - } else if(frametype == FSTRM_CONTROL_FRAME_START) { - at+=snprintf(buf+at, sizeof(buf)-at, "start"); - } else if(frametype == FSTRM_CONTROL_FRAME_STOP) { - at+=snprintf(buf+at, sizeof(buf)-at, "stop"); - } else if(frametype == FSTRM_CONTROL_FRAME_READY) { - at+=snprintf(buf+at, sizeof(buf)-at, "ready"); - } else if(frametype == FSTRM_CONTROL_FRAME_FINISH) { - at+=snprintf(buf+at, sizeof(buf)-at, "finish"); - } else { - at+=snprintf(buf+at, sizeof(buf)-at, "type%d", - (int)frametype); - } - - /* show the content type options */ - pos = pkt + 4; - remain = len - 4; - while(remain >= 8) { - uint32_t field_type = sldns_read_uint32(pos); - uint32_t field_len = sldns_read_uint32(pos+4); - if(remain < field_len) { - at+=snprintf(buf+at, sizeof(buf)-at, "malformed_field"); - break; - } - if(field_type == FSTRM_CONTROL_FIELD_TYPE_CONTENT_TYPE) { - at+=snprintf(buf+at, sizeof(buf)-at, " content-type("); - if(at+field_len < sizeof(buf)) { - memmove(buf+at, pos+8, field_len); - at += field_len; - } - at+=snprintf(buf+at, sizeof(buf)-at, ")"); - } - pos += 8 + field_len; - remain -= (8 + field_len); - } - log_info("control frame %s", buf); + log_info("control frame %s", desc); + free(desc); } /** convert mtype to string */ @@ -804,32 +765,17 @@ void tap_data_free(struct tap_data* data) * returns 0 on error */ static int reply_with_accept(int fd) { - /* control frame on reply: - * 4 bytes 0 escape - * 4 bytes bigendian length of frame - * 4 bytes bigendian type ACCEPT - * 4 bytes bigendian frame option content type - * 4 bytes bigendian length of string - * string of content type. - */ - uint32_t* acceptframe; /* len includes the escape and framelength */ - size_t len = 4+4+4+4+4+strlen(DNSTAP_CONTENT_TYPE); - acceptframe = calloc(1, len); + size_t len = 0; + void* acceptframe = fstrm_create_control_frame_accept( + DNSTAP_CONTENT_TYPE, &len); if(!acceptframe) { log_err("out of memory"); return 0; } - acceptframe[0] = 0; - acceptframe[1] = htonl(4+4+4+strlen(DNSTAP_CONTENT_TYPE)); - acceptframe[2] = htonl(FSTRM_CONTROL_FRAME_ACCEPT); - acceptframe[3] = htonl(FSTRM_CONTROL_FIELD_TYPE_CONTENT_TYPE); - acceptframe[4] = htonl(strlen(DNSTAP_CONTENT_TYPE)); - memmove(&acceptframe[5], DNSTAP_CONTENT_TYPE, - strlen(DNSTAP_CONTENT_TYPE)); fd_set_block(fd); - if(send(fd, (void*)acceptframe, len, 0) == -1) { + if(send(fd, acceptframe, len, 0) == -1) { #ifndef USE_WINSOCK log_err("send failed: %s", strerror(errno)); #else @@ -851,31 +797,28 @@ static int reply_with_accept(int fd) * returns 0 on error */ static int reply_with_finish(int fd) { - /* control frame on reply: - * 4 bytes 0 escape - * 4 bytes bigendian length of frame - * 4 bytes bigendian type FINISH - */ - uint32_t finishframe[3]; - /* len includes the escape and framelength */ - size_t len = 4+4+4; - finishframe[0] = 0; - finishframe[1] = htonl(4); - finishframe[2] = htonl(FSTRM_CONTROL_FRAME_FINISH); + size_t len = 0; + void* finishframe = fstrm_create_control_frame_finish(&len); + if(!finishframe) { + log_err("out of memory"); + return 0; + } fd_set_block(fd); - if(send(fd, (void*)finishframe, len, 0) == -1) { + if(send(fd, finishframe, len, 0) == -1) { #ifndef USE_WINSOCK log_err("send failed: %s", strerror(errno)); #else log_err("send failed: %s", wsa_strerror(WSAGetLastError())); #endif fd_set_nonblock(fd); + free(finishframe); return 0; } if(verbosity) log_info("sent control frame(finish)"); fd_set_nonblock(fd); + free(finishframe); return 1; } -- 2.47.3