1*25039b37SCy Schubert /*
2*25039b37SCy Schubert * dnstap/dnstap_fstrm.c - Frame Streams protocol for dnstap
3*25039b37SCy Schubert *
4*25039b37SCy Schubert * Copyright (c) 2020, NLnet Labs. All rights reserved.
5*25039b37SCy Schubert *
6*25039b37SCy Schubert * This software is open source.
7*25039b37SCy Schubert *
8*25039b37SCy Schubert * Redistribution and use in source and binary forms, with or without
9*25039b37SCy Schubert * modification, are permitted provided that the following conditions
10*25039b37SCy Schubert * are met:
11*25039b37SCy Schubert *
12*25039b37SCy Schubert * Redistributions of source code must retain the above copyright notice,
13*25039b37SCy Schubert * this list of conditions and the following disclaimer.
14*25039b37SCy Schubert *
15*25039b37SCy Schubert * Redistributions in binary form must reproduce the above copyright notice,
16*25039b37SCy Schubert * this list of conditions and the following disclaimer in the documentation
17*25039b37SCy Schubert * and/or other materials provided with the distribution.
18*25039b37SCy Schubert *
19*25039b37SCy Schubert * Neither the name of the NLNET LABS nor the names of its contributors may
20*25039b37SCy Schubert * be used to endorse or promote products derived from this software without
21*25039b37SCy Schubert * specific prior written permission.
22*25039b37SCy Schubert *
23*25039b37SCy Schubert * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24*25039b37SCy Schubert * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25*25039b37SCy Schubert * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
26*25039b37SCy Schubert * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
27*25039b37SCy Schubert * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
28*25039b37SCy Schubert * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
29*25039b37SCy Schubert * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
30*25039b37SCy Schubert * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
31*25039b37SCy Schubert * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
32*25039b37SCy Schubert * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
33*25039b37SCy Schubert * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34*25039b37SCy Schubert *
35*25039b37SCy Schubert */
36*25039b37SCy Schubert
37*25039b37SCy Schubert /**
38*25039b37SCy Schubert * \file
39*25039b37SCy Schubert *
40*25039b37SCy Schubert * Definitions for the Frame Streams data transport protocol for
41*25039b37SCy Schubert * dnstap message logs.
42*25039b37SCy Schubert */
43*25039b37SCy Schubert
44*25039b37SCy Schubert #include "config.h"
45*25039b37SCy Schubert #include "dnstap/dnstap_fstrm.h"
46*25039b37SCy Schubert #include "sldns/sbuffer.h"
47*25039b37SCy Schubert #include "sldns/wire2str.h"
48*25039b37SCy Schubert
fstrm_create_control_frame_start(char * contenttype,size_t * len)49*25039b37SCy Schubert void* fstrm_create_control_frame_start(char* contenttype, size_t* len)
50*25039b37SCy Schubert {
51*25039b37SCy Schubert uint32_t* control;
52*25039b37SCy Schubert size_t n;
53*25039b37SCy Schubert /* start framestream message:
54*25039b37SCy Schubert * 4byte 0: control indicator.
55*25039b37SCy Schubert * 4byte bigendian: length of control frame
56*25039b37SCy Schubert * 4byte bigendian: type START
57*25039b37SCy Schubert * 4byte bigendian: option: content-type
58*25039b37SCy Schubert * 4byte bigendian: length of string
59*25039b37SCy Schubert * string of content type (dnstap)
60*25039b37SCy Schubert */
61*25039b37SCy Schubert n = 4+4+4+4+4+strlen(contenttype);
62*25039b37SCy Schubert control = malloc(n);
63*25039b37SCy Schubert if(!control)
64*25039b37SCy Schubert return NULL;
65*25039b37SCy Schubert control[0] = 0;
66*25039b37SCy Schubert control[1] = htonl(4+4+4+strlen(contenttype));
67*25039b37SCy Schubert control[2] = htonl(FSTRM_CONTROL_FRAME_START);
68*25039b37SCy Schubert control[3] = htonl(FSTRM_CONTROL_FIELD_TYPE_CONTENT_TYPE);
69*25039b37SCy Schubert control[4] = htonl(strlen(contenttype));
70*25039b37SCy Schubert memmove(&control[5], contenttype, strlen(contenttype));
71*25039b37SCy Schubert *len = n;
72*25039b37SCy Schubert return control;
73*25039b37SCy Schubert }
74*25039b37SCy Schubert
fstrm_create_control_frame_stop(size_t * len)75*25039b37SCy Schubert void* fstrm_create_control_frame_stop(size_t* len)
76*25039b37SCy Schubert {
77*25039b37SCy Schubert uint32_t* control;
78*25039b37SCy Schubert size_t n;
79*25039b37SCy Schubert /* stop framestream message:
80*25039b37SCy Schubert * 4byte 0: control indicator.
81*25039b37SCy Schubert * 4byte bigendian: length of control frame
82*25039b37SCy Schubert * 4byte bigendian: type STOP
83*25039b37SCy Schubert */
84*25039b37SCy Schubert n = 4+4+4;
85*25039b37SCy Schubert control = malloc(n);
86*25039b37SCy Schubert if(!control)
87*25039b37SCy Schubert return NULL;
88*25039b37SCy Schubert control[0] = 0;
89*25039b37SCy Schubert control[1] = htonl(4);
90*25039b37SCy Schubert control[2] = htonl(FSTRM_CONTROL_FRAME_STOP);
91*25039b37SCy Schubert *len = n;
92*25039b37SCy Schubert return control;
93*25039b37SCy Schubert }
94*25039b37SCy Schubert
fstrm_create_control_frame_ready(char * contenttype,size_t * len)95*25039b37SCy Schubert void* fstrm_create_control_frame_ready(char* contenttype, size_t* len)
96*25039b37SCy Schubert {
97*25039b37SCy Schubert uint32_t* control;
98*25039b37SCy Schubert size_t n;
99*25039b37SCy Schubert /* start bidirectional stream:
100*25039b37SCy Schubert * 4 bytes 0 escape
101*25039b37SCy Schubert * 4 bytes bigendian length of frame
102*25039b37SCy Schubert * 4 bytes bigendian type READY
103*25039b37SCy Schubert * 4 bytes bigendian frame option content type
104*25039b37SCy Schubert * 4 bytes bigendian length of string
105*25039b37SCy Schubert * string of content type.
106*25039b37SCy Schubert */
107*25039b37SCy Schubert /* len includes the escape and framelength */
108*25039b37SCy Schubert n = 4+4+4+4+4+strlen(contenttype);
109*25039b37SCy Schubert control = malloc(n);
110*25039b37SCy Schubert if(!control) {
111*25039b37SCy Schubert return NULL;
112*25039b37SCy Schubert }
113*25039b37SCy Schubert control[0] = 0;
114*25039b37SCy Schubert control[1] = htonl(4+4+4+strlen(contenttype));
115*25039b37SCy Schubert control[2] = htonl(FSTRM_CONTROL_FRAME_READY);
116*25039b37SCy Schubert control[3] = htonl(FSTRM_CONTROL_FIELD_TYPE_CONTENT_TYPE);
117*25039b37SCy Schubert control[4] = htonl(strlen(contenttype));
118*25039b37SCy Schubert memmove(&control[5], contenttype, strlen(contenttype));
119*25039b37SCy Schubert *len = n;
120*25039b37SCy Schubert return control;
121*25039b37SCy Schubert }
122*25039b37SCy Schubert
fstrm_create_control_frame_accept(char * contenttype,size_t * len)123*25039b37SCy Schubert void* fstrm_create_control_frame_accept(char* contenttype, size_t* len)
124*25039b37SCy Schubert {
125*25039b37SCy Schubert uint32_t* control;
126*25039b37SCy Schubert size_t n;
127*25039b37SCy Schubert /* control frame on reply:
128*25039b37SCy Schubert * 4 bytes 0 escape
129*25039b37SCy Schubert * 4 bytes bigendian length of frame
130*25039b37SCy Schubert * 4 bytes bigendian type ACCEPT
131*25039b37SCy Schubert * 4 bytes bigendian frame option content type
132*25039b37SCy Schubert * 4 bytes bigendian length of string
133*25039b37SCy Schubert * string of content type.
134*25039b37SCy Schubert */
135*25039b37SCy Schubert /* len includes the escape and framelength */
136*25039b37SCy Schubert n = 4+4+4+4+4+strlen(contenttype);
137*25039b37SCy Schubert control = malloc(n);
138*25039b37SCy Schubert if(!control) {
139*25039b37SCy Schubert return NULL;
140*25039b37SCy Schubert }
141*25039b37SCy Schubert control[0] = 0;
142*25039b37SCy Schubert control[1] = htonl(4+4+4+strlen(contenttype));
143*25039b37SCy Schubert control[2] = htonl(FSTRM_CONTROL_FRAME_ACCEPT);
144*25039b37SCy Schubert control[3] = htonl(FSTRM_CONTROL_FIELD_TYPE_CONTENT_TYPE);
145*25039b37SCy Schubert control[4] = htonl(strlen(contenttype));
146*25039b37SCy Schubert memmove(&control[5], contenttype, strlen(contenttype));
147*25039b37SCy Schubert *len = n;
148*25039b37SCy Schubert return control;
149*25039b37SCy Schubert }
150*25039b37SCy Schubert
fstrm_create_control_frame_finish(size_t * len)151*25039b37SCy Schubert void* fstrm_create_control_frame_finish(size_t* len)
152*25039b37SCy Schubert {
153*25039b37SCy Schubert uint32_t* control;
154*25039b37SCy Schubert size_t n;
155*25039b37SCy Schubert /* control frame on reply:
156*25039b37SCy Schubert * 4 bytes 0 escape
157*25039b37SCy Schubert * 4 bytes bigendian length of frame
158*25039b37SCy Schubert * 4 bytes bigendian type FINISH
159*25039b37SCy Schubert */
160*25039b37SCy Schubert /* len includes the escape and framelength */
161*25039b37SCy Schubert n = 4+4+4;
162*25039b37SCy Schubert control = malloc(n);
163*25039b37SCy Schubert if(!control) {
164*25039b37SCy Schubert return NULL;
165*25039b37SCy Schubert }
166*25039b37SCy Schubert control[0] = 0;
167*25039b37SCy Schubert control[1] = htonl(4);
168*25039b37SCy Schubert control[2] = htonl(FSTRM_CONTROL_FRAME_FINISH);
169*25039b37SCy Schubert *len = n;
170*25039b37SCy Schubert return control;
171*25039b37SCy Schubert }
172*25039b37SCy Schubert
fstrm_describe_control(void * pkt,size_t len)173*25039b37SCy Schubert char* fstrm_describe_control(void* pkt, size_t len)
174*25039b37SCy Schubert {
175*25039b37SCy Schubert uint32_t frametype = 0;
176*25039b37SCy Schubert char buf[512];
177*25039b37SCy Schubert char* str = buf;
178*25039b37SCy Schubert size_t remain, slen = sizeof(buf);
179*25039b37SCy Schubert uint8_t* pos;
180*25039b37SCy Schubert
181*25039b37SCy Schubert buf[0]=0;
182*25039b37SCy Schubert if(len < 4) {
183*25039b37SCy Schubert snprintf(buf, sizeof(buf), "malformed control frame, "
184*25039b37SCy Schubert "too short, len=%u", (unsigned int)len);
185*25039b37SCy Schubert return strdup(buf);
186*25039b37SCy Schubert }
187*25039b37SCy Schubert frametype = sldns_read_uint32(pkt);
188*25039b37SCy Schubert if(frametype == FSTRM_CONTROL_FRAME_ACCEPT) {
189*25039b37SCy Schubert (void)sldns_str_print(&str, &slen, "accept");
190*25039b37SCy Schubert } else if(frametype == FSTRM_CONTROL_FRAME_START) {
191*25039b37SCy Schubert (void)sldns_str_print(&str, &slen, "start");
192*25039b37SCy Schubert } else if(frametype == FSTRM_CONTROL_FRAME_STOP) {
193*25039b37SCy Schubert (void)sldns_str_print(&str, &slen, "stop");
194*25039b37SCy Schubert } else if(frametype == FSTRM_CONTROL_FRAME_READY) {
195*25039b37SCy Schubert (void)sldns_str_print(&str, &slen, "ready");
196*25039b37SCy Schubert } else if(frametype == FSTRM_CONTROL_FRAME_FINISH) {
197*25039b37SCy Schubert (void)sldns_str_print(&str, &slen, "finish");
198*25039b37SCy Schubert } else {
199*25039b37SCy Schubert (void)sldns_str_print(&str, &slen, "type%d", (int)frametype);
200*25039b37SCy Schubert }
201*25039b37SCy Schubert
202*25039b37SCy Schubert /* show the content type options */
203*25039b37SCy Schubert pos = pkt + 4;
204*25039b37SCy Schubert remain = len - 4;
205*25039b37SCy Schubert while(remain >= 8) {
206*25039b37SCy Schubert uint32_t field_type = sldns_read_uint32(pos);
207*25039b37SCy Schubert uint32_t field_len = sldns_read_uint32(pos+4);
208*25039b37SCy Schubert if(remain < field_len) {
209*25039b37SCy Schubert (void)sldns_str_print(&str, &slen, "malformed_field");
210*25039b37SCy Schubert break;
211*25039b37SCy Schubert }
212*25039b37SCy Schubert if(field_type == FSTRM_CONTROL_FIELD_TYPE_CONTENT_TYPE) {
213*25039b37SCy Schubert char tempf[512];
214*25039b37SCy Schubert (void)sldns_str_print(&str, &slen, " content-type(");
215*25039b37SCy Schubert if(field_len < sizeof(tempf)-1) {
216*25039b37SCy Schubert memmove(tempf, pos+8, field_len);
217*25039b37SCy Schubert tempf[field_len] = 0;
218*25039b37SCy Schubert (void)sldns_str_print(&str, &slen, "%s", tempf);
219*25039b37SCy Schubert } else {
220*25039b37SCy Schubert (void)sldns_str_print(&str, &slen, "<error-too-long>");
221*25039b37SCy Schubert }
222*25039b37SCy Schubert (void)sldns_str_print(&str, &slen, ")");
223*25039b37SCy Schubert } else {
224*25039b37SCy Schubert (void)sldns_str_print(&str, &slen,
225*25039b37SCy Schubert " field(type %u, length %u)",
226*25039b37SCy Schubert (unsigned int)field_type,
227*25039b37SCy Schubert (unsigned int)field_len);
228*25039b37SCy Schubert }
229*25039b37SCy Schubert pos += 8 + field_len;
230*25039b37SCy Schubert remain -= (8 + field_len);
231*25039b37SCy Schubert }
232*25039b37SCy Schubert if(remain > 0)
233*25039b37SCy Schubert (void)sldns_str_print(&str, &slen, " trailing-bytes"
234*25039b37SCy Schubert "(length %u)", (unsigned int)remain);
235*25039b37SCy Schubert return strdup(buf);
236*25039b37SCy Schubert }
237