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 0x30:
292 0 : case 0x31:
293 0 : {
294 0 : ulong remain = (ulong)( buf_end - cur_buf );
295 0 : ulong data_sz = id==0x30U ? remain : data.datagram_1_frame.length;
296 0 : ulong out_sz;
297 :
298 0 : if( FD_UNLIKELY( data_sz > remain ) ) {
299 0 : out_sz = safe_snprintf( *out_buf, *out_buf_sz, "\"err\": \"overflow\", " );
300 0 : *out_buf += out_sz;
301 0 : *out_buf_sz -= out_sz;
302 :
303 0 : return FD_QUIC_PARSE_FAIL;
304 0 : }
305 :
306 0 : out_sz = safe_snprintf( *out_buf, *out_buf_sz, "\"data\": [ " );
307 0 : *out_buf += out_sz;
308 0 : *out_buf_sz -= out_sz;
309 :
310 0 : for( ulong j = 0UL; j < data_sz; ++j ) {
311 0 : out_sz = safe_snprintf( *out_buf, *out_buf_sz, "0x%02x, ", cur_buf[j] );
312 0 : *out_buf += out_sz;
313 0 : *out_buf_sz -= out_sz;
314 0 : }
315 :
316 0 : out_sz = safe_snprintf( *out_buf, *out_buf_sz, "], " );
317 0 : *out_buf += out_sz;
318 0 : *out_buf_sz -= out_sz;
319 :
320 0 : cur_buf += data_sz;
321 :
322 0 : break;
323 0 : }
324 :
325 0 : case 0x1c: /* connection close */
326 0 : {
327 : /* the conn_close_1_frame structure is different to conn_close_0_frame */
328 0 : ulong reason_phrase_length = data.conn_close_0_frame.reason_phrase_length;
329 0 : ulong remain = (ulong)( buf_end - cur_buf );
330 0 : if( FD_UNLIKELY( reason_phrase_length > remain ) ) {
331 0 : ulong out_sz = safe_snprintf( *out_buf, *out_buf_sz, "\"err\": \"overflow\", " );
332 0 : *out_buf += out_sz;
333 0 : *out_buf_sz -= out_sz;
334 :
335 0 : return FD_QUIC_PARSE_FAIL;
336 0 : }
337 :
338 : /* TODO pretty print the reason phrase */
339 :
340 0 : cur_buf += reason_phrase_length;
341 :
342 0 : break;
343 0 : }
344 :
345 0 : case 0x1d: /* connection close */
346 0 : {
347 : /* the conn_close_1_frame structure is different to conn_close_0_frame */
348 0 : ulong reason_phrase_length = data.conn_close_1_frame.reason_phrase_length;
349 0 : ulong remain = (ulong)( buf_end - cur_buf );
350 0 : if( FD_UNLIKELY( reason_phrase_length > remain ) ) {
351 0 : ulong out_sz = safe_snprintf( *out_buf, *out_buf_sz, "\"err\": \"overflow\", " );
352 0 : *out_buf += out_sz;
353 0 : *out_buf_sz -= out_sz;
354 :
355 0 : return FD_QUIC_PARSE_FAIL;
356 0 : }
357 :
358 : /* TODO pretty print the reason phrase */
359 :
360 0 : cur_buf += reason_phrase_length;
361 :
362 0 : break;
363 0 : }
364 0 : }
365 :
366 0 : return (ulong)( cur_buf - buf );
367 :
368 0 : }
369 :
370 : ulong
371 : fd_quic_pretty_print_frames( char ** out_buf,
372 : ulong * out_buf_sz,
373 : uchar const * buf,
374 : ulong buf_sz );
375 :
376 :
377 : ulong
378 : fd_quic_pretty_print_quic_hdr_initial( char ** out_buf,
379 : ulong * out_buf_sz,
380 : uchar const ** frame_ptr,
381 : ulong * frame_sz,
382 : uchar const * buf,
383 0 : ulong buf_sz ) {
384 0 : ulong sz = safe_snprintf( *out_buf, *out_buf_sz, "\"hdr_type\": \"initial\", " );
385 0 : *out_buf += sz;
386 0 : *out_buf_sz -= sz;
387 :
388 0 : fd_quic_initial_t initial[1] = {0};
389 0 : ulong rc = fd_quic_decode_initial( initial, buf, buf_sz );
390 0 : if( FD_UNLIKELY( rc == FD_QUIC_PARSE_FAIL ) ) {
391 0 : ulong sz = safe_snprintf( *out_buf, *out_buf_sz, "\"err\": \"hdr_parse_failed\", " );
392 0 : *out_buf += sz;
393 0 : *out_buf_sz -= sz;
394 :
395 0 : FD_LOG_HEXDUMP_ERR(( "hdr_parse_failed", buf, fd_ulong_min( 16, buf_sz ) ));
396 :
397 0 : return FD_QUIC_PARSE_FAIL;
398 0 : }
399 :
400 0 : ulong body_sz = initial->len; /* not a protected field */
401 0 : ulong pn_offset = initial->pkt_num_pnoff;
402 0 : ulong pkt_number_sz = fd_quic_h0_pkt_num_len( buf[0] ) + 1u;
403 0 : ulong payload_off = pn_offset + pkt_number_sz;
404 :
405 : /* now we have decrypted packet number */
406 0 : ulong pkt_number = fd_quic_pktnum_decode( buf+pn_offset, pkt_number_sz );
407 :
408 : /* write pkt_number_sz into initial, for tracing */
409 : /* note this is the raw packet number, which may have been truncated */
410 0 : initial->pkt_num = pkt_number;
411 :
412 0 : *frame_ptr = buf + payload_off;
413 0 : *frame_sz = body_sz - pkt_number_sz - FD_QUIC_CRYPTO_TAG_SZ; /* total size of all frames in packet */
414 :
415 0 : fd_quic_pretty_print_struct_initial( out_buf, out_buf_sz, initial );
416 :
417 0 : return payload_off;
418 0 : }
419 :
420 :
421 : ulong
422 : fd_quic_pretty_print_quic_hdr_handshake( char ** out_buf,
423 : ulong * out_buf_sz,
424 : uchar const ** frame_ptr,
425 : ulong * frame_sz,
426 : uchar const * buf,
427 0 : ulong buf_sz ) {
428 0 : ulong sz = safe_snprintf( *out_buf, *out_buf_sz, "\"hdr_type\": \"handshake\", " );
429 0 : *out_buf += sz;
430 0 : *out_buf_sz -= sz;
431 :
432 0 : fd_quic_handshake_t handshake[1] = {0};
433 0 : ulong rc = fd_quic_decode_handshake( handshake, buf, buf_sz );
434 0 : if( FD_UNLIKELY( rc == FD_QUIC_PARSE_FAIL ) ) {
435 0 : ulong sz = safe_snprintf( *out_buf, *out_buf_sz, "\"err\": \"hdr_parse_failed\", " );
436 0 : *out_buf += sz;
437 0 : *out_buf_sz -= sz;
438 :
439 0 : FD_LOG_HEXDUMP_ERR(( "hdr_parse_failed", buf, fd_ulong_min( 16, buf_sz ) ));
440 :
441 0 : return FD_QUIC_PARSE_FAIL;
442 0 : }
443 :
444 0 : ulong body_sz = handshake->len; /* not a protected field */
445 0 : ulong pn_offset = handshake->pkt_num_pnoff;
446 0 : ulong pkt_number_sz = fd_quic_h0_pkt_num_len( buf[0] ) + 1u;
447 0 : ulong payload_off = pn_offset + pkt_number_sz;
448 :
449 : /* now we have decrypted packet number */
450 0 : ulong pkt_number = fd_quic_pktnum_decode( buf+pn_offset, pkt_number_sz );
451 :
452 : /* write pkt_number_sz into handshake, for tracing */
453 : /* note this is the raw packet number, which may have been truncated */
454 0 : handshake->pkt_num = pkt_number;
455 :
456 0 : *frame_ptr = buf + payload_off;
457 0 : *frame_sz = body_sz - pkt_number_sz - FD_QUIC_CRYPTO_TAG_SZ; /* total size of all frames in packet */
458 :
459 0 : fd_quic_pretty_print_struct_handshake( out_buf, out_buf_sz, handshake );
460 :
461 0 : return payload_off;
462 0 : }
463 :
464 :
465 : ulong
466 : fd_quic_pretty_print_quic_hdr_one_rtt( char ** out_buf,
467 : ulong * out_buf_sz,
468 : uchar const ** frame_ptr,
469 : ulong * frame_sz,
470 : uchar const * buf,
471 0 : ulong buf_sz ) {
472 0 : ulong sz = safe_snprintf( *out_buf, *out_buf_sz, "\"hdr_type\": \"1-rtt\", " );
473 0 : *out_buf += sz;
474 0 : *out_buf_sz -= sz;
475 :
476 0 : fd_quic_one_rtt_t one_rtt[1] = {0};
477 :
478 : /* hidden field needed by decode function */
479 0 : one_rtt->dst_conn_id_len = 8;
480 :
481 0 : ulong rc = fd_quic_decode_one_rtt( one_rtt, buf, buf_sz );
482 0 : if( FD_UNLIKELY( rc == FD_QUIC_PARSE_FAIL ) ) {
483 0 : ulong sz = safe_snprintf( *out_buf, *out_buf_sz, "\"err\": \"hdr_parse_failed\", " );
484 0 : *out_buf += sz;
485 0 : *out_buf_sz -= sz;
486 :
487 0 : FD_LOG_HEXDUMP_ERR(( "hdr_parse_failed", buf, fd_ulong_min( 16, buf_sz ) ));
488 :
489 0 : return FD_QUIC_PARSE_FAIL;
490 0 : }
491 :
492 0 : ulong pn_offset = one_rtt->pkt_num_pnoff;
493 0 : ulong pkt_number_sz = fd_quic_h0_pkt_num_len( buf[0] ) + 1u;
494 0 : ulong payload_off = pn_offset + pkt_number_sz;
495 0 : ulong payload_sz = buf_sz - pn_offset - pkt_number_sz; /* includes auth tag */
496 :
497 : /* now we have decrypted packet number */
498 0 : ulong pkt_number = fd_quic_pktnum_decode( buf+pn_offset, pkt_number_sz );
499 :
500 : /* write pkt_number_sz into one_rtt, for tracing */
501 : /* note this is the raw packet number, which may have been truncated */
502 0 : one_rtt->pkt_num = pkt_number;
503 :
504 0 : *frame_ptr = buf + payload_off;
505 0 : *frame_sz = payload_sz - FD_QUIC_CRYPTO_TAG_SZ; /* total size of all frames in packet */
506 :
507 0 : fd_quic_pretty_print_struct_one_rtt( out_buf, out_buf_sz, one_rtt );
508 :
509 0 : return payload_off;
510 0 : }
511 :
512 :
513 : ulong
514 : fd_quic_pretty_print_quic_hdr( char ** out_buf,
515 : ulong * out_buf_sz,
516 : uchar const ** frame_ptr,
517 : ulong * frame_sz,
518 : uchar const * buf,
519 0 : ulong buf_sz ) {
520 0 : ulong sz;
521 :
522 0 : uint first = (uint)buf[0];
523 0 : uint is_long = first >> 7u;
524 :
525 0 : if( !is_long ) {
526 0 : return fd_quic_pretty_print_quic_hdr_one_rtt( out_buf, out_buf_sz, frame_ptr, frame_sz, buf, buf_sz );
527 0 : }
528 :
529 0 : uint long_type = ( first >> 4u ) & 0x03u;
530 :
531 0 : switch( long_type ) {
532 0 : case 0x00: /* initial */
533 0 : return fd_quic_pretty_print_quic_hdr_initial( out_buf, out_buf_sz, frame_ptr, frame_sz, buf, buf_sz );
534 0 : case 0x01: /* 0-rtt - unused */
535 0 : sz = safe_snprintf( *out_buf, *out_buf_sz, "\"err\": \"0-rtt\", " );
536 0 : *out_buf += sz;
537 0 : *out_buf_sz -= sz;
538 0 : return FD_QUIC_PARSE_FAIL;
539 0 : case 0x02: /* handshake */
540 0 : return fd_quic_pretty_print_quic_hdr_handshake( out_buf, out_buf_sz, frame_ptr, frame_sz, buf, buf_sz );
541 0 : case 0x03:
542 0 : sz = safe_snprintf( *out_buf, *out_buf_sz, "\"err\": \"not-implemented-retry\", " );
543 0 : *out_buf += sz;
544 0 : *out_buf_sz -= sz;
545 0 : return FD_QUIC_PARSE_FAIL;
546 0 : }
547 :
548 : /* long type is uint & 0x03u - yet gcc thinks this is reachable */
549 0 : return FD_QUIC_PARSE_FAIL;
550 0 : }
551 :
552 :
553 : /* 16 bytes allows for: xxx.xxx.xxx.xxx\0 */
554 0 : #define IP4_TO_STR_BUF_SZ 16
555 : static
556 : char const *
557 0 : ip4_to_str( char buf[IP4_TO_STR_BUF_SZ], uint ip4_addr ) {
558 : /* can't use sizeof(buf) here, as technically typeof(buf) is char* */
559 0 : ulong sz = safe_snprintf( buf, IP4_TO_STR_BUF_SZ, FD_IP4_ADDR_FMT, FD_IP4_ADDR_FMT_ARGS( ip4_addr ) );
560 : /* should not be possible */
561 0 : if( FD_UNLIKELY( sz >= IP4_TO_STR_BUF_SZ ) ) buf[IP4_TO_STR_BUF_SZ-1] = '\0';
562 0 : return buf;
563 0 : }
564 :
565 :
566 : ulong
567 : fd_quic_pretty_print_quic_pkt( fd_quic_pretty_print_t * pkt_ctx,
568 : long now,
569 : uchar const * buf,
570 0 : ulong buf_sz ) {
571 0 : (void)now;
572 :
573 0 : char tmp_buf[16];
574 :
575 0 : if( buf == NULL ) return FD_QUIC_PARSE_FAIL;
576 :
577 0 : static FD_TL char pretty_print_buf[16384];
578 :
579 0 : memset( pretty_print_buf, 0, sizeof( pretty_print_buf ) );
580 :
581 0 : char * out_buf = &pretty_print_buf[0];
582 0 : ulong out_buf_sz = sizeof( pretty_print_buf ) - 1UL;
583 :
584 0 : uchar const * frame_ptr = NULL;
585 0 : ulong frame_sz = 0;
586 :
587 0 : ulong sz = safe_snprintf( out_buf, out_buf_sz, "{ \"type\": \"packet\", \"flow\": \"%s\", ",
588 0 : pkt_ctx->flow ? "egress" : "ingress" );
589 0 : out_buf += sz;
590 0 : out_buf_sz -= sz;
591 :
592 0 : /* */ sz = safe_snprintf( out_buf, out_buf_sz, "\"conn_idx\": %u, ",
593 0 : pkt_ctx->conn_idx );
594 0 : out_buf += sz;
595 0 : out_buf_sz -= sz;
596 :
597 0 : char time_str[FD_LOG_WALLCLOCK_CSTR_BUF_SZ];
598 0 : /* */ sz = safe_snprintf( out_buf, out_buf_sz, "\"trace_time\": \"%s\", ",
599 0 : fd_log_wallclock_cstr( fd_log_wallclock(), time_str ) );
600 0 : out_buf += sz;
601 0 : out_buf_sz -= sz;
602 :
603 0 : /* */ sz = safe_snprintf( out_buf, out_buf_sz, "\"src_ip_addr\": \"%s\", \"src_udp_port\": \"%u\", ",
604 0 : ip4_to_str( tmp_buf, pkt_ctx->ip4_saddr ), pkt_ctx->udp_sport );
605 0 : out_buf += sz;
606 0 : out_buf_sz -= sz;
607 :
608 0 : /* */ sz = safe_snprintf( out_buf, out_buf_sz, "\"dst_ip_addr\": \"%s\", \"dst_udp_port\": \"%u\", ",
609 0 : ip4_to_str( tmp_buf, pkt_ctx->ip4_daddr ), pkt_ctx->udp_dport );
610 0 : out_buf += sz;
611 0 : out_buf_sz -= sz;
612 :
613 0 : ulong hdr_rc = fd_quic_pretty_print_quic_hdr( &out_buf,
614 0 : &out_buf_sz,
615 0 : &frame_ptr,
616 0 : &frame_sz,
617 0 : buf,
618 0 : buf_sz );
619 0 : if( hdr_rc == FD_QUIC_PARSE_FAIL ) {
620 0 : sz = safe_snprintf( out_buf, out_buf_sz, "\"err\": \"parse_fail\" } " );
621 0 : out_buf += sz;
622 0 : out_buf_sz -= sz;
623 :
624 0 : return FD_QUIC_PARSE_FAIL;
625 0 : }
626 :
627 0 : sz = safe_snprintf( out_buf, out_buf_sz, "\"frames\": [ " );
628 0 : out_buf += sz;
629 0 : out_buf_sz -= sz;
630 :
631 0 : ulong rc = fd_quic_pretty_print_frames( &out_buf,
632 0 : &out_buf_sz,
633 0 : frame_ptr,
634 0 : frame_sz );
635 0 : if( rc == FD_QUIC_PARSE_FAIL ) {
636 0 : sz = safe_snprintf( out_buf, out_buf_sz, "], \"err\": \"parse_fail\" }, " );
637 0 : out_buf += sz;
638 0 : out_buf_sz -= sz;
639 0 : printf( "\n[ %s ]\n", pretty_print_buf );
640 0 : fflush( stdout );
641 0 : return FD_QUIC_PARSE_FAIL;
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 : for( ulong j = 0; j < (ulong)( out_buf - pretty_print_buf); ++j ) {
649 0 : if( pretty_print_buf[j] == '\0' ) pretty_print_buf[j] = '*';
650 0 : }
651 :
652 0 : printf( "[ %s ]\n", pretty_print_buf );
653 :
654 0 : return rc;
655 0 : }
656 :
657 : ulong
658 : fd_quic_pretty_print_frames( char ** out_buf,
659 : ulong * out_buf_sz,
660 : uchar const * buf,
661 0 : ulong buf_sz ) {
662 0 : uchar const * orig_buf = buf;
663 0 : ulong sz;
664 :
665 0 : while( buf_sz > 0 ) {
666 0 : sz = safe_snprintf( *out_buf, *out_buf_sz, "{ \"type\": \"frame\", " );
667 0 : *out_buf += sz;
668 0 : *out_buf_sz -= sz;
669 :
670 0 : ulong rc = fd_quic_pretty_print_frame( out_buf, out_buf_sz, buf, buf_sz );
671 0 : if( rc == FD_QUIC_PARSE_FAIL ) {
672 0 : sz = safe_snprintf( *out_buf, *out_buf_sz, "\"err\": \"parse_fail\" }, " );
673 0 : *out_buf += sz;
674 0 : *out_buf_sz -= sz;
675 0 : break;
676 0 : }
677 :
678 0 : sz = safe_snprintf( *out_buf, *out_buf_sz, " }, " );
679 0 : *out_buf += sz;
680 0 : *out_buf_sz -= sz;
681 :
682 0 : if( rc >= buf_sz ) break;
683 :
684 0 : buf += rc;
685 0 : buf_sz -= rc;
686 0 : }
687 :
688 0 : return (ulong)( buf - orig_buf );
689 0 : }
|