#include "config.h"
#include "dnstap/dnstap_fstrm.h"
+#include "sldns/sbuffer.h"
void* fstrm_create_control_frame_start(char* contenttype, 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);
+}
*/
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 */
/** 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 */
* 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
* 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;
}