analyzer/protocol: Reformat with spicy-format

This commit is contained in:
Arne Welzel 2025-07-28 09:39:40 +02:00
parent aa2afa3e9b
commit d70bcd07b9
6 changed files with 1433 additions and 1519 deletions

View file

@ -55,5 +55,4 @@ repos:
rev: v0.26.0
hooks:
- id: spicy-format
# TODO: Reformat existing large analyzers just before 8.0.
exclude: '(^testing/.*)|(protocol/ldap/.*)|(protocol/quic/.*)|(protocol/websocket/.*)'
exclude: '^testing/.*'

View file

@ -50,7 +50,7 @@ public type ASN1Type = enum {
GeneralString = 27,
UniversalString = 28,
CharacterString = 29,
BMPString = 30
BMPString = 30,
};
#- ASN.1 data classes --------------------------------------------------------
@ -59,7 +59,7 @@ public type ASN1Class = enum {
Universal = 0,
Application = 1,
ContextSpecific = 2,
Private = 3
Private = 3,
};
#- ASN.1 tag definition (including length) ------------------------------------
@ -73,14 +73,12 @@ type LengthType = unit {
islong: 7;
};
switch (self.data.islong) {
0 -> : void {
self.len = self.data.num;
self.tag_len = 1;
}
1 -> : bytes &size=self.data.num
&convert=$$.to_uint(spicy::ByteOrder::Network) {
1 -> : bytes &size=self.data.num &convert=$$.to_uint(spicy::ByteOrder::Network) {
self.len = $$;
self.tag_len = self.data.num + 1;
}
@ -128,13 +126,11 @@ type ASN1String = unit(tag: ASN1Tag, len: uint64) {
# see "Restricted Character String Types" in
# "Generic String Encoding Rules (GSER) for ASN.1 Types"
# (https://datatracker.ietf.org/doc/html/rfc3641#section-3.2)
case ASN1Type::PrintableString,
ASN1Type::GeneralizedTime,
ASN1Type::UTCTime: {
self.encoding = spicy::Charset::ASCII;
}
case ASN1Type::UTF8String,
ASN1Type::GeneralString,
ASN1Type::CharacterString,
@ -192,7 +188,6 @@ type ASN1ObjectIdentifier = unit(len: uint64) {
}
};
#- ASN.1 message header (tag + length information) ----------------------------
public type ASN1Header = unit {
@ -204,23 +199,13 @@ public type ASN1Header = unit {
public type ASN1Body = unit(head: ASN1Header, recursive: bool) {
switch (head.tag.type_) {
ASN1Type::Boolean -> bool_value: uint8 &convert=cast<bool>($$) &requires=head.len.len == 1;
ASN1Type::Integer,
ASN1Type::Enumerated -> num_value: bytes &size=head.len.len
&convert=$$.to_int(spicy::ByteOrder::Big);
ASN1Type::Enumerated -> num_value: bytes &size=head.len.len &convert=$$.to_int(spicy::ByteOrder::Big);
ASN1Type::NullVal -> null_value: bytes &size=0 &requires=head.len.len == 0;
ASN1Type::BitString -> bitstr_value: ASN1BitString(head.len.len, head.tag.constructed);
ASN1Type::OctetString -> str_value: ASN1OctetString(head.len.len, head.tag.constructed)
&convert=$$.value.decode(spicy::Charset::ASCII);
ASN1Type::ObjectIdentifier -> str_value: ASN1ObjectIdentifier(head.len.len)
&convert=$$.oidstring;
ASN1Type::OctetString -> str_value: ASN1OctetString(head.len.len, head.tag.constructed) &convert=$$.value.decode(spicy::Charset::ASCII);
ASN1Type::ObjectIdentifier -> str_value: ASN1ObjectIdentifier(head.len.len) &convert=$$.oidstring;
ASN1Type::BMPString,
ASN1Type::CharacterString,
ASN1Type::GeneralizedTime,
@ -235,8 +220,8 @@ public type ASN1Body = unit(head: ASN1Header, recursive: bool) {
ASN1Type::VideotextString,
ASN1Type::VisibleString,
ASN1Type::UniversalString -> str_value: ASN1String(head.tag, head.len.len);
ASN1Type::Sequence, ASN1Type::Set -> seq: ASN1SubMessages(head.len.len) if (recursive);
ASN1Type::Sequence,
ASN1Type::Set -> seq: ASN1SubMessages(head.len.len) if(recursive);
# TODO: ASN1Type values not handled yet
ASN1Type::ObjectDescriptor,
@ -266,14 +251,11 @@ public type ASN1Message = unit(recursive: bool) {
head: ASN1Header;
switch (self.head.tag.class) {
ASN1Class::Universal -> body: ASN1Body(self.head, recursive);
ASN1Class::Application,
ASN1Class::ContextSpecific,
ASN1Class::Private -> application_data: bytes &size=self.head.len.len {
self.application_id = cast<int32>(self.head.tag.type_);
}
};
};

View file

@ -115,12 +115,9 @@ public type ResultCode = enum {
#-----------------------------------------------------------------------------
public type Result = unit {
code: ASN1::ASN1Message(True) &convert=cast<ResultCode>(cast<uint8>($$.body.num_value))
&default=ResultCode::Undef;
matchedDN: ASN1::ASN1Message(True) &convert=$$.body.str_value
&default="";
diagnosticMessage: ASN1::ASN1Message(True) &convert=$$.body.str_value
&default="";
code: ASN1::ASN1Message(True) &convert=cast<ResultCode>(cast<uint8>($$.body.num_value)) &default=ResultCode::Undef;
matchedDN: ASN1::ASN1Message(True) &convert=$$.body.str_value &default="";
diagnosticMessage: ASN1::ASN1Message(True) &convert=$$.body.str_value &default="";
# TODO: if we want to parse referral URIs in result
# https://tools.ietf.org/html/rfc4511#section-4.1.10
@ -162,7 +159,6 @@ public type MessageDispatch = unit(ctx: Ctx&) {
};
};
#-----------------------------------------------------------------------------
type MaybeEncrypted = unit(ctx: Ctx&) {
# A plaintext LDAP message always starts with at least 3 bytes and the first
@ -242,7 +238,8 @@ type KrbWrapToken = unit {
};
filler: skip b"\xff";
ec: uint16; # extra count
rrc: uint16 { # right rotation count
rrc: uint16 {
# right rotation count
# Handle rrc == ec or rrc == 0.
if (self.rrc == self.ec) {
self.header_ec = self.ec;
@ -406,7 +403,7 @@ type GSS_SPNEGO_Init = unit {
spnegoInitial: skip GSS_SPNEGO_negTokenInit if(self?.spnegoInitByte);
};
type SaslCredentials = unit() {
type SaslCredentials = unit {
mechanism: ASN1::ASN1Message(False) &convert=$$.body.str_value;
# Peak into GSS-SPNEGO payload if we have any.
@ -416,7 +413,7 @@ type SaslCredentials = unit() {
};
};
type SicilyMessage = unit() {
type SicilyMessage = unit {
# Just ensure the signature matches. We could do more,
# but it'd be better to forward to an NTLM analyzer.
signature: skip b"NTLMSSP";
@ -486,23 +483,18 @@ type BindRequest = unit(inout message: Message, ctx: Ctx&) {
if (|self.authData| > 0) {
switch (self.authType) {
BindAuthType::BIND_AUTH_SIMPLE ->
: void {
BindAuthType::BIND_AUTH_SIMPLE -> : void {
self.simpleCreds = self.authData.decode();
message.arg = self.simpleCreds;
}
BindAuthType::BIND_AUTH_SASL ->
saslCreds: SaslCredentials {
BindAuthType::BIND_AUTH_SASL -> saslCreds: SaslCredentials {
message.arg = self.saslCreds.mechanism;
ctx.saslMechanism = self.saslCreds.mechanism;
}
BindAuthType::SICILY_NEGOTIATE, BindAuthType::SICILY_RESPONSE ->
sicilyMessage: SicilyMessage {
BindAuthType::SICILY_NEGOTIATE,
BindAuthType::SICILY_RESPONSE -> sicilyMessage: SicilyMessage {
message.arg = self.sicilyMessage.signature_decoded;
}
* -> : void;
} &parse-from=self.authData;
};
@ -543,8 +535,7 @@ type BindResponse = unit(inout message: Message, ctx: Ctx&) {
# If the client requested GSS-SPNEGO, try to parse the server's response
# to switch message mode.
gss_spnego: GSS_SPNEGO_Subsequent &parse-from=self.serverSaslCreds[0].payload
if (ctx.saslMechanism == "GSS-SPNEGO" && |self.serverSaslCreds| > 0) {
gss_spnego: GSS_SPNEGO_Subsequent &parse-from=self.serverSaslCreds[0].payload if(ctx.saslMechanism == "GSS-SPNEGO" && |self.serverSaslCreds| > 0) {
if ($$?.negTokenResp) {
local token = $$.negTokenResp;
@ -603,8 +594,7 @@ public type AttributeSelection = unit {
# https://tools.ietf.org/html/rfc4511#section-4.5.1
# and decide how deep that should be fleshed out.
: ASN1::ASN1Message(True) {
if (($$.head.tag.type_ == ASN1::ASN1Type::Sequence) &&
($$.body?.seq)) {
if (($$.head.tag.type_ == ASN1::ASN1Type::Sequence) && ($$.body?.seq)) {
for (i in $$.body.seq.submessages) {
if (i.body?.str_value) {
self.attributes.push_back(i.body.str_value);
@ -619,9 +609,7 @@ type AttributeValueAssertion = unit {
var val: string = "";
: ASN1::ASN1Message(True) {
if (($$.head.tag.type_ == ASN1::ASN1Type::Sequence) &&
($$.body?.seq) &&
(|$$.body.seq.submessages| >= 2)) {
if (($$.head.tag.type_ == ASN1::ASN1Type::Sequence) && ($$.body?.seq) && (|$$.body.seq.submessages| >= 2)) {
if ($$.body.seq.submessages[0].body?.str_value) {
self.desc = $$.body.seq.submessages[0].body.str_value;
}
@ -715,7 +703,6 @@ public function bytes_sid_to_SID_repr(bts: bytes) : string {
return ret;
}
public function uint32_to_hex_repr(bts: bytes): string {
# Needs to be exactly 4 bytes
if (|bts| != 4) {
@ -739,12 +726,11 @@ public function string_representation(search_filter: SearchFilter): string {
switch (local fType = search_filter.filterType) {
# The NOT, AND and OR filter types are trees and may hold many leaf nodes. So recursively get
# the stringPresentations for the leaf nodes and add them all in one final statement.
case FilterType::FILTER_NOT: {
repr = "(!%s)" % search_filter.FILTER_NOT.searchfilter.stringRepresentation;
}
case FilterType::FILTER_AND, FilterType::FILTER_OR: {
case FilterType::FILTER_AND,
FilterType::FILTER_OR: {
local nestedObj: ParseNestedAndOr;
local printChar = "";
@ -780,12 +766,9 @@ public function string_representation(search_filter: SearchFilter): string {
for (searchFilter in nestedObj.searchfilters) {
switch (i) {
case 0: {
repr = "(%s%s%s" % (
printChar,
searchFilter.stringRepresentation,
repr = "(%s%s%s" % (printChar, searchFilter.stringRepresentation,
# If we have exactly one element immediately close the statement since we are done.
|nestedObj.searchfilters| == 1 ? ")" : ""
);
|nestedObj.searchfilters| == 1 ? ")" : "");
}
case 1: {
repr = repr + searchFilter.stringRepresentation + ")";
@ -799,39 +782,29 @@ public function string_representation(search_filter: SearchFilter): string {
}
# The following FilterTypes are leaf nodes and can thus be represented in a statement
case FilterType::FILTER_EXT: {
# For extended search filters the meaning of the individual fields in
# `DecodedAttributeValue` is slightly different.
repr = "(%s:%s:=%s)" % (search_filter.FILTER_EXT.assertionValueDecoded,
search_filter.FILTER_EXT.attributeDesc.decode(),
search_filter.FILTER_EXT.matchValue);
repr = "(%s:%s:=%s)" % (search_filter.FILTER_EXT.assertionValueDecoded, search_filter.FILTER_EXT.attributeDesc.decode(), search_filter.FILTER_EXT.matchValue);
}
case FilterType::FILTER_APPROX: {
repr = "(%s~=%s)" % (search_filter.FILTER_APPROX.attributeDesc.decode(),
search_filter.FILTER_APPROX.assertionValueDecoded);
repr = "(%s~=%s)" % (search_filter.FILTER_APPROX.attributeDesc.decode(), search_filter.FILTER_APPROX.assertionValueDecoded);
}
case FilterType::FILTER_EQ: {
repr = "(%s=%s)" % (search_filter.FILTER_EQ.attributeDesc.decode(),
search_filter.FILTER_EQ.assertionValueDecoded);
repr = "(%s=%s)" % (search_filter.FILTER_EQ.attributeDesc.decode(), search_filter.FILTER_EQ.assertionValueDecoded);
}
case FilterType::FILTER_GE: {
repr = "(%s>=%s)" % (search_filter.FILTER_GE.attributeDesc.decode(),
search_filter.FILTER_GE.assertionValueDecoded);
repr = "(%s>=%s)" % (search_filter.FILTER_GE.attributeDesc.decode(), search_filter.FILTER_GE.assertionValueDecoded);
}
case FilterType::FILTER_LE: {
repr = "(%s<=%s)" % (search_filter.FILTER_LE.attributeDesc.decode(),
search_filter.FILTER_LE.assertionValueDecoded);
repr = "(%s<=%s)" % (search_filter.FILTER_LE.attributeDesc.decode(), search_filter.FILTER_LE.assertionValueDecoded);
}
case FilterType::FILTER_SUBSTR: {
local anys: string = "";
if (|search_filter.FILTER_SUBSTR.anys| > 0)
anys = b"*".join(search_filter.FILTER_SUBSTR.anys).decode() + "*";
repr = "(%s=%s*%s%s)" % (search_filter.FILTER_SUBSTR.attributeDesc.decode(),
search_filter.FILTER_SUBSTR.initial,
anys,
search_filter.FILTER_SUBSTR.final);
repr = "(%s=%s*%s%s)" % (search_filter.FILTER_SUBSTR.attributeDesc.decode(), search_filter.FILTER_SUBSTR.initial, anys, search_filter.FILTER_SUBSTR.final);
}
case FilterType::FILTER_PRESENT: {
repr = "(%s=*)" % search_filter.FILTER_PRESENT;
@ -862,19 +835,16 @@ type DecodedAttributeValue = unit(fType: FilterType) {
switch (self.attributeDesc) {
# Special parsing required for some CLDAP attributes,
# see https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-adts/895a7744-aff3-4f64-bcfa-f8c05915d2e9
case b"DomainGuid": {
self.assertionValueDecoded = utf16_guid_to_hex_repr(self.assertionValue);
}
case b"objectSid", b"AAC": {
case b"objectSid",
b"AAC": {
self.assertionValueDecoded = bytes_sid_to_hex_repr(self.assertionValue);
}
case b"DomainSid": {
self.assertionValueDecoded = bytes_sid_to_SID_repr(self.assertionValue);
}
case b"NtVer": {
self.assertionValueDecoded = uint32_to_hex_repr(self.assertionValue);
}
@ -933,31 +903,18 @@ type SearchFilter = unit {
switch (self.filterType) {
# FilterTypes that hold one or more SearchFilters inside them
FilterType::FILTER_AND -> FILTER_AND: ParseNestedAndOr()
&parse-from=self.filterBytes;
FilterType::FILTER_OR -> FILTER_OR: ParseNestedAndOr()
&parse-from=self.filterBytes;
FilterType::FILTER_NOT -> FILTER_NOT: ParseNestedNot()
&parse-from=self.filterBytes;
FilterType::FILTER_AND -> FILTER_AND: ParseNestedAndOr() &parse-from=self.filterBytes;
FilterType::FILTER_OR -> FILTER_OR: ParseNestedAndOr() &parse-from=self.filterBytes;
FilterType::FILTER_NOT -> FILTER_NOT: ParseNestedNot() &parse-from=self.filterBytes;
# FilterTypes that we can actually convert to a string
FilterType::FILTER_EQ -> FILTER_EQ: DecodedAttributeValue(FilterType::FILTER_EQ)
&parse-from=self.filterBytes;
FilterType::FILTER_SUBSTR -> FILTER_SUBSTR: SubstringFilter
&parse-from=self.filterBytes;
FilterType::FILTER_GE -> FILTER_GE: DecodedAttributeValue(FilterType::FILTER_GE)
&parse-from=self.filterBytes;
FilterType::FILTER_LE -> FILTER_LE: DecodedAttributeValue(FilterType::FILTER_LE)
&parse-from=self.filterBytes;
FilterType::FILTER_APPROX -> FILTER_APPROX: DecodedAttributeValue(FilterType::FILTER_APPROX)
&parse-from=self.filterBytes;
FilterType::FILTER_EXT -> FILTER_EXT: DecodedAttributeValue(FilterType::FILTER_EXT)
&parse-from=self.filterBytes;
FilterType::FILTER_PRESENT -> FILTER_PRESENT: ASN1::ASN1OctetString(self.filterLen, False)
&convert=$$.value.decode(spicy::Charset::ASCII)
&parse-from=self.filterBytes;
FilterType::FILTER_EQ -> FILTER_EQ: DecodedAttributeValue(FilterType::FILTER_EQ) &parse-from=self.filterBytes;
FilterType::FILTER_SUBSTR -> FILTER_SUBSTR: SubstringFilter &parse-from=self.filterBytes;
FilterType::FILTER_GE -> FILTER_GE: DecodedAttributeValue(FilterType::FILTER_GE) &parse-from=self.filterBytes;
FilterType::FILTER_LE -> FILTER_LE: DecodedAttributeValue(FilterType::FILTER_LE) &parse-from=self.filterBytes;
FilterType::FILTER_APPROX -> FILTER_APPROX: DecodedAttributeValue(FilterType::FILTER_APPROX) &parse-from=self.filterBytes;
FilterType::FILTER_EXT -> FILTER_EXT: DecodedAttributeValue(FilterType::FILTER_EXT) &parse-from=self.filterBytes;
FilterType::FILTER_PRESENT -> FILTER_PRESENT: ASN1::ASN1OctetString(self.filterLen, False) &convert=$$.value.decode(spicy::Charset::ASCII) &parse-from=self.filterBytes;
};
# So when you're done with recursively parsing the filters, we can now leverage the tree structure to
@ -970,19 +927,16 @@ type SearchFilter = unit {
on %error {
self.stringRepresentation = "FILTER_PARSING_ERROR";
}
};
public type SearchRequest = unit(inout message: Message) {
baseObject: ASN1::ASN1Message(True) &convert=$$.body.str_value {
message.obj = self.baseObject;
}
scope: ASN1::ASN1Message(True) &convert=cast<SearchScope>(cast<uint8>($$.body.num_value))
&default=SearchScope::Undef {
scope: ASN1::ASN1Message(True) &convert=cast<SearchScope>(cast<uint8>($$.body.num_value)) &default=SearchScope::Undef {
message.arg = "%s" % self.scope;
}
deref: ASN1::ASN1Message(True) &convert=cast<SearchDerefAlias>(cast<uint8>($$.body.num_value))
&default=SearchDerefAlias::Undef;
deref: ASN1::ASN1Message(True) &convert=cast<SearchDerefAlias>(cast<uint8>($$.body.num_value)) &default=SearchDerefAlias::Undef;
sizeLimit: ASN1::ASN1Message(True) &convert=$$.body.num_value &default=0;
timeLimit: ASN1::ASN1Message(True) &convert=$$.body.num_value &default=0;
typesOnly: ASN1::ASN1Message(True) &convert=$$.body.bool_value &default=False;
@ -1110,9 +1064,7 @@ type ExtendedRequest = unit(inout message: Message, ctx: Ctx&) {
}
# If there's more byte to parse, it's the requestValue.
: ASN1::ASN1Message(False)
&requires=($$.head.tag.class == ASN1::ASN1Class::ContextSpecific)
if ( message.opLen > self.offset() ) {
: ASN1::ASN1Message(False) &requires=($$.head.tag.class == ASN1::ASN1Class::ContextSpecific) if(message.opLen > self.offset()) {
self.requestValue = $$.application_data;
}

View file

@ -7,15 +7,7 @@ import spicy;
import zeek;
# The interface to the C++ code that handles the decryption of the INITIAL packet payload using well-known keys
public function decrypt_crypto_payload(
version: uint32,
data: bytes,
connection_id: bytes,
encrypted_offset: uint64,
payload_offset: uint64,
from_client: bool
): bytes &cxxname="QUIC_decrypt_crypto_payload";
public function decrypt_crypto_payload(version: uint32, data: bytes, connection_id: bytes, encrypted_offset: uint64, payload_offset: uint64, from_client: bool): bytes &cxxname="QUIC_decrypt_crypto_payload";
# Can we decrypt?
function can_decrypt(long_header: LongHeaderPacket, context: Context, crypto: CryptoSinkUnit&): bool {
@ -76,7 +68,8 @@ type CryptoSinkUnit = unit(is_orig: bool, context: Context&) {
self.buffered += $$[2];
}
: void &requires=(self.length <= 2**14 + 256) { # The length MUST NOT exceed 2^14 + 256 bytes (RFC 8446)
: void &requires=(self.length <= 2**14 + 256) {
# The length MUST NOT exceed 2^14 + 256 bytes (RFC 8446)
# The client or server hello data is forwarded to the SSL analyzer as a
# TLSPlaintext record with legacy_record_version set to \x03\x03 (1.3).
@ -246,13 +239,9 @@ public type LongHeaderPacketV1 = unit(inout outer: LongHeaderPacket) {
switch (LongPacketTypeV1(outer.first_byte.packet_type)) {
LongPacketTypeV1::INITIAL -> initial_hdr: InitialPacket(outer) {
outer.is_initial = True;
outer.encrypted_offset = outer.offset() +
self.initial_hdr.length.bytes_to_parse +
self.initial_hdr.token_length.bytes_to_parse +
self.initial_hdr.token_length.result_;
outer.encrypted_offset = outer.offset() + self.initial_hdr.length.bytes_to_parse + self.initial_hdr.token_length.bytes_to_parse + self.initial_hdr.token_length.result_;
outer.payload_length = self.initial_hdr.length.result_;
}
LongPacketTypeV1::ZERO_RTT -> zerortt_hdr: ZeroRTTPacket(outer);
LongPacketTypeV1::HANDSHAKE -> handshake_hdr: HandshakePacket(outer);
LongPacketTypeV1::RETRY -> retry_hdr: RetryPacket(outer) {
@ -265,13 +254,9 @@ public type LongHeaderPacketV2 = unit(inout outer: LongHeaderPacket) {
switch (LongPacketTypeV2(outer.first_byte.packet_type)) {
LongPacketTypeV2::INITIAL -> initial_hdr: InitialPacket(outer) {
outer.is_initial = True;
outer.encrypted_offset = outer.offset() +
self.initial_hdr.length.bytes_to_parse +
self.initial_hdr.token_length.bytes_to_parse +
self.initial_hdr.token_length.result_;
outer.encrypted_offset = outer.offset() + self.initial_hdr.length.bytes_to_parse + self.initial_hdr.token_length.bytes_to_parse + self.initial_hdr.token_length.result_;
outer.payload_length = self.initial_hdr.length.result_;
}
LongPacketTypeV2::ZERO_RTT -> zerortt_hdr: ZeroRTTPacket(outer);
LongPacketTypeV2::HANDSHAKE -> handshake_hdr: HandshakePacket(outer);
LongPacketTypeV2::RETRY -> retry_hdr: RetryPacket(outer) {
@ -302,9 +287,13 @@ public type LongHeaderPacket = unit {
};
version: uint32;
dest_conn_id_len: uint8 { self.server_conn_id_length = $$; }
dest_conn_id_len: uint8 {
self.server_conn_id_length = $$;
}
dest_conn_id: bytes &size=self.server_conn_id_length;
src_conn_id_len: uint8 { self.client_conn_id_length = $$; }
src_conn_id_len: uint8 {
self.client_conn_id_length = $$;
}
src_conn_id: bytes &size=self.client_conn_id_length;
switch (self.version) {
@ -407,7 +396,6 @@ type ConnectionClosePayload = unit(header: LongHeaderPacket) {
reason_phrase: bytes &size=self.reason_phrase_length.result_;
};
##############
# Long packets
# Specific long packet type units
@ -448,7 +436,6 @@ type HandshakePacket = unit(header: LongHeaderPacket) {
payload: skip bytes &size=self.length.result_;
};
type RetryPacket = unit(header: LongHeaderPacket) {
var header: LongHeaderPacket = header;
var retry_token: bytes;
@ -585,7 +572,6 @@ type Packet = unit(from_client: bool, context: Context&) {
self.long_header.payload_length,
from_client
);
} else {
context.server_cid_len = self.long_header.src_conn_id_len;
context.client_cid_len = self.long_header.dest_conn_id_len;

View file

@ -12,11 +12,7 @@ const OPCODE_CLOSE = 0x08;
const OPCODE_PING = 0x09;
const OPCODE_PONG = 0x0a;
public function fast_unmask(
masking_key_idx: uint64,
masking_key: vector<uint8>,
chunk: bytes
): bytes &cxxname="hlt_websocket::WebSocket::fast_unmask";
public function fast_unmask(masking_key_idx: uint64, masking_key: vector<uint8>, chunk: bytes): bytes &cxxname="hlt_websocket::WebSocket::fast_unmask";
type Frame = unit(m: Message) {
var payload_len: uint64;
@ -89,7 +85,6 @@ type CloseFrame = unit {
}
};
public type Message = unit {
# transient trickery
var done: bool = False;