Line data Source code
1 : #pragma GCC diagnostic ignored "-Wtype-limits"
2 :
3 : #include "templ/fd_quic_pretty_print.h"
4 : #include "templ/fd_quic_templ.h"
5 : #include "templ/fd_quic_frames_templ.h"
6 : #include "templ/fd_quic_undefs.h"
7 : #include "fd_quic_private.h"
8 : #include "fd_quic_pretty_print.h"
9 :
10 : /* Generate frame pretty-print */
11 :
12 : #define FD_TEMPL_DEF_STRUCT_BEGIN(NAME) \
13 : static ulong fd_quic_pretty_print_frame_##NAME( \
14 : fd_quic_##NAME##_t * frame, \
15 : char ** out_buf, \
16 : ulong * out_buf_sz, \
17 : uchar const * const buf, \
18 : ulong const buf_sz \
19 0 : ) { \
20 0 : uchar const * p0 = buf; \
21 0 : uchar const * const p1 = buf+buf_sz; \
22 0 : ulong rc; \
23 0 : \
24 0 : rc = fd_quic_decode_##NAME( frame, p0, (ulong)(p1-p0) ); \
25 0 : if( FD_UNLIKELY( rc==FD_QUIC_PARSE_FAIL ) ) return FD_QUIC_PARSE_FAIL; \
26 0 : p0 += rc; \
27 0 : \
28 0 : fd_quic_pretty_print_struct_##NAME( out_buf, out_buf_sz, frame ); \
29 0 : \
30 0 : return (ulong)(p0-buf); \
31 0 : }
32 : #include "templ/fd_quic_dft.h"
33 : #include "templ/fd_quic_frames_templ.h"
34 : #include "templ/fd_quic_undefs.h"
35 :
36 : #include "templ/fd_quic_frame.h"
37 :
38 :
39 : #define safe_snprintf( out, sz, ... ) \
40 0 : (__extension__({ \
41 0 : int rtn = snprintf( (out), (sz), __VA_ARGS__ ); \
42 0 : if( rtn < 0 ) rtn = 0; \
43 0 : if( rtn > (int)(sz) ) rtn = (int)(sz); \
44 0 : (ulong)rtn; }))
45 :
46 : ulong
47 : fd_quic_pretty_print_frame( char ** out_buf,
48 : ulong * out_buf_sz,
49 : uchar const * buf,
50 0 : ulong buf_sz ) {
51 0 : if( FD_UNLIKELY( buf_sz<1UL ) ) return FD_QUIC_PARSE_FAIL;
52 :
53 0 : uchar const * cur_buf = buf;
54 0 : uchar const * buf_end = buf + buf_sz;
55 :
56 0 : if( ( cur_buf[0] & 0xfe ) == 0x00 ) { /* handle padding and pings separately */
57 0 : ulong padding_cnt = 0;
58 0 : ulong ping_cnt = 0;
59 0 : while( cur_buf < buf_end && ( *cur_buf & 0xfe ) == 0x00 ) {
60 0 : uint pad = (uint)( *cur_buf == 0 );
61 0 : padding_cnt += pad;
62 0 : ping_cnt += 1u - pad;
63 0 : cur_buf++;
64 0 : }
65 :
66 0 : ulong sz = safe_snprintf( *out_buf, *out_buf_sz,
67 0 : "\"frame_type\": \"pad-ping\", \"pad-count\": %lu, "
68 0 : "\"ping-count\": %lu, ",
69 0 : padding_cnt, ping_cnt );
70 0 : *out_buf += sz;
71 0 : *out_buf_sz -= sz;
72 :
73 0 : return (ulong)( cur_buf - buf );
74 0 : }
75 :
76 : /* Frame ID is technically a varint but it's sufficient to look at the
77 : first byte. */
78 0 : uint id = cur_buf[0];
79 0 : if( FD_UNLIKELY( id >= FD_QUIC_FRAME_TYPE_CNT ) ) {
80 0 : ulong sz = safe_snprintf( *out_buf, *out_buf_sz, "\"frame_type\": \"%x-unknown\", ", (uint)id );
81 0 : *out_buf += sz;
82 0 : *out_buf_sz -= sz;
83 :
84 0 : return FD_QUIC_PARSE_FAIL;
85 0 : }
86 :
87 0 : ulong consumed = 0UL;
88 :
89 0 : union {
90 0 : #define FD_TEMPL_DEF_STRUCT_BEGIN(NAME) fd_quic_##NAME##_t NAME;
91 0 : #include "templ/fd_quic_dft.h"
92 0 : #include "templ/fd_quic_frames_templ.h"
93 0 : #include "templ/fd_quic_undefs.h"
94 0 : } data;
95 :
96 0 : memset( &data, 0, sizeof( data ) );
97 :
98 : /* tail call to frame handler */
99 0 : switch( id ) {
100 :
101 0 : # define F(T,MID,NAME,...) \
102 0 : case T: { \
103 0 : ulong sz = safe_snprintf( *out_buf, *out_buf_sz, "\"frame_type\": \"%u\", ", (uint)id ); \
104 0 : *out_buf += sz; \
105 0 : *out_buf_sz -= sz; \
106 0 : consumed = fd_quic_pretty_print_frame_##NAME##_frame( &data.NAME##_frame, out_buf, out_buf_sz, cur_buf, (ulong)( buf_end - cur_buf ) ); \
107 0 : break; \
108 0 : }
109 0 : FD_QUIC_FRAME_TYPES(F)
110 0 : # undef F
111 :
112 0 : default:
113 : /* we're unable to consume more bytes, since this is invalid */
114 : /* TODO put error key in json */
115 0 : return FD_QUIC_PARSE_FAIL;
116 0 : }
117 :
118 0 : if( consumed == FD_QUIC_PARSE_FAIL ) return FD_QUIC_PARSE_FAIL;
119 :
120 : /* handle repeating blocks, etc. */
121 0 : cur_buf += consumed;
122 :
123 0 : switch( id ) {
124 0 : case 0x02:
125 0 : case 0x03:
126 0 : {
127 0 : ulong ack_range_count = data.ack_frame.ack_range_count;
128 :
129 0 : if( ack_range_count ) {
130 0 : ulong out_sz = safe_snprintf( *out_buf, *out_buf_sz, "\"ack_ranges\": [ " );
131 0 : *out_buf += out_sz;
132 0 : *out_buf_sz -= out_sz;
133 :
134 : /* skip ack ranges */
135 0 : for( ulong j = 0UL; j < ack_range_count; ++j ) {
136 0 : fd_quic_ack_range_frag_t ack_range[1];
137 0 : ulong rc = fd_quic_decode_ack_range_frag( ack_range, cur_buf, (ulong)( buf_end - cur_buf ) );
138 0 : if( FD_UNLIKELY( rc == FD_QUIC_PARSE_FAIL ) ) {
139 0 : ulong out_sz = safe_snprintf( *out_buf, *out_buf_sz, "\"err\": \"parse-ack-ranges\", " );
140 0 : *out_buf += out_sz;
141 0 : *out_buf_sz -= out_sz;
142 0 : return FD_QUIC_PARSE_FAIL;
143 0 : }
144 :
145 0 : cur_buf += rc;
146 :
147 0 : ulong out_sz = safe_snprintf( *out_buf, *out_buf_sz, "{ " );
148 0 : *out_buf += out_sz;
149 0 : *out_buf_sz -= out_sz;
150 :
151 0 : fd_quic_pretty_print_struct_ack_range_frag( out_buf, out_buf_sz, ack_range );
152 :
153 0 : out_sz = safe_snprintf( *out_buf, *out_buf_sz, "}, " );
154 0 : *out_buf += out_sz;
155 0 : *out_buf_sz -= out_sz;
156 0 : }
157 :
158 0 : out_sz = safe_snprintf( *out_buf, *out_buf_sz, "], " );
159 0 : *out_buf += out_sz;
160 0 : *out_buf_sz -= out_sz;
161 0 : }
162 :
163 0 : if( data.ack_frame.type & 1U ) {
164 0 : fd_quic_ecn_counts_frag_t ecn_counts[1] = {0};
165 0 : ulong rc = fd_quic_decode_ecn_counts_frag( ecn_counts, cur_buf, (ulong)( buf_end - cur_buf ) );
166 0 : if( rc == FD_QUIC_PARSE_FAIL ) {
167 0 : ulong out_sz = safe_snprintf( *out_buf, *out_buf_sz, "\"err\": \"parse-ecn-counts\", " );
168 0 : *out_buf += out_sz;
169 0 : *out_buf_sz -= out_sz;
170 0 : return FD_QUIC_PARSE_FAIL;
171 0 : }
172 :
173 0 : fd_quic_pretty_print_struct_ecn_counts_frag( out_buf, out_buf_sz, ecn_counts );
174 :
175 0 : cur_buf += rc;
176 0 : }
177 :
178 0 : break;
179 0 : }
180 :
181 0 : case 0x06:
182 0 : {
183 0 : ulong out_sz = 0;
184 0 : ulong remain = (ulong)( buf_end - cur_buf );
185 0 : ulong data_sz = data.crypto_frame.length;
186 0 : if( data_sz > remain ) {
187 0 : out_sz = safe_snprintf( *out_buf, *out_buf_sz, "\"err\": \"overflow\", " );
188 0 : *out_buf += out_sz;
189 0 : *out_buf_sz -= out_sz;
190 :
191 0 : return FD_QUIC_PARSE_FAIL;
192 0 : }
193 :
194 0 : out_sz = safe_snprintf( *out_buf, *out_buf_sz, "\"data\": [ " );
195 0 : *out_buf += out_sz;
196 0 : *out_buf_sz -= out_sz;
197 :
198 0 : for( ulong j = 0; j < data_sz; ++j ) {
199 0 : out_sz = safe_snprintf( *out_buf, *out_buf_sz, "0x%02x, ", cur_buf[j] );
200 0 : *out_buf += out_sz;
201 0 : *out_buf_sz -= out_sz;
202 0 : }
203 :
204 0 : out_sz = safe_snprintf( *out_buf, *out_buf_sz, "], " );
205 0 : *out_buf += out_sz;
206 0 : *out_buf_sz -= out_sz;
207 :
208 0 : cur_buf += data_sz;
209 :
210 0 : break;
211 0 : }
212 :
213 0 : case 0x08:
214 0 : case 0x09:
215 0 : case 0x0a:
216 0 : case 0x0b:
217 0 : case 0x0c:
218 0 : case 0x0d:
219 0 : case 0x0e:
220 0 : case 0x0f:
221 0 : {
222 0 : ulong remain = (ulong)( buf_end - cur_buf );
223 :
224 : /* stream */
225 : /* optional fields decoding */
226 0 : ulong offset = 0;
227 0 : ulong stream_id = 0;
228 0 : ulong data_sz = remain;
229 0 : ulong fin = 0;
230 :
231 0 : switch( id ) {
232 0 : # define _0(ELSE,...) ELSE
233 0 : # define _1(ELSE,...) __VA_ARGS__
234 0 : # define _CASE(OFF,LEN,FIN,NAME) \
235 0 : case 8 + OFF(0,4) + LEN(0,2) + FIN(0,1): \
236 0 : OFF(,offset = data.NAME.offset;) \
237 0 : LEN(,data_sz = data.NAME.length;) \
238 0 : FIN(,fin = 1;) \
239 0 : stream_id = data.NAME.stream_id; \
240 0 : break;
241 0 : _CASE(_0,_0,_0,stream_8_frame)
242 0 : _CASE(_0,_0,_1,stream_8_frame)
243 0 : _CASE(_0,_1,_0,stream_a_frame)
244 0 : _CASE(_0,_1,_1,stream_a_frame)
245 0 : _CASE(_1,_0,_0,stream_c_frame)
246 0 : _CASE(_1,_0,_1,stream_c_frame)
247 0 : _CASE(_1,_1,_0,stream_e_frame)
248 0 : _CASE(_1,_1,_1,stream_e_frame)
249 0 : # undef _CASE
250 0 : # undef _1
251 0 : # undef _0
252 0 : }
253 :
254 0 : ulong stream_type = stream_id & 3UL;
255 :
256 0 : ulong out_sz = safe_snprintf(
257 0 : *out_buf,
258 0 : *out_buf_sz,
259 0 : "\"stream_type\": %u, \"offset\": %lu, \"length\": %lu, \"fin\": %lu, ",
260 0 : (uint)stream_type, offset, data_sz, fin );
261 0 : *out_buf += out_sz;
262 0 : *out_buf_sz -= out_sz;
263 :
264 0 : if( data_sz > remain ) {
265 0 : out_sz = safe_snprintf( *out_buf, *out_buf_sz, "\"err\": \"overflow\", " );
266 0 : *out_buf += out_sz;
267 0 : *out_buf_sz -= out_sz;
268 :
269 0 : return FD_QUIC_PARSE_FAIL;
270 0 : }
271 :
272 0 : out_sz = safe_snprintf( *out_buf, *out_buf_sz, "\"data\": [ " );
273 0 : *out_buf += out_sz;
274 0 : *out_buf_sz -= out_sz;
275 :
276 0 : for( ulong j = 0; j < data_sz; ++j ) {
277 0 : out_sz = safe_snprintf( *out_buf, *out_buf_sz, "0x%02x, ", cur_buf[j] );
278 0 : *out_buf += out_sz;
279 0 : *out_buf_sz -= out_sz;
280 0 : }
281 :
282 0 : out_sz = safe_snprintf( *out_buf, *out_buf_sz, "], " );
283 0 : *out_buf += out_sz;
284 0 : *out_buf_sz -= out_sz;
285 :
286 0 : cur_buf += data_sz;
287 :
288 0 : break;
289 0 : }
290 :
291 0 : case 0x1c: /* connection close */
292 0 : {
293 : /* the conn_close_1_frame structure is different to conn_close_0_frame */
294 0 : ulong reason_phrase_length = data.conn_close_0_frame.reason_phrase_length;
295 0 : ulong remain = (ulong)( buf_end - cur_buf );
296 0 : if( FD_UNLIKELY( reason_phrase_length > remain ) ) {
297 0 : ulong out_sz = safe_snprintf( *out_buf, *out_buf_sz, "\"err\": \"overflow\", " );
298 0 : *out_buf += out_sz;
299 0 : *out_buf_sz -= out_sz;
300 :
301 0 : return FD_QUIC_PARSE_FAIL;
302 0 : }
303 :
304 : /* TODO pretty print the reason phrase */
305 :
306 0 : cur_buf += reason_phrase_length;
307 :
308 0 : break;
309 0 : }
310 :
311 0 : case 0x1d: /* connection close */
312 0 : {
313 : /* the conn_close_1_frame structure is different to conn_close_0_frame */
314 0 : ulong reason_phrase_length = data.conn_close_1_frame.reason_phrase_length;
315 0 : ulong remain = (ulong)( buf_end - cur_buf );
316 0 : if( FD_UNLIKELY( reason_phrase_length > remain ) ) {
317 0 : ulong out_sz = safe_snprintf( *out_buf, *out_buf_sz, "\"err\": \"overflow\", " );
318 0 : *out_buf += out_sz;
319 0 : *out_buf_sz -= out_sz;
320 :
321 0 : return FD_QUIC_PARSE_FAIL;
322 0 : }
323 :
324 : /* TODO pretty print the reason phrase */
325 :
326 0 : cur_buf += reason_phrase_length;
327 :
328 0 : break;
329 0 : }
330 0 : }
331 :
332 0 : return (ulong)( cur_buf - buf );
333 :
334 0 : }
335 :
336 : ulong
337 : fd_quic_pretty_print_frames( char ** out_buf,
338 : ulong * out_buf_sz,
339 : uchar const * buf,
340 : ulong buf_sz );
341 :
342 :
343 : ulong
344 : fd_quic_pretty_print_quic_hdr_initial( char ** out_buf,
345 : ulong * out_buf_sz,
346 : uchar const ** frame_ptr,
347 : ulong * frame_sz,
348 : uchar const * buf,
349 0 : ulong buf_sz ) {
350 0 : ulong sz = safe_snprintf( *out_buf, *out_buf_sz, "\"hdr_type\": \"initial\", " );
351 0 : *out_buf += sz;
352 0 : *out_buf_sz -= sz;
353 :
354 0 : fd_quic_initial_t initial[1] = {0};
355 0 : ulong rc = fd_quic_decode_initial( initial, buf, buf_sz );
356 0 : if( FD_UNLIKELY( rc == FD_QUIC_PARSE_FAIL ) ) {
357 0 : ulong sz = safe_snprintf( *out_buf, *out_buf_sz, "\"err\": \"hdr_parse_failed\", " );
358 0 : *out_buf += sz;
359 0 : *out_buf_sz -= sz;
360 :
361 0 : FD_LOG_HEXDUMP_ERR(( "hdr_parse_failed", buf, fd_ulong_min( 16, buf_sz ) ));
362 :
363 0 : return FD_QUIC_PARSE_FAIL;
364 0 : }
365 :
366 0 : ulong body_sz = initial->len; /* not a protected field */
367 0 : ulong pn_offset = initial->pkt_num_pnoff;
368 0 : ulong pkt_number_sz = fd_quic_h0_pkt_num_len( buf[0] ) + 1u;
369 0 : ulong payload_off = pn_offset + pkt_number_sz;
370 :
371 : /* now we have decrypted packet number */
372 0 : ulong pkt_number = fd_quic_pktnum_decode( buf+pn_offset, pkt_number_sz );
373 :
374 : /* write pkt_number_sz into initial, for tracing */
375 : /* note this is the raw packet number, which may have been truncated */
376 0 : initial->pkt_num = pkt_number;
377 :
378 0 : *frame_ptr = buf + payload_off;
379 0 : *frame_sz = body_sz - pkt_number_sz - FD_QUIC_CRYPTO_TAG_SZ; /* total size of all frames in packet */
380 :
381 0 : fd_quic_pretty_print_struct_initial( out_buf, out_buf_sz, initial );
382 :
383 0 : return payload_off;
384 0 : }
385 :
386 :
387 : ulong
388 : fd_quic_pretty_print_quic_hdr_handshake( char ** out_buf,
389 : ulong * out_buf_sz,
390 : uchar const ** frame_ptr,
391 : ulong * frame_sz,
392 : uchar const * buf,
393 0 : ulong buf_sz ) {
394 0 : ulong sz = safe_snprintf( *out_buf, *out_buf_sz, "\"hdr_type\": \"handshake\", " );
395 0 : *out_buf += sz;
396 0 : *out_buf_sz -= sz;
397 :
398 0 : fd_quic_handshake_t handshake[1] = {0};
399 0 : ulong rc = fd_quic_decode_handshake( handshake, buf, buf_sz );
400 0 : if( FD_UNLIKELY( rc == FD_QUIC_PARSE_FAIL ) ) {
401 0 : ulong sz = safe_snprintf( *out_buf, *out_buf_sz, "\"err\": \"hdr_parse_failed\", " );
402 0 : *out_buf += sz;
403 0 : *out_buf_sz -= sz;
404 :
405 0 : FD_LOG_HEXDUMP_ERR(( "hdr_parse_failed", buf, fd_ulong_min( 16, buf_sz ) ));
406 :
407 0 : return FD_QUIC_PARSE_FAIL;
408 0 : }
409 :
410 0 : ulong body_sz = handshake->len; /* not a protected field */
411 0 : ulong pn_offset = handshake->pkt_num_pnoff;
412 0 : ulong pkt_number_sz = fd_quic_h0_pkt_num_len( buf[0] ) + 1u;
413 0 : ulong payload_off = pn_offset + pkt_number_sz;
414 :
415 : /* now we have decrypted packet number */
416 0 : ulong pkt_number = fd_quic_pktnum_decode( buf+pn_offset, pkt_number_sz );
417 :
418 : /* write pkt_number_sz into handshake, for tracing */
419 : /* note this is the raw packet number, which may have been truncated */
420 0 : handshake->pkt_num = pkt_number;
421 :
422 0 : *frame_ptr = buf + payload_off;
423 0 : *frame_sz = body_sz - pkt_number_sz - FD_QUIC_CRYPTO_TAG_SZ; /* total size of all frames in packet */
424 :
425 0 : fd_quic_pretty_print_struct_handshake( out_buf, out_buf_sz, handshake );
426 :
427 0 : return payload_off;
428 0 : }
429 :
430 :
431 : ulong
432 : fd_quic_pretty_print_quic_hdr_one_rtt( char ** out_buf,
433 : ulong * out_buf_sz,
434 : uchar const ** frame_ptr,
435 : ulong * frame_sz,
436 : uchar const * buf,
437 0 : ulong buf_sz ) {
438 0 : ulong sz = safe_snprintf( *out_buf, *out_buf_sz, "\"hdr_type\": \"1-rtt\", " );
439 0 : *out_buf += sz;
440 0 : *out_buf_sz -= sz;
441 :
442 0 : fd_quic_one_rtt_t one_rtt[1] = {0};
443 :
444 : /* hidden field needed by decode function */
445 0 : one_rtt->dst_conn_id_len = 8;
446 :
447 0 : ulong rc = fd_quic_decode_one_rtt( one_rtt, buf, buf_sz );
448 0 : if( FD_UNLIKELY( rc == FD_QUIC_PARSE_FAIL ) ) {
449 0 : ulong sz = safe_snprintf( *out_buf, *out_buf_sz, "\"err\": \"hdr_parse_failed\", " );
450 0 : *out_buf += sz;
451 0 : *out_buf_sz -= sz;
452 :
453 0 : FD_LOG_HEXDUMP_ERR(( "hdr_parse_failed", buf, fd_ulong_min( 16, buf_sz ) ));
454 :
455 0 : return FD_QUIC_PARSE_FAIL;
456 0 : }
457 :
458 0 : ulong pn_offset = one_rtt->pkt_num_pnoff;
459 0 : ulong pkt_number_sz = fd_quic_h0_pkt_num_len( buf[0] ) + 1u;
460 0 : ulong payload_off = pn_offset + pkt_number_sz;
461 0 : ulong payload_sz = buf_sz - pn_offset - pkt_number_sz; /* includes auth tag */
462 :
463 : /* now we have decrypted packet number */
464 0 : ulong pkt_number = fd_quic_pktnum_decode( buf+pn_offset, pkt_number_sz );
465 :
466 : /* write pkt_number_sz into one_rtt, for tracing */
467 : /* note this is the raw packet number, which may have been truncated */
468 0 : one_rtt->pkt_num = pkt_number;
469 :
470 0 : *frame_ptr = buf + payload_off;
471 0 : *frame_sz = payload_sz - FD_QUIC_CRYPTO_TAG_SZ; /* total size of all frames in packet */
472 :
473 0 : fd_quic_pretty_print_struct_one_rtt( out_buf, out_buf_sz, one_rtt );
474 :
475 0 : return payload_off;
476 0 : }
477 :
478 :
479 : ulong
480 : fd_quic_pretty_print_quic_hdr( char ** out_buf,
481 : ulong * out_buf_sz,
482 : uchar const ** frame_ptr,
483 : ulong * frame_sz,
484 : uchar const * buf,
485 0 : ulong buf_sz ) {
486 0 : ulong sz;
487 :
488 0 : uint first = (uint)buf[0];
489 0 : uint is_long = first >> 7u;
490 :
491 0 : if( !is_long ) {
492 0 : return fd_quic_pretty_print_quic_hdr_one_rtt( out_buf, out_buf_sz, frame_ptr, frame_sz, buf, buf_sz );
493 0 : }
494 :
495 0 : uint long_type = ( first >> 4u ) & 0x03u;
496 :
497 0 : switch( long_type ) {
498 0 : case 0x00: /* initial */
499 0 : return fd_quic_pretty_print_quic_hdr_initial( out_buf, out_buf_sz, frame_ptr, frame_sz, buf, buf_sz );
500 0 : case 0x01: /* 0-rtt - unused */
501 0 : sz = safe_snprintf( *out_buf, *out_buf_sz, "\"err\": \"0-rtt\", " );
502 0 : *out_buf += sz;
503 0 : *out_buf_sz -= sz;
504 0 : return FD_QUIC_PARSE_FAIL;
505 0 : case 0x02: /* handshake */
506 0 : return fd_quic_pretty_print_quic_hdr_handshake( out_buf, out_buf_sz, frame_ptr, frame_sz, buf, buf_sz );
507 0 : case 0x03:
508 0 : sz = safe_snprintf( *out_buf, *out_buf_sz, "\"err\": \"not-implemented-retry\", " );
509 0 : *out_buf += sz;
510 0 : *out_buf_sz -= sz;
511 0 : return FD_QUIC_PARSE_FAIL;
512 0 : }
513 :
514 : /* long type is uint & 0x03u - yet gcc thinks this is reachable */
515 0 : return FD_QUIC_PARSE_FAIL;
516 0 : }
517 :
518 :
519 : /* 16 bytes allows for: xxx.xxx.xxx.xxx\0 */
520 0 : #define IP4_TO_STR_BUF_SZ 16
521 : static
522 : char const *
523 0 : ip4_to_str( char buf[IP4_TO_STR_BUF_SZ], uint ip4_addr ) {
524 : /* can't use sizeof(buf) here, as technically typeof(buf) is char* */
525 0 : ulong sz = safe_snprintf( buf, IP4_TO_STR_BUF_SZ, FD_IP4_ADDR_FMT, FD_IP4_ADDR_FMT_ARGS( ip4_addr ) );
526 : /* should not be possible */
527 0 : if( FD_UNLIKELY( sz >= IP4_TO_STR_BUF_SZ ) ) buf[IP4_TO_STR_BUF_SZ-1] = '\0';
528 0 : return buf;
529 0 : }
530 :
531 :
532 : ulong
533 : fd_quic_pretty_print_quic_pkt( fd_quic_pretty_print_t * pkt_ctx,
534 : ulong now,
535 : uchar const * buf,
536 0 : ulong buf_sz ) {
537 0 : (void)now;
538 :
539 0 : char tmp_buf[16];
540 :
541 0 : if( buf == NULL ) return FD_QUIC_PARSE_FAIL;
542 :
543 0 : static FD_TL char pretty_print_buf[16384];
544 :
545 0 : memset( pretty_print_buf, 0, sizeof( pretty_print_buf ) );
546 :
547 0 : char * out_buf = &pretty_print_buf[0];
548 0 : ulong out_buf_sz = sizeof( pretty_print_buf ) - 1UL;
549 :
550 0 : uchar const * frame_ptr = NULL;
551 0 : ulong frame_sz = 0;
552 :
553 0 : ulong sz = safe_snprintf( out_buf, out_buf_sz, "{ \"type\": \"packet\", \"flow\": \"%s\", ",
554 0 : pkt_ctx->flow ? "egress" : "ingress" );
555 0 : out_buf += sz;
556 0 : out_buf_sz -= sz;
557 :
558 0 : /* */ sz = safe_snprintf( out_buf, out_buf_sz, "\"conn_idx\": %u, ",
559 0 : pkt_ctx->conn_idx );
560 0 : out_buf += sz;
561 0 : out_buf_sz -= sz;
562 :
563 0 : char time_str[FD_LOG_WALLCLOCK_CSTR_BUF_SZ];
564 0 : /* */ sz = safe_snprintf( out_buf, out_buf_sz, "\"trace_time\": \"%s\", ",
565 0 : fd_log_wallclock_cstr( fd_log_wallclock(), time_str ) );
566 0 : out_buf += sz;
567 0 : out_buf_sz -= sz;
568 :
569 0 : /* */ sz = safe_snprintf( out_buf, out_buf_sz, "\"src_ip_addr\": \"%s\", \"src_udp_port\": \"%u\", ",
570 0 : ip4_to_str( tmp_buf, pkt_ctx->ip4_saddr ), fd_ushort_bswap( (ushort)pkt_ctx->udp_sport ) );
571 0 : out_buf += sz;
572 0 : out_buf_sz -= sz;
573 :
574 0 : /* */ sz = safe_snprintf( out_buf, out_buf_sz, "\"dst_ip_addr\": \"%s\", \"dst_udp_port\": \"%u\", ",
575 0 : ip4_to_str( tmp_buf, pkt_ctx->ip4_daddr ), fd_ushort_bswap( (ushort)pkt_ctx->udp_dport ) );
576 0 : out_buf += sz;
577 0 : out_buf_sz -= sz;
578 :
579 0 : ulong hdr_rc = fd_quic_pretty_print_quic_hdr( &out_buf,
580 0 : &out_buf_sz,
581 0 : &frame_ptr,
582 0 : &frame_sz,
583 0 : buf,
584 0 : buf_sz );
585 0 : if( hdr_rc == FD_QUIC_PARSE_FAIL ) {
586 0 : sz = safe_snprintf( out_buf, out_buf_sz, "\"err\": \"parse_fail\" } " );
587 0 : out_buf += sz;
588 0 : out_buf_sz -= sz;
589 :
590 0 : return FD_QUIC_PARSE_FAIL;
591 0 : }
592 :
593 0 : sz = safe_snprintf( out_buf, out_buf_sz, "\"frames\": [ " );
594 0 : out_buf += sz;
595 0 : out_buf_sz -= sz;
596 :
597 0 : ulong rc = fd_quic_pretty_print_frames( &out_buf,
598 0 : &out_buf_sz,
599 0 : frame_ptr,
600 0 : frame_sz );
601 0 : if( rc == FD_QUIC_PARSE_FAIL ) {
602 0 : sz = safe_snprintf( out_buf, out_buf_sz, "], \"err\": \"parse_fail\" }, " );
603 0 : out_buf += sz;
604 0 : out_buf_sz -= sz;
605 0 : printf( "\n[ %s ]\n", pretty_print_buf );
606 0 : fflush( stdout );
607 0 : return FD_QUIC_PARSE_FAIL;
608 0 : }
609 :
610 0 : sz = safe_snprintf( out_buf, out_buf_sz, "] }, " );
611 0 : out_buf += sz;
612 0 : out_buf_sz -= sz;
613 :
614 0 : for( ulong j = 0; j < (ulong)( out_buf - pretty_print_buf); ++j ) {
615 0 : if( pretty_print_buf[j] == '\0' ) pretty_print_buf[j] = '*';
616 0 : }
617 :
618 0 : printf( "[ %s ]\n", pretty_print_buf );
619 :
620 0 : return rc;
621 0 : }
622 :
623 : ulong
624 : fd_quic_pretty_print_frames( char ** out_buf,
625 : ulong * out_buf_sz,
626 : uchar const * buf,
627 0 : ulong buf_sz ) {
628 0 : uchar const * orig_buf = buf;
629 0 : ulong sz;
630 :
631 0 : while( buf_sz > 0 ) {
632 0 : sz = safe_snprintf( *out_buf, *out_buf_sz, "{ \"type\": \"frame\", " );
633 0 : *out_buf += sz;
634 0 : *out_buf_sz -= sz;
635 :
636 0 : ulong rc = fd_quic_pretty_print_frame( out_buf, out_buf_sz, buf, buf_sz );
637 0 : if( rc == FD_QUIC_PARSE_FAIL ) {
638 0 : sz = safe_snprintf( *out_buf, *out_buf_sz, "\"err\": \"parse_fail\" }, " );
639 0 : *out_buf += sz;
640 0 : *out_buf_sz -= sz;
641 0 : break;
642 0 : }
643 :
644 0 : sz = safe_snprintf( *out_buf, *out_buf_sz, " }, " );
645 0 : *out_buf += sz;
646 0 : *out_buf_sz -= sz;
647 :
648 0 : if( rc >= buf_sz ) break;
649 :
650 0 : buf += rc;
651 0 : buf_sz -= rc;
652 0 : }
653 :
654 0 : return (ulong)( buf - orig_buf );
655 0 : }
|