summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRui Paulo <rpaulo@apple.com>2021-09-30 18:34:46 -0700
committerFrancois-Xavier Le Bail <devel.fx.lebail@orange.fr>2021-11-09 09:11:34 +0100
commit8ce37b54edb27294047ad059350eada8d17e6909 (patch)
treee4479b661f2a19c96b67fe5487844f92c531a0c8
parent58a4ab67fc75b62968634cddec290c1f2e2c1ded (diff)
downloadtcpdump-8ce37b54edb27294047ad059350eada8d17e6909.tar.gz
Initial support to parse QUIC packets.
-rw-r--r--CMakeLists.txt1
-rw-r--r--Makefile.in1
-rw-r--r--netdissect.h3
-rw-r--r--print-quic.c289
-rw-r--r--print-udp.c6
-rw-r--r--tcpdump.c2
-rw-r--r--tests/TESTLIST6
-rw-r--r--tests/gquic.out2
-rw-r--r--tests/gquic.pcapbin0 -> 1418 bytes
-rw-r--r--tests/quic_handshake.out18
-rw-r--r--tests/quic_handshake.pcapbin0 -> 5802 bytes
-rw-r--r--tests/quic_handshake_truncated.out18
-rw-r--r--tests/quic_handshake_truncated.pcapbin0 -> 2774 bytes
-rw-r--r--tests/quic_vn.out25
-rw-r--r--tests/quic_vn.pcapbin0 -> 10167 bytes
-rw-r--r--udp.h3
16 files changed, 374 insertions, 0 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 8fa04bcf..ce4fe1a2 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1101,6 +1101,7 @@ set(NETDISSECT_SOURCE_LIST_C
print-pppoe.c
print-pptp.c
print-ptp.c
+ print-quic.c
print-radius.c
print-raw.c
print-resp.c
diff --git a/Makefile.in b/Makefile.in
index b5c78ee2..3900e699 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -201,6 +201,7 @@ LIBNETDISSECT_SRC=\
print-pppoe.c \
print-pptp.c \
print-ptp.c \
+ print-quic.c \
print-radius.c \
print-raw.c \
print-resp.c \
diff --git a/netdissect.h b/netdissect.h
index 3eb576f7..53bc842f 100644
--- a/netdissect.h
+++ b/netdissect.h
@@ -291,6 +291,7 @@ extern void nd_pop_all_packet_info(netdissect_options *);
#define PT_PTP 18 /* PTP */
#define PT_SOMEIP 19 /* Autosar SOME/IP Protocol */
#define PT_DOMAIN 20 /* Domain Name System (DNS) */
+#define PT_QUIC 21 /* QUIC */
#define ND_MIN(a,b) ((a)>(b)?(b):(a))
#define ND_MAX(a,b) ((b)>(a)?(b):(a))
@@ -692,6 +693,8 @@ extern int print_unknown_data(netdissect_options *, const u_char *, const char *
extern void ptp_print(netdissect_options *, const u_char *, u_int);
extern const char *q922_string(netdissect_options *, const u_char *, u_int);
extern void q933_print(netdissect_options *, const u_char *, u_int);
+extern int quic_detect(netdissect_options *, const u_char *, const u_int);
+extern void quic_print(netdissect_options *, const u_char *, const u_int);
extern void radius_print(netdissect_options *, const u_char *, u_int);
extern void resp_print(netdissect_options *, const u_char *, u_int);
extern void rip_print(netdissect_options *, const u_char *, u_int);
diff --git a/print-quic.c b/print-quic.c
new file mode 100644
index 00000000..d6963b77
--- /dev/null
+++ b/print-quic.c
@@ -0,0 +1,289 @@
+/*
+ * Copyright (c) 2021 Apple, Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * 3. The names of the authors may not be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+/* \summary: QUIC Protocol printer */
+/* specification: https://www.rfc-editor.org/rfc/rfc9000.txt */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "netdissect-stdinc.h"
+#include "netdissect-alloc.h"
+#include "netdissect.h"
+#include "extract.h"
+
+#define QUIC_MAX_CID_LENGTH 20
+
+typedef uint8_t quic_cid[QUIC_MAX_CID_LENGTH];
+
+struct quic_cid_array {
+ uint8_t cid[QUIC_MAX_CID_LENGTH];
+ uint8_t length;
+};
+
+enum quic_lh_packet_type {
+ QUIC_LH_TYPE_INITIAL = 0,
+ QUIC_LH_TYPE_0RTT = 1,
+ QUIC_LH_TYPE_HANDSHAKE = 2,
+ QUIC_LH_TYPE_RETRY = 3
+};
+
+static void
+hexprint(netdissect_options *ndo, const uint8_t *cp, size_t len)
+{
+ size_t i;
+
+ for (i = 0; i < len; i++)
+ ND_PRINT("%02x", cp[i]);
+}
+
+#define QUIC_CID_LIST_MAX 512
+
+static struct quic_cid_array quic_cid_array[QUIC_CID_LIST_MAX];
+
+static struct quic_cid_array *
+lookup_quic_cid(const u_char *cid, size_t length)
+{
+ for (unsigned int i = 0; i < QUIC_CID_LIST_MAX; i++) {
+ if (quic_cid_array[i].length > length) {
+ continue;
+ }
+ if (quic_cid_array[i].length == 0) {
+ break;
+ }
+ if (memcmp(quic_cid_array[i].cid, cid,
+ quic_cid_array[i].length) == 0) {
+ /*
+ * Swap the entries so that it behaves like an
+ * LRU cache.
+ */
+ if (i != 0) {
+ struct quic_cid_array tmp = quic_cid_array[i];
+ quic_cid_array[i] = quic_cid_array[0];
+ quic_cid_array[0] = tmp;
+ }
+
+ return &quic_cid_array[0];
+ }
+ }
+
+ return NULL;
+}
+
+static void
+register_quic_cid(const quic_cid cid, uint8_t length)
+{
+ static uint16_t next_cid = 0;
+
+ if (length == 0 ||
+ lookup_quic_cid(cid, length) != NULL) {
+ return;
+ }
+ memcpy(&quic_cid_array[next_cid].cid, cid, QUIC_MAX_CID_LENGTH);
+ quic_cid_array[next_cid].length = length;
+ next_cid = (next_cid + 1) % QUIC_CID_LIST_MAX;
+}
+
+/* Returns 1 if the first octet looks like a QUIC packet. */
+int
+quic_detect(netdissect_options *ndo, const u_char *p, const u_int len)
+{
+ uint8_t first_octet;
+
+ if (len < 1)
+ return 0;
+ first_octet = GET_U_1(p);
+ /* All QUIC packets must have the Fixed Bit set to 1. */
+ if ((first_octet & 0x40) == 0x40)
+ return 1;
+ else
+ return 0;
+}
+
+/* Extracts the variable length integer (see RFC 9000 section 16). */
+static inline uint64_t
+get_be_vli(netdissect_options *ndo, const u_char *p, uint8_t *out_length)
+{
+ uint64_t v;
+ uint8_t prefix;
+ uint8_t length;
+
+ v = GET_U_1(p);
+ p++;
+ prefix = (uint8_t)v >> 6;
+ length = 1 << prefix;
+ if (out_length != NULL)
+ *out_length = length;
+ v = v & 0x3f;
+ while (length > 1) {
+ v = (v << 8) + GET_U_1(p);
+ p++;
+ length--;
+ }
+
+ return v;
+}
+
+#define GET_BE_VLI(p, l) get_be_vli(ndo, (const u_char *)(p), l)
+
+static const u_char *
+quic_print_packet(netdissect_options *ndo, const u_char *bp, const u_char *end)
+{
+ uint8_t first_octet = 0;
+ uint8_t packet_type = 0;
+ uint32_t version = 0;
+ quic_cid dcid = {0};
+ quic_cid scid = {0};
+ uint8_t dcil = 0; /* DCID length */
+ uint8_t scil = 0; /* SCID length */
+ uint8_t vli_length = 0;
+ uint8_t *token = NULL;
+ uint64_t token_length = 0;
+
+ first_octet = GET_U_1(bp);
+ bp += 1;
+ if (first_octet & 0x80) {
+ /* Long Header */
+ packet_type = (first_octet >> 4) & 0x02;
+ version = GET_BE_U_4(bp);
+ bp += 4;
+
+ if (version == 0)
+ ND_PRINT(", version negotiation");
+ else if (packet_type == QUIC_LH_TYPE_INITIAL)
+ ND_PRINT(", initial");
+ else if (packet_type == QUIC_LH_TYPE_0RTT)
+ ND_PRINT(", 0-rtt");
+ else if (packet_type == QUIC_LH_TYPE_HANDSHAKE)
+ ND_PRINT(", handshake");
+ else if (packet_type == QUIC_LH_TYPE_RETRY)
+ ND_PRINT(", retry");
+ if (version != 0 && version != 1)
+ ND_PRINT(", v%x", version);
+ dcil = GET_U_1(bp);
+ bp += 1;
+ if (dcil > 0 && dcil <= QUIC_MAX_CID_LENGTH) {
+ memset(dcid, 0, sizeof(dcid));
+ GET_CPY_BYTES(&dcid, bp, dcil);
+ bp += dcil;
+ ND_PRINT(", dcid ");
+ hexprint(ndo, dcid, dcil);
+ register_quic_cid(dcid, dcil);
+ }
+ scil = GET_U_1(bp);
+ bp += 1;
+ if (scil > 0 && scil <= QUIC_MAX_CID_LENGTH) {
+ memset(scid, 0, sizeof(dcid));
+ GET_CPY_BYTES(&scid, bp, scil);
+ bp += scil;
+ ND_PRINT(", scid ");
+ hexprint(ndo, scid, scil);
+ register_quic_cid(scid, scil);
+ }
+ if (version == 0) {
+ /* Version Negotiation packet */
+ while (bp < end) {
+ if (!ND_TTEST_4(bp)) {
+ nd_print_trunc(ndo);
+ bp = end;
+ } else {
+ uint32_t vn_version = GET_BE_U_4(bp);
+ bp += 4;
+ ND_PRINT(", version 0x%x", vn_version);
+ }
+ }
+ } else {
+ if (packet_type == QUIC_LH_TYPE_INITIAL) {
+ token_length = GET_BE_VLI(bp, &vli_length);
+ bp += vli_length;
+ if (token_length > 0 && token_length < 1000) {
+ token = nd_malloc(ndo, (size_t)token_length);
+ GET_CPY_BYTES(token, bp, (size_t)token_length);
+ bp += token_length;
+ ND_PRINT(", token ");
+ hexprint(ndo, token, (size_t)token_length);
+ }
+ }
+ if (packet_type == QUIC_LH_TYPE_RETRY) {
+ ND_PRINT(", token ");
+ if (end > bp && end - bp > 16) {
+ token_length = end - bp - 16;
+ token = nd_malloc(ndo, (size_t)token_length);
+ GET_CPY_BYTES(token, bp, (size_t)token_length);
+ bp += token_length;
+ hexprint(ndo, token, (size_t)token_length);
+ } else {
+ nd_print_trunc(ndo);
+ }
+ bp = end;
+ } else {
+ /* Initial/Handshake/0-RTT */
+ uint64_t payload_length =
+ GET_BE_VLI(bp, &vli_length);
+ bp += vli_length;
+ ND_PRINT(", length %" PRIu64, payload_length);
+ if (!ND_TTEST_LEN(bp, payload_length)) {
+ nd_print_trunc(ndo);
+ bp = end;
+ } else
+ bp += payload_length;
+ }
+ }
+ } else {
+ /* Short Header */
+ ND_PRINT(", protected");
+ if (ND_TTEST_LEN(bp, 16)) {
+ struct quic_cid_array *cid_array =
+ lookup_quic_cid(bp, end - bp);
+ if (cid_array != NULL) {
+ ND_PRINT(", dcid ");
+ hexprint(ndo, cid_array->cid,
+ cid_array->length);
+ }
+ } else {
+ nd_print_trunc(ndo);
+ }
+ bp = end;
+ }
+
+ return bp;
+}
+
+void
+quic_print(netdissect_options *ndo, const u_char *bp, const u_int len)
+{
+ const uint8_t *end = bp + len;
+
+ ndo->ndo_protocol = "quic";
+ nd_print_protocol(ndo);
+
+ while (bp < end) {
+ bp = quic_print_packet(ndo, bp, end);
+ /*
+ * Skip all zero bytes which are
+ * considered padding.
+ */
+ while (ND_TTEST_1(bp) && GET_U_1(bp) == 0)
+ bp++;
+ }
+}
diff --git a/print-udp.c b/print-udp.c
index 4fb0a591..d5891de6 100644
--- a/print-udp.c
+++ b/print-udp.c
@@ -463,6 +463,9 @@ udp_print(netdissect_options *ndo, const u_char *bp, u_int length,
/* over_tcp: FALSE, is_mdns: FALSE */
domain_print(ndo, cp, length, FALSE, FALSE);
break;
+ case PT_QUIC:
+ quic_print(ndo, cp, length);
+ break;
}
return;
}
@@ -669,6 +672,9 @@ udp_print(netdissect_options *ndo, const u_char *bp, u_int length,
ptp_print(ndo, cp, length);
} else if (IS_SRC_OR_DST_PORT(SOMEIP_PORT))
someip_print(ndo, cp, length);
+ else if (IS_SRC_OR_DST_PORT(HTTPS_PORT) &&
+ quic_detect(ndo, cp, length))
+ quic_print(ndo, cp, length);
else {
if (ulen > length && !fragmented)
ND_PRINT("UDP, bad length %u > %u",
diff --git a/tcpdump.c b/tcpdump.c
index bac890f0..a4403370 100644
--- a/tcpdump.c
+++ b/tcpdump.c
@@ -1864,6 +1864,8 @@ main(int argc, char **argv)
ndo->ndo_packettype = PT_SOMEIP;
else if (ascii_strcasecmp(optarg, "domain") == 0)
ndo->ndo_packettype = PT_DOMAIN;
+ else if (ascii_strcasecmp(optarg, "quic") == 0)
+ ndo->ndo_packettype = PT_QUIC;
else
error("unknown packet type `%s'", optarg);
break;
diff --git a/tests/TESTLIST b/tests/TESTLIST
index 085985e7..8a8542c1 100644
--- a/tests/TESTLIST
+++ b/tests/TESTLIST
@@ -885,3 +885,9 @@ lsp-ping-timestamp lsp-ping-timestamp.pcap lsp-ping-timestamp.out -vv
# lwres with "extra" bytes
lwres_with_extra lwres_with_extra.pcap lwres_with_extra.out
+
+# QUIC tests
+quic_vn quic_vn.pcap quic_vn.out -v
+quic_handshake quic_handshake.pcap quic_handshake.out -v
+quic_handshake_truncated quic_handshake_truncated.pcap quic_handshake_truncated.out -v
+gquic gquic.pcap gquic.out -v
diff --git a/tests/gquic.out b/tests/gquic.out
new file mode 100644
index 00000000..9f2708fe
--- /dev/null
+++ b/tests/gquic.out
@@ -0,0 +1,2 @@
+ 1 06:42:38.000000 IP (tos 0x0, ttl 64, id 38137, offset 0, flags [DF], proto UDP (17), length 1378)
+ 10.7.0.3.38824 > 216.58.195.67.443: quic, initial, v51303436, length 0, protected
diff --git a/tests/gquic.pcap b/tests/gquic.pcap
new file mode 100644
index 00000000..54bdcad1
--- /dev/null
+++ b/tests/gquic.pcap
Binary files differ
diff --git a/tests/quic_handshake.out b/tests/quic_handshake.out
new file mode 100644
index 00000000..1059855c
--- /dev/null
+++ b/tests/quic_handshake.out
@@ -0,0 +1,18 @@
+ 1 19:55:22.974137 IP6 (flowlabel 0xa0f00, hlim 64, next-header UDP (17) payload length: 1208) ::1.50606 > ::1.443: [bad udp cksum 0x04cb -> 0x88c5!] quic, initial, dcid 84acac06b42ed863, length 1182
+ 2 19:55:22.986150 IP6 (flowlabel 0x50400, hlim 64, next-header UDP (17) payload length: 142) ::1.443 > ::1.50606: [bad udp cksum 0x00a1 -> 0x4011!] quic, initial, scid 51d1e44dc57a579e, length 116
+ 3 19:55:22.986194 IP6 (class 0x02, flowlabel 0x50400, hlim 64, next-header UDP (17) payload length: 1205) ::1.443 > ::1.50606: [bad udp cksum 0x04c8 -> 0x7bc8!] quic, handshake, scid 51d1e44dc57a579e, length 1180
+ 4 19:55:22.986207 IP6 (class 0x02, flowlabel 0x50400, hlim 64, next-header UDP (17) payload length: 127) ::1.443 > ::1.50606: [bad udp cksum 0x0092 -> 0x195c!] quic, handshake, scid 51d1e44dc57a579e, length 102
+ 5 19:55:22.993319 IP6 (flowlabel 0xa0f00, hlim 64, next-header UDP (17) payload length: 1208) ::1.50606 > ::1.443: [bad udp cksum 0x04cb -> 0x166a!] quic, initial, dcid 51d1e44dc57a579e, length 1182
+ 6 19:55:22.993381 IP6 (class 0x02, flowlabel 0xa0f00, hlim 64, next-header UDP (17) payload length: 47) ::1.50606 > ::1.443: [bad udp cksum 0x0042 -> 0x9e10!] quic, handshake, dcid 51d1e44dc57a579e, length 22
+ 7 19:55:22.993883 IP6 (class 0x02, flowlabel 0xa0f00, hlim 64, next-header UDP (17) payload length: 81) ::1.50606 > ::1.443: [bad udp cksum 0x0064 -> 0xb505!] quic, handshake, dcid 51d1e44dc57a579e, length 56
+ 8 19:55:22.994315 IP6 (class 0x02, flowlabel 0x50400, hlim 64, next-header UDP (17) payload length: 50) ::1.443 > ::1.50606: [bad udp cksum 0x0045 -> 0x174b!] quic, handshake, scid 51d1e44dc57a579e, length 25
+ 9 19:55:22.994422 IP6 (class 0x02, flowlabel 0x50400, hlim 64, next-header UDP (17) payload length: 29) ::1.443 > ::1.50606: [bad udp cksum 0x0030 -> 0x028d!] quic, protected
+ 10 19:55:22.994681 IP6 (class 0x02, flowlabel 0x50400, hlim 64, next-header UDP (17) payload length: 250) ::1.443 > ::1.50606: [bad udp cksum 0x010d -> 0xd406!] quic, protected
+ 11 19:55:22.995595 IP6 (class 0x02, flowlabel 0xa0f00, hlim 64, next-header UDP (17) payload length: 42) ::1.50606 > ::1.443: [bad udp cksum 0x003d -> 0xd43e!] quic, protected, dcid 51d1e44dc57a579e
+ 12 19:55:22.995673 IP6 (class 0x02, flowlabel 0xa0f00, hlim 64, next-header UDP (17) payload length: 37) ::1.50606 > ::1.443: [bad udp cksum 0x0038 -> 0x45ed!] quic, protected, dcid 51d1e44dc57a579e
+ 13 19:55:22.995717 IP6 (class 0x02, flowlabel 0x50400, hlim 64, next-header UDP (17) payload length: 34) ::1.443 > ::1.50606: [bad udp cksum 0x0035 -> 0xc655!] quic, protected
+ 14 19:55:22.995871 IP6 (class 0x02, flowlabel 0xa0f00, hlim 64, next-header UDP (17) payload length: 44) ::1.50606 > ::1.443: [bad udp cksum 0x003f -> 0xa02d!] quic, protected, dcid 51d1e44dc57a579e
+ 15 19:55:22.996769 IP6 (class 0x02, flowlabel 0x50400, hlim 64, next-header UDP (17) payload length: 87) ::1.443 > ::1.50606: [bad udp cksum 0x006a -> 0xf83f!] quic, protected
+ 16 19:55:22.996914 IP6 (class 0x02, flowlabel 0x50400, hlim 64, next-header UDP (17) payload length: 29) ::1.443 > ::1.50606: [bad udp cksum 0x0030 -> 0x9c19!] quic, protected
+ 17 19:55:22.997174 IP6 (class 0x02, flowlabel 0xa0f00, hlim 64, next-header UDP (17) payload length: 39) ::1.50606 > ::1.443: [bad udp cksum 0x003a -> 0x34f5!] quic, protected, dcid 51d1e44dc57a579e
+ 18 19:55:23.022890 IP6 (class 0x02, flowlabel 0xa0f00, hlim 64, next-header UDP (17) payload length: 39) ::1.50606 > ::1.443: [bad udp cksum 0x003a -> 0xef78!] quic, protected, dcid 51d1e44dc57a579e
diff --git a/tests/quic_handshake.pcap b/tests/quic_handshake.pcap
new file mode 100644
index 00000000..56ee4289
--- /dev/null
+++ b/tests/quic_handshake.pcap
Binary files differ
diff --git a/tests/quic_handshake_truncated.out b/tests/quic_handshake_truncated.out
new file mode 100644
index 00000000..909b6191
--- /dev/null
+++ b/tests/quic_handshake_truncated.out
@@ -0,0 +1,18 @@
+ 1 19:57:02.464273 IP6 (flowlabel 0x70e00, hlim 64, next-header UDP (17) payload length: 1208) ::1.65165 > ::1.443: quic, initial, dcid f71ae16671baa8b7, length 1182 [|quic]
+ 2 19:57:02.477244 IP6 (flowlabel 0x50700, hlim 64, next-header UDP (17) payload length: 142) ::1.443 > ::1.65165: [bad udp cksum 0x00a1 -> 0x1f62!] quic, initial, scid beb256567ee5698c, length 116
+ 3 19:57:02.477289 IP6 (class 0x02, flowlabel 0x50700, hlim 64, next-header UDP (17) payload length: 1205) ::1.443 > ::1.65165: quic, handshake, scid beb256567ee5698c, length 1180 [|quic]
+ 4 19:57:02.477305 IP6 (class 0x02, flowlabel 0x50700, hlim 64, next-header UDP (17) payload length: 127) ::1.443 > ::1.65165: [bad udp cksum 0x0092 -> 0x912a!] quic, handshake, scid beb256567ee5698c, length 102
+ 5 19:57:02.485020 IP6 (flowlabel 0x70e00, hlim 64, next-header UDP (17) payload length: 1208) ::1.65165 > ::1.443: quic, initial, dcid beb256567ee5698c, length 1182 [|quic]
+ 6 19:57:02.485088 IP6 (class 0x02, flowlabel 0x70e00, hlim 64, next-header UDP (17) payload length: 47) ::1.65165 > ::1.443: [bad udp cksum 0x0042 -> 0x0519!] quic, handshake, dcid beb256567ee5698c, length 22
+ 7 19:57:02.485464 IP6 (class 0x02, flowlabel 0x70e00, hlim 64, next-header UDP (17) payload length: 81) ::1.65165 > ::1.443: [bad udp cksum 0x0064 -> 0x9855!] quic, handshake, dcid beb256567ee5698c, length 56
+ 8 19:57:02.485711 IP6 (class 0x02, flowlabel 0x50700, hlim 64, next-header UDP (17) payload length: 50) ::1.443 > ::1.65165: [bad udp cksum 0x0045 -> 0xca20!] quic, handshake, scid beb256567ee5698c, length 25
+ 9 19:57:02.485809 IP6 (class 0x02, flowlabel 0x50700, hlim 64, next-header UDP (17) payload length: 29) ::1.443 > ::1.65165: [bad udp cksum 0x0030 -> 0x4f93!] quic, protected
+ 10 19:57:02.486075 IP6 (class 0x02, flowlabel 0x50700, hlim 64, next-header UDP (17) payload length: 250) ::1.443 > ::1.65165: quic, protected
+ 11 19:57:02.486726 IP6 (class 0x02, flowlabel 0x70e00, hlim 64, next-header UDP (17) payload length: 39) ::1.65165 > ::1.443: [bad udp cksum 0x003a -> 0x38d3!] quic, protected, dcid beb256567ee5698c
+ 12 19:57:02.487067 IP6 (class 0x02, flowlabel 0x70e00, hlim 64, next-header UDP (17) payload length: 37) ::1.65165 > ::1.443: [bad udp cksum 0x0038 -> 0x3993!] quic, protected, dcid beb256567ee5698c
+ 13 19:57:02.487144 IP6 (class 0x02, flowlabel 0x70e00, hlim 64, next-header UDP (17) payload length: 37) ::1.65165 > ::1.443: [bad udp cksum 0x0038 -> 0x7ae0!] quic, protected, dcid beb256567ee5698c
+ 14 19:57:02.487236 IP6 (class 0x02, flowlabel 0x50700, hlim 64, next-header UDP (17) payload length: 34) ::1.443 > ::1.65165: [bad udp cksum 0x0035 -> 0x08ea!] quic, protected
+ 15 19:57:02.487484 IP6 (class 0x02, flowlabel 0x70e00, hlim 64, next-header UDP (17) payload length: 44) ::1.65165 > ::1.443: [bad udp cksum 0x003f -> 0xb09b!] quic, protected, dcid beb256567ee5698c
+ 16 19:57:02.488209 IP6 (class 0x02, flowlabel 0x50700, hlim 64, next-header UDP (17) payload length: 87) ::1.443 > ::1.65165: [bad udp cksum 0x006a -> 0xd85a!] quic, protected
+ 17 19:57:02.488303 IP6 (class 0x02, flowlabel 0x50700, hlim 64, next-header UDP (17) payload length: 29) ::1.443 > ::1.65165: [bad udp cksum 0x0030 -> 0xca53!] quic, protected
+ 18 19:57:02.489327 IP6 (class 0x02, flowlabel 0x70e00, hlim 64, next-header UDP (17) payload length: 39) ::1.65165 > ::1.443: [bad udp cksum 0x003a -> 0x12d6!] quic, protected, dcid beb256567ee5698c
diff --git a/tests/quic_handshake_truncated.pcap b/tests/quic_handshake_truncated.pcap
new file mode 100644
index 00000000..ee5a5775
--- /dev/null
+++ b/tests/quic_handshake_truncated.pcap
Binary files differ
diff --git a/tests/quic_vn.out b/tests/quic_vn.out
new file mode 100644
index 00000000..802d1ff2
--- /dev/null
+++ b/tests/quic_vn.out
@@ -0,0 +1,25 @@
+ 1 19:58:43.195985 IP6 (flowlabel 0x60e00, hlim 64, next-header UDP (17) payload length: 1208) ::1.57406 > ::1.443: [bad udp cksum 0x04cb -> 0x9841!] quic, initial, v1a2a3a4a, dcid 9d5728481287a3b4, length 1182
+ 2 19:58:43.197540 IP6 (flowlabel 0x00e00, hlim 64, next-header UDP (17) payload length: 31) ::1.443 > ::1.57406: [bad udp cksum 0x0032 -> 0xcfe3!] quic, version negotiation, scid 9d5728481287a3b4, version 0x1, version 0x1a2a3a4a
+ 3 19:58:43.198343 IP6 (flowlabel 0x60e00, hlim 64, next-header UDP (17) payload length: 1208) ::1.57406 > ::1.443: [bad udp cksum 0x04cb -> 0x00e3!] quic, initial, dcid 9d5728481287a3b4, length 1182
+ 4 19:58:43.209491 IP6 (flowlabel 0x00e00, hlim 64, next-header UDP (17) payload length: 142) ::1.443 > ::1.57406: [bad udp cksum 0x00a1 -> 0xe0dc!] quic, initial, scid 0c3c2e287ccdc535, length 116
+ 5 19:58:43.209543 IP6 (class 0x02, flowlabel 0x00e00, hlim 64, next-header UDP (17) payload length: 1205) ::1.443 > ::1.57406: [bad udp cksum 0x04c8 -> 0x3f59!] quic, handshake, scid 0c3c2e287ccdc535, length 1180
+ 6 19:58:43.209561 IP6 (class 0x02, flowlabel 0x00e00, hlim 64, next-header UDP (17) payload length: 127) ::1.443 > ::1.57406: [bad udp cksum 0x0092 -> 0xfe4e!] quic, handshake, scid 0c3c2e287ccdc535, length 102
+ 7 19:58:43.210228 IP6 (flowlabel 0x60e00, hlim 64, next-header UDP (17) payload length: 1208) ::1.57406 > ::1.443: [bad udp cksum 0x04cb -> 0x0be5!] quic, initial, dcid 0c3c2e287ccdc535, length 1182
+ 8 19:58:43.211686 IP6 (class 0x02, flowlabel 0x00e00, hlim 64, next-header UDP (17) payload length: 1205) ::1.443 > ::1.57406: [bad udp cksum 0x04c8 -> 0x38d0!] quic, handshake, scid 0c3c2e287ccdc535, length 1180
+ 9 19:58:43.211707 IP6 (class 0x02, flowlabel 0x00e00, hlim 64, next-header UDP (17) payload length: 127) ::1.443 > ::1.57406: [bad udp cksum 0x0092 -> 0x6a3b!] quic, handshake, scid 0c3c2e287ccdc535, length 102
+ 10 19:58:43.215352 IP6 (class 0x02, flowlabel 0x00e00, hlim 64, next-header UDP (17) payload length: 1205) ::1.443 > ::1.57406: [bad udp cksum 0x04c8 -> 0xd8ff!] quic, handshake, scid 0c3c2e287ccdc535, length 1180
+ 11 19:58:43.215372 IP6 (class 0x02, flowlabel 0x00e00, hlim 64, next-header UDP (17) payload length: 127) ::1.443 > ::1.57406: [bad udp cksum 0x0092 -> 0xb975!] quic, handshake, scid 0c3c2e287ccdc535, length 102
+ 12 19:58:43.218021 IP6 (class 0x02, flowlabel 0x60e00, hlim 64, next-header UDP (17) payload length: 47) ::1.57406 > ::1.443: [bad udp cksum 0x0042 -> 0x25c0!] quic, handshake, dcid 0c3c2e287ccdc535, length 22
+ 13 19:58:43.218451 IP6 (class 0x02, flowlabel 0x60e00, hlim 64, next-header UDP (17) payload length: 81) ::1.57406 > ::1.443: [bad udp cksum 0x0064 -> 0x7e36!] quic, handshake, dcid 0c3c2e287ccdc535, length 56
+ 14 19:58:43.218672 IP6 (class 0x02, flowlabel 0x00e00, hlim 64, next-header UDP (17) payload length: 50) ::1.443 > ::1.57406: [bad udp cksum 0x0045 -> 0x8994!] quic, handshake, scid 0c3c2e287ccdc535, length 25
+ 15 19:58:43.218736 IP6 (class 0x02, flowlabel 0x00e00, hlim 64, next-header UDP (17) payload length: 29) ::1.443 > ::1.57406: [bad udp cksum 0x0030 -> 0xb0c3!] quic, protected
+ 16 19:58:43.218901 IP6 (class 0x02, flowlabel 0x00e00, hlim 64, next-header UDP (17) payload length: 250) ::1.443 > ::1.57406: [bad udp cksum 0x010d -> 0xb0e1!] quic, protected
+ 17 19:58:43.219325 IP6 (class 0x02, flowlabel 0x60e00, hlim 64, next-header UDP (17) payload length: 47) ::1.57406 > ::1.443: [bad udp cksum 0x0042 -> 0xd3d9!] quic, handshake, dcid 0c3c2e287ccdc535, length 22
+ 18 19:58:43.219731 IP6 (class 0x02, flowlabel 0x60e00, hlim 64, next-header UDP (17) payload length: 39) ::1.57406 > ::1.443: [bad udp cksum 0x003a -> 0x2311!] quic, protected, dcid 0c3c2e287ccdc535
+ 19 19:58:43.219941 IP6 (class 0x02, flowlabel 0x60e00, hlim 64, next-header UDP (17) payload length: 37) ::1.57406 > ::1.443: [bad udp cksum 0x0038 -> 0x9c23!] quic, protected, dcid 0c3c2e287ccdc535
+ 20 19:58:43.220031 IP6 (class 0x02, flowlabel 0x60e00, hlim 64, next-header UDP (17) payload length: 37) ::1.57406 > ::1.443: [bad udp cksum 0x0038 -> 0x34fe!] quic, protected, dcid 0c3c2e287ccdc535
+ 21 19:58:43.220140 IP6 (class 0x02, flowlabel 0x00e00, hlim 64, next-header UDP (17) payload length: 34) ::1.443 > ::1.57406: [bad udp cksum 0x0035 -> 0xaf64!] quic, protected
+ 22 19:58:43.220191 IP6 (class 0x02, flowlabel 0x60e00, hlim 64, next-header UDP (17) payload length: 44) ::1.57406 > ::1.443: [bad udp cksum 0x003f -> 0xaa1b!] quic, protected, dcid 0c3c2e287ccdc535
+ 23 19:58:43.220999 IP6 (flowlabel 0x00e00, hlim 64, next-header UDP (17) payload length: 87) ::1.443 > ::1.57406: [bad udp cksum 0x006a -> 0x5b11!] quic, protected
+ 24 19:58:43.221067 IP6 (flowlabel 0x00e00, hlim 64, next-header UDP (17) payload length: 29) ::1.443 > ::1.57406: [bad udp cksum 0x0030 -> 0x7382!] quic, protected
+ 25 19:58:43.221638 IP6 (class 0x02, flowlabel 0x60e00, hlim 64, next-header UDP (17) payload length: 39) ::1.57406 > ::1.443: [bad udp cksum 0x003a -> 0x00cc!] quic, protected, dcid 0c3c2e287ccdc535
diff --git a/tests/quic_vn.pcap b/tests/quic_vn.pcap
new file mode 100644
index 00000000..5487c23c
--- /dev/null
+++ b/tests/quic_vn.pcap
Binary files differ
diff --git a/udp.h b/udp.h
index 1eb844ab..4f6fa380 100644
--- a/udp.h
+++ b/udp.h
@@ -251,3 +251,6 @@ struct udphdr {
#ifndef SOMEIP_PORT
#define SOMEIP_PORT 30490 /* https://www.autosar.org/standards/foundation */
#endif
+#ifndef HTTPS_PORT
+#define HTTPS_PORT 443
+#endif