From 26c68db182ab50d4710e0b85f7c24faf49da1fca Mon Sep 17 00:00:00 2001 From: Nick Banks Date: Thu, 8 Jun 2023 10:42:17 -0400 Subject: [PATCH 01/10] Add Prototype Pseudocode --- include/qeo_ndis.h | 57 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) diff --git a/include/qeo_ndis.h b/include/qeo_ndis.h index e7b162c..d8a9dff 100644 --- a/include/qeo_ndis.h +++ b/include/qeo_ndis.h @@ -76,3 +76,60 @@ typedef struct _NDIS_QUIC_CONNECTION { UINT8 PayloadIv[12]; NDIS_STATUS Status; // The result of trying to offload this connection. } NDIS_QUIC_CONNECTION; + +/* + TODO - Eventually remove this once prototyping is complete. + + The follow outlines some psuedocode for how to implement the logic for a + prototype QEO solution. + +struct offload_info { + int operation; + int direction; + int next_packet_number; + addr ip_address; + byte cid[]; + key_info key; +} + +offload_info[] rx_offload_table; +offload_info[] tx_offload_table; + +int rx_cid_length = -1; +int tx_cid_length = -1; + +void update_offload(offload_info offloads[]) { + foreach (auto offload in offloads) { + if (offload.operation == "add") { + if (offload.direction == "tx") { + if (tx_cid_length == -1) tx_cid_length = offload.cid.length; + } else { + if (rx_cid_length == -1) rx_cid_length = offload.cid.length; + } + } else { + if (offload.direction == "tx") { + tx_offload_table.remove(offload); + } else { + rx_offload_table.remove(offload); + } + } + } +} + +void on_packet_tx(packet packet) { + if (packet.udp_payload[0] == "long header") return; + byte[] cid = packet.udp_payload[1 .. tx_cid_length+1]; + byte packet_number = packet.udp_payload[tx_cid_length+2 .. tx_cid_length+6]; // 4 bytes + offload_info offload = tx_offload_table.find(packet.ip_address, cid); + encrypt_quic_packet(packet, offload, packet_number) +} + +void on_packet_rx(packet packet) { + if (packet.udp_payload[0] == "long header") return; + byte[] cid = packet.udp_payload[1 .. rx_cid_length+1]; + byte packet_number = packet.udp_payload[rx_cid_length+2 .. rx_cid_length+6]; // 4 bytes + offload_info offload = rx_offload_table.find(packet.ip_address, cid); + decrypt_quic_packet(packet, offload, packet_number) +} + +*/ From 47bbc191f5e22d0f15bdb9eaac983a0e0166ac52 Mon Sep 17 00:00:00 2001 From: Nick Banks Date: Thu, 8 Jun 2023 11:29:50 -0400 Subject: [PATCH 02/10] Move to markdown --- include/psuedocode.md | 52 +++++++++++++++++++++++++++++++++++++++ include/qeo_ndis.h | 57 ------------------------------------------- 2 files changed, 52 insertions(+), 57 deletions(-) create mode 100644 include/psuedocode.md diff --git a/include/psuedocode.md b/include/psuedocode.md new file mode 100644 index 0000000..32bee95 --- /dev/null +++ b/include/psuedocode.md @@ -0,0 +1,52 @@ +The follow outlines some psuedocode for how to implement the logic for a prototype QEO solution. + +``` +struct offload_info { + int operation; + int direction; + int next_packet_number; + addr ip_address; + byte cid[]; + key_info key; +} + +offload_info[] rx_offload_table; +offload_info[] tx_offload_table; + +int rx_cid_length = -1; +int tx_cid_length = -1; + +void update_offload(offload_info offloads[]) { + foreach (auto offload in offloads) { + if (offload.operation == "add") { + if (offload.direction == "tx") { + if (tx_cid_length == -1) tx_cid_length = offload.cid.length; + } else { + if (rx_cid_length == -1) rx_cid_length = offload.cid.length; + } + } else { + if (offload.direction == "tx") { + tx_offload_table.remove(offload); + } else { + rx_offload_table.remove(offload); + } + } + } +} + +void on_packet_tx(packet packet) { + if (packet.udp_payload[0] == "long header") return; + byte[] cid = packet.udp_payload[1 .. tx_cid_length+1]; + byte packet_number = packet.udp_payload[tx_cid_length+2 .. tx_cid_length+6]; // 4 bytes + offload_info offload = tx_offload_table.find(packet.ip_address, cid); + encrypt_quic_packet(packet, offload, packet_number) +} + +void on_packet_rx(packet packet) { + if (packet.udp_payload[0] == "long header") return; + byte[] cid = packet.udp_payload[1 .. rx_cid_length+1]; + byte packet_number = packet.udp_payload[rx_cid_length+2 .. rx_cid_length+6]; // 4 bytes + offload_info offload = rx_offload_table.find(packet.ip_address, cid); + decrypt_quic_packet(packet, offload, packet_number) +} +``` diff --git a/include/qeo_ndis.h b/include/qeo_ndis.h index d8a9dff..e7b162c 100644 --- a/include/qeo_ndis.h +++ b/include/qeo_ndis.h @@ -76,60 +76,3 @@ typedef struct _NDIS_QUIC_CONNECTION { UINT8 PayloadIv[12]; NDIS_STATUS Status; // The result of trying to offload this connection. } NDIS_QUIC_CONNECTION; - -/* - TODO - Eventually remove this once prototyping is complete. - - The follow outlines some psuedocode for how to implement the logic for a - prototype QEO solution. - -struct offload_info { - int operation; - int direction; - int next_packet_number; - addr ip_address; - byte cid[]; - key_info key; -} - -offload_info[] rx_offload_table; -offload_info[] tx_offload_table; - -int rx_cid_length = -1; -int tx_cid_length = -1; - -void update_offload(offload_info offloads[]) { - foreach (auto offload in offloads) { - if (offload.operation == "add") { - if (offload.direction == "tx") { - if (tx_cid_length == -1) tx_cid_length = offload.cid.length; - } else { - if (rx_cid_length == -1) rx_cid_length = offload.cid.length; - } - } else { - if (offload.direction == "tx") { - tx_offload_table.remove(offload); - } else { - rx_offload_table.remove(offload); - } - } - } -} - -void on_packet_tx(packet packet) { - if (packet.udp_payload[0] == "long header") return; - byte[] cid = packet.udp_payload[1 .. tx_cid_length+1]; - byte packet_number = packet.udp_payload[tx_cid_length+2 .. tx_cid_length+6]; // 4 bytes - offload_info offload = tx_offload_table.find(packet.ip_address, cid); - encrypt_quic_packet(packet, offload, packet_number) -} - -void on_packet_rx(packet packet) { - if (packet.udp_payload[0] == "long header") return; - byte[] cid = packet.udp_payload[1 .. rx_cid_length+1]; - byte packet_number = packet.udp_payload[rx_cid_length+2 .. rx_cid_length+6]; // 4 bytes - offload_info offload = rx_offload_table.find(packet.ip_address, cid); - decrypt_quic_packet(packet, offload, packet_number) -} - -*/ From 94679edcbba9e8e9175313c277f3eca428afb60b Mon Sep 17 00:00:00 2001 From: Nick Banks Date: Thu, 8 Jun 2023 11:32:39 -0400 Subject: [PATCH 03/10] Add to the table --- include/psuedocode.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/include/psuedocode.md b/include/psuedocode.md index 32bee95..0da8b2a 100644 --- a/include/psuedocode.md +++ b/include/psuedocode.md @@ -21,8 +21,10 @@ void update_offload(offload_info offloads[]) { if (offload.operation == "add") { if (offload.direction == "tx") { if (tx_cid_length == -1) tx_cid_length = offload.cid.length; + tx_offload_table.add_or_update(offload); } else { if (rx_cid_length == -1) rx_cid_length = offload.cid.length; + rx_offload_table.add_or_update(offload); } } else { if (offload.direction == "tx") { From d82c9ed40d5f9075478337e3722261e709d2d7b6 Mon Sep 17 00:00:00 2001 From: Nick Banks Date: Thu, 8 Jun 2023 11:34:49 -0400 Subject: [PATCH 04/10] better type for packet number --- include/psuedocode.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/include/psuedocode.md b/include/psuedocode.md index 0da8b2a..9a33abf 100644 --- a/include/psuedocode.md +++ b/include/psuedocode.md @@ -2,9 +2,9 @@ The follow outlines some psuedocode for how to implement the logic for a prototy ``` struct offload_info { - int operation; - int direction; - int next_packet_number; + uint operation; + uint direction; + uint next_packet_number; addr ip_address; byte cid[]; key_info key; @@ -39,7 +39,7 @@ void update_offload(offload_info offloads[]) { void on_packet_tx(packet packet) { if (packet.udp_payload[0] == "long header") return; byte[] cid = packet.udp_payload[1 .. tx_cid_length+1]; - byte packet_number = packet.udp_payload[tx_cid_length+2 .. tx_cid_length+6]; // 4 bytes + uint packet_number = packet.udp_payload[tx_cid_length+2 .. tx_cid_length+6]; // 4 bytes offload_info offload = tx_offload_table.find(packet.ip_address, cid); encrypt_quic_packet(packet, offload, packet_number) } @@ -47,7 +47,7 @@ void on_packet_tx(packet packet) { void on_packet_rx(packet packet) { if (packet.udp_payload[0] == "long header") return; byte[] cid = packet.udp_payload[1 .. rx_cid_length+1]; - byte packet_number = packet.udp_payload[rx_cid_length+2 .. rx_cid_length+6]; // 4 bytes + uint packet_number = packet.udp_payload[rx_cid_length+2 .. rx_cid_length+6]; // 4 bytes offload_info offload = rx_offload_table.find(packet.ip_address, cid); decrypt_quic_packet(packet, offload, packet_number) } From b39aad0393d2d256e19c523cf7445637f45d55a2 Mon Sep 17 00:00:00 2001 From: Nick Banks Date: Thu, 8 Jun 2023 11:39:10 -0400 Subject: [PATCH 05/10] comments --- include/psuedocode.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/include/psuedocode.md b/include/psuedocode.md index 9a33abf..59919b1 100644 --- a/include/psuedocode.md +++ b/include/psuedocode.md @@ -38,16 +38,16 @@ void update_offload(offload_info offloads[]) { void on_packet_tx(packet packet) { if (packet.udp_payload[0] == "long header") return; - byte[] cid = packet.udp_payload[1 .. tx_cid_length+1]; - uint packet_number = packet.udp_payload[tx_cid_length+2 .. tx_cid_length+6]; // 4 bytes + byte[] cid = packet.udp_payload[1 .. tx_cid_length]; // tx_cid_length bytes after the first byte + uint packet_number = packet.udp_payload[tx_cid_length+1 .. tx_cid_length+4]; // 4 bytes after the CID offload_info offload = tx_offload_table.find(packet.ip_address, cid); encrypt_quic_packet(packet, offload, packet_number) } void on_packet_rx(packet packet) { if (packet.udp_payload[0] == "long header") return; - byte[] cid = packet.udp_payload[1 .. rx_cid_length+1]; - uint packet_number = packet.udp_payload[rx_cid_length+2 .. rx_cid_length+6]; // 4 bytes + byte[] cid = packet.udp_payload[1 .. rx_cid_length]; // tx_cid_length bytes after the first byte + uint packet_number = packet.udp_payload[rx_cid_length+1 .. rx_cid_length+4]; // 4 bytes after the CID offload_info offload = rx_offload_table.find(packet.ip_address, cid); decrypt_quic_packet(packet, offload, packet_number) } From a6362d4fb3b31e4c18a9906caf03888ec98c3fb8 Mon Sep 17 00:00:00 2001 From: Nick Banks Date: Thu, 8 Jun 2023 11:39:20 -0400 Subject: [PATCH 06/10] typo --- include/psuedocode.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/psuedocode.md b/include/psuedocode.md index 59919b1..5351ded 100644 --- a/include/psuedocode.md +++ b/include/psuedocode.md @@ -46,7 +46,7 @@ void on_packet_tx(packet packet) { void on_packet_rx(packet packet) { if (packet.udp_payload[0] == "long header") return; - byte[] cid = packet.udp_payload[1 .. rx_cid_length]; // tx_cid_length bytes after the first byte + byte[] cid = packet.udp_payload[1 .. rx_cid_length]; // rx_cid_length bytes after the first byte uint packet_number = packet.udp_payload[rx_cid_length+1 .. rx_cid_length+4]; // 4 bytes after the CID offload_info offload = rx_offload_table.find(packet.ip_address, cid); decrypt_quic_packet(packet, offload, packet_number) From e52dfdd01a45489d7295b68825da991c2d0807f7 Mon Sep 17 00:00:00 2001 From: Nick Banks Date: Thu, 8 Jun 2023 11:51:09 -0400 Subject: [PATCH 07/10] Add more detail/comments --- include/psuedocode.md | 79 ++++++++++++++++++++++++++++++++++++++----- 1 file changed, 70 insertions(+), 9 deletions(-) diff --git a/include/psuedocode.md b/include/psuedocode.md index 5351ded..b834600 100644 --- a/include/psuedocode.md +++ b/include/psuedocode.md @@ -4,7 +4,7 @@ The follow outlines some psuedocode for how to implement the logic for a prototy struct offload_info { uint operation; uint direction; - uint next_packet_number; + ulong next_packet_number; addr ip_address; byte cid[]; key_info key; @@ -36,19 +36,80 @@ void update_offload(offload_info offloads[]) { } } +// Based on https://github.com/microsoft/msquic/blob/main/src/core/packet.h#L372 +void decompress_packet_number(ulong expected_packet_number, int compressed_packet_number) { + ulong Mask = 0xFFFFFFFF00000000; + ulong PacketNumberInc = (~Mask) + 1; + ulong PacketNumber = (Mask & expected_packet_number) | compressed_packet_number; + if (PacketNumber < expected_packet_number) { + ulong High = expected_packet_number - PacketNumber; + ulong Low = PacketNumberInc - High; + if (Low < High) { + PacketNumber += PacketNumberInc; + } + + } else { + ulong Low = PacketNumber - expected_packet_number; + ulong High = PacketNumberInc - Low; + if (High <= Low && PacketNumber >= PacketNumberInc) { + PacketNumber -= PacketNumberInc; + } + } + return PacketNumber; +} + +void encrypt_quic_packet(packet packet, offload_info offload) { + // Decompress the full packet number + ulong packet_number = + decompress_packet_number( + offload.next_packet_number, + packet.udp_payload[tx_cid_length+1 .. tx_cid_length+4]); // 4 bytes after the CID + + // Update the next full packet number for the next TX/encrypt call + offload.next_packet_number = packet_number + 1; + + // TODO - Encrypt the packet payload + // TODO - Encrypt the packet header +} + void on_packet_tx(packet packet) { if (packet.udp_payload[0] == "long header") return; - byte[] cid = packet.udp_payload[1 .. tx_cid_length]; // tx_cid_length bytes after the first byte - uint packet_number = packet.udp_payload[tx_cid_length+1 .. tx_cid_length+4]; // 4 bytes after the CID - offload_info offload = tx_offload_table.find(packet.ip_address, cid); - encrypt_quic_packet(packet, offload, packet_number) + + // Find the offload info based on the destination IP:port and CID. + offload_info offload = + rx_offload_table.find( + packet.dest_ip_address, + packet.udp_payload[1 .. tx_cid_length]); // tx_cid_length bytes after the first byte + + encrypt_quic_packet(packet, offload); +} + +void decrypt_quic_packet(packet packet, offload_info offload) { + // TODO - Decrypt packet header + + // Decompress the full packet number + ulong packet_number = + decompress_packet_number( + offload.next_packet_number, + packet.udp_payload[rx_cid_length+1 .. rx_cid_length+4]); // 4 bytes after the CID + + // Update the next full packet number for the next RX/decrypt call + if (packet_number >= offload.next_packet_number) { + offload.next_packet_number = packet_number + 1; + } + + // TODO - Decrypt packet payload } void on_packet_rx(packet packet) { if (packet.udp_payload[0] == "long header") return; - byte[] cid = packet.udp_payload[1 .. rx_cid_length]; // rx_cid_length bytes after the first byte - uint packet_number = packet.udp_payload[rx_cid_length+1 .. rx_cid_length+4]; // 4 bytes after the CID - offload_info offload = rx_offload_table.find(packet.ip_address, cid); - decrypt_quic_packet(packet, offload, packet_number) + + // Find the offload info based on the destination IP:port and CID. + offload_info offload = + rx_offload_table.find( + packet.dest_ip_address, + packet.udp_payload[1 .. rx_cid_length]); // rx_cid_length bytes after the first byte + + decrypt_quic_packet(packet, offload); } ``` From af08dabb0c078bf93fb1eeec3663c1b6af219328 Mon Sep 17 00:00:00 2001 From: Nick Banks Date: Thu, 8 Jun 2023 12:12:38 -0400 Subject: [PATCH 08/10] add only --- include/psuedocode.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/psuedocode.md b/include/psuedocode.md index b834600..187e82a 100644 --- a/include/psuedocode.md +++ b/include/psuedocode.md @@ -21,10 +21,10 @@ void update_offload(offload_info offloads[]) { if (offload.operation == "add") { if (offload.direction == "tx") { if (tx_cid_length == -1) tx_cid_length = offload.cid.length; - tx_offload_table.add_or_update(offload); + tx_offload_table.add(offload); // eventually will support update too, but simplifying things for now } else { if (rx_cid_length == -1) rx_cid_length = offload.cid.length; - rx_offload_table.add_or_update(offload); + rx_offload_table.add(offload); // eventually will support update too, but simplifying things for now } } else { if (offload.direction == "tx") { From 9119859167839a1ec2d6d132ff088e6d065c2c5d Mon Sep 17 00:00:00 2001 From: Nick Banks Date: Thu, 8 Jun 2023 12:14:48 -0400 Subject: [PATCH 09/10] uint instead --- include/psuedocode.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/psuedocode.md b/include/psuedocode.md index 187e82a..059c167 100644 --- a/include/psuedocode.md +++ b/include/psuedocode.md @@ -37,7 +37,7 @@ void update_offload(offload_info offloads[]) { } // Based on https://github.com/microsoft/msquic/blob/main/src/core/packet.h#L372 -void decompress_packet_number(ulong expected_packet_number, int compressed_packet_number) { +void decompress_packet_number(ulong expected_packet_number, uint compressed_packet_number) { ulong Mask = 0xFFFFFFFF00000000; ulong PacketNumberInc = (~Mask) + 1; ulong PacketNumber = (Mask & expected_packet_number) | compressed_packet_number; From 11ff6378f217488d009be512ec4396d566ec82a8 Mon Sep 17 00:00:00 2001 From: Nick Banks Date: Fri, 9 Jun 2023 07:38:21 -0400 Subject: [PATCH 10/10] better highlight --- include/psuedocode.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/psuedocode.md b/include/psuedocode.md index 059c167..24c05c4 100644 --- a/include/psuedocode.md +++ b/include/psuedocode.md @@ -1,6 +1,6 @@ The follow outlines some psuedocode for how to implement the logic for a prototype QEO solution. -``` +```csharp struct offload_info { uint operation; uint direction;