2 * Copyright (c) 2021 Apple, Inc.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in
12 * the documentation and/or other materials provided with the
14 * 3. The names of the authors may not be used to endorse or promote
15 * products derived from this software without specific prior
18 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
19 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
20 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
23 /* \summary: QUIC Protocol printer */
24 /* specification: https://www.rfc-editor.org/rfc/rfc9000.txt */
28 #include "netdissect-stdinc.h"
29 #include "netdissect-alloc.h"
30 #include "netdissect.h"
33 #define QUIC_MAX_CID_LENGTH 20
35 typedef uint8_t quic_cid
[QUIC_MAX_CID_LENGTH
];
37 struct quic_cid_array
{
38 uint8_t cid
[QUIC_MAX_CID_LENGTH
];
42 enum quic_lh_packet_type
{
43 QUIC_LH_TYPE_INITIAL
= 0,
44 QUIC_LH_TYPE_0RTT
= 1,
45 QUIC_LH_TYPE_HANDSHAKE
= 2,
46 QUIC_LH_TYPE_RETRY
= 3
50 hexprint(netdissect_options
*ndo
, const uint8_t *cp
, size_t len
)
54 for (i
= 0; i
< len
; i
++)
55 ND_PRINT("%02x", cp
[i
]);
58 #define QUIC_CID_LIST_MAX 512
60 static struct quic_cid_array quic_cid_array
[QUIC_CID_LIST_MAX
];
62 static struct quic_cid_array
*
63 lookup_quic_cid(const u_char
*cid
, size_t length
)
65 for (unsigned int i
= 0; i
< QUIC_CID_LIST_MAX
; i
++) {
66 if (quic_cid_array
[i
].length
> length
) {
69 if (quic_cid_array
[i
].length
== 0) {
72 if (memcmp(quic_cid_array
[i
].cid
, cid
,
73 quic_cid_array
[i
].length
) == 0) {
75 * Swap the entries so that it behaves like an
79 struct quic_cid_array tmp
= quic_cid_array
[i
];
80 quic_cid_array
[i
] = quic_cid_array
[0];
81 quic_cid_array
[0] = tmp
;
84 return &quic_cid_array
[0];
92 register_quic_cid(const quic_cid cid
, uint8_t length
)
94 static uint16_t next_cid
= 0;
97 lookup_quic_cid(cid
, length
) != NULL
) {
100 memcpy(&quic_cid_array
[next_cid
].cid
, cid
, QUIC_MAX_CID_LENGTH
);
101 quic_cid_array
[next_cid
].length
= length
;
102 next_cid
= (next_cid
+ 1) % QUIC_CID_LIST_MAX
;
105 /* Returns 1 if the first octet looks like a QUIC packet. */
107 quic_detect(netdissect_options
*ndo
, const u_char
*p
, const u_int len
)
113 first_octet
= GET_U_1(p
);
114 /* All QUIC packets must have the Fixed Bit set to 1. */
115 if ((first_octet
& 0x40) == 0x40)
121 /* Extracts the variable length integer (see RFC 9000 section 16). */
122 static inline uint64_t
123 get_be_vli(netdissect_options
*ndo
, const u_char
*p
, uint8_t *out_length
)
131 prefix
= (uint8_t)v
>> 6;
132 length
= 1 << prefix
;
133 if (out_length
!= NULL
)
134 *out_length
= length
;
137 v
= (v
<< 8) + GET_U_1(p
);
145 #define GET_BE_VLI(p, l) get_be_vli(ndo, (const u_char *)(p), l)
147 static const u_char
*
148 quic_print_packet(netdissect_options
*ndo
, const u_char
*bp
, const u_char
*end
)
150 uint8_t first_octet
= 0;
151 uint8_t packet_type
= 0;
152 uint32_t version
= 0;
155 uint8_t dcil
= 0; /* DCID length */
156 uint8_t scil
= 0; /* SCID length */
157 uint8_t vli_length
= 0;
158 uint8_t *token
= NULL
;
159 uint64_t token_length
= 0;
161 first_octet
= GET_U_1(bp
);
163 if (first_octet
& 0x80) {
165 packet_type
= (first_octet
>> 4) & 0x03;
166 version
= GET_BE_U_4(bp
);
170 ND_PRINT(", version negotiation");
171 else if (packet_type
== QUIC_LH_TYPE_INITIAL
)
172 ND_PRINT(", initial");
173 else if (packet_type
== QUIC_LH_TYPE_0RTT
)
175 else if (packet_type
== QUIC_LH_TYPE_HANDSHAKE
)
176 ND_PRINT(", handshake");
177 else if (packet_type
== QUIC_LH_TYPE_RETRY
)
179 if (version
!= 0 && version
!= 1)
180 ND_PRINT(", v%x", version
);
183 if (dcil
> 0 && dcil
<= QUIC_MAX_CID_LENGTH
) {
184 memset(dcid
, 0, sizeof(dcid
));
185 GET_CPY_BYTES(&dcid
, bp
, dcil
);
188 hexprint(ndo
, dcid
, dcil
);
189 register_quic_cid(dcid
, dcil
);
193 if (scil
> 0 && scil
<= QUIC_MAX_CID_LENGTH
) {
194 memset(scid
, 0, sizeof(dcid
));
195 GET_CPY_BYTES(&scid
, bp
, scil
);
198 hexprint(ndo
, scid
, scil
);
199 register_quic_cid(scid
, scil
);
202 /* Version Negotiation packet */
204 if (!ND_TTEST_4(bp
)) {
208 uint32_t vn_version
= GET_BE_U_4(bp
);
210 ND_PRINT(", version 0x%x", vn_version
);
214 if (packet_type
== QUIC_LH_TYPE_INITIAL
) {
215 token_length
= GET_BE_VLI(bp
, &vli_length
);
217 if (token_length
> 0 && token_length
< 1000) {
218 token
= nd_malloc(ndo
, (size_t)token_length
);
219 GET_CPY_BYTES(token
, bp
, (size_t)token_length
);
221 ND_PRINT(", token ");
222 hexprint(ndo
, token
, (size_t)token_length
);
225 if (packet_type
== QUIC_LH_TYPE_RETRY
) {
226 ND_PRINT(", token ");
227 if (end
> bp
&& end
- bp
> 16 &&
228 ND_TTEST_LEN(bp
, end
- bp
- 16)) {
229 token_length
= end
- bp
- 16;
230 token
= nd_malloc(ndo
, (size_t)token_length
);
231 GET_CPY_BYTES(token
, bp
, (size_t)token_length
);
233 hexprint(ndo
, token
, (size_t)token_length
);
239 /* Initial/Handshake/0-RTT */
240 uint64_t payload_length
=
241 GET_BE_VLI(bp
, &vli_length
);
243 ND_PRINT(", length %" PRIu64
, payload_length
);
244 if (!ND_TTEST_LEN(bp
, payload_length
)) {
248 bp
+= payload_length
;
253 ND_PRINT(", protected");
254 if (end
> bp
&& end
- bp
> 16 &&
255 ND_TTEST_LEN(bp
, end
- bp
)) {
256 struct quic_cid_array
*cid_array
=
257 lookup_quic_cid(bp
, end
- bp
);
258 if (cid_array
!= NULL
) {
260 hexprint(ndo
, cid_array
->cid
,
273 quic_print(netdissect_options
*ndo
, const u_char
*bp
)
275 const uint8_t *end
= bp
+ ND_BYTES_AVAILABLE_AFTER(bp
);
277 ndo
->ndo_protocol
= "quic";
278 nd_print_protocol(ndo
);
281 bp
= quic_print_packet(ndo
, bp
, end
);
283 * Skip all zero bytes which are
284 * considered padding.
286 while (ND_TTEST_1(bp
) && GET_U_1(bp
) == 0)