///|
/// DCE/RPC header — 80 bytes.
pub(all) struct DceHeader {
version : Byte
packet_type : Byte
flags1 : Byte
flags2 : Byte
drep : Bytes
serial_high : Byte
object_uuid : Uuid
interface_uuid : Uuid
activity_uuid : Uuid
server_boot_time : Int
interface_version : Int
sequence_number : Int
opnum : Int
interface_hint : Int
activity_hint : Int
body_length : Int
fragment_number : Int
auth_proto : Byte
serial_low : Byte
} derive(Eq, Debug)
///|
pub fn DceHeader::default() -> DceHeader {
DceHeader::{
version: b'\x04',
packet_type: packet_type_request,
flags1: b'\x20',
flags2: b'\x00',
drep: Bytes::from_array([b'\x10', b'\x00', b'\x00']),
serial_high: b'\x00',
object_uuid: Uuid::empty(),
interface_uuid: Uuid::empty(),
activity_uuid: Uuid::empty(),
server_boot_time: 0,
interface_version: 3,
sequence_number: 1111,
opnum: 0,
interface_hint: 0xFFFF,
activity_hint: 0xFFFF,
body_length: 0,
fragment_number: 0,
auth_proto: b'\x00',
serial_low: b'\x00',
}
}
///|
/// Encode a DCE/RPC header to bytes (80 bytes).
pub fn encode_dce_header(hdr : DceHeader) -> Bytes {
let output : Array[Byte] = []
output.push(hdr.version)
output.push(hdr.packet_type)
output.push(hdr.flags1)
output.push(hdr.flags2)
append_bytes(output, hdr.drep)
output.push(hdr.serial_high)
append_bytes(output, hdr.object_uuid.to_dce_bytes_le())
append_bytes(output, hdr.interface_uuid.to_dce_bytes_le())
append_bytes(output, hdr.activity_uuid.to_dce_bytes_le())
push_u32_le(output, hdr.server_boot_time)
push_u32_le(output, hdr.interface_version)
push_u32_le(output, hdr.sequence_number)
push_u16_le(output, hdr.opnum)
push_u16_le(output, hdr.interface_hint)
push_u16_le(output, hdr.activity_hint)
push_u16_le(output, hdr.body_length)
push_u16_le(output, hdr.fragment_number)
output.push(hdr.auth_proto)
output.push(hdr.serial_low)
Bytes::from_array(output)
}
///|
/// Parse a DCE/RPC header from bytes (requires at least 80 bytes from offset).
pub fn parse_dce_header(
data : Bytes,
offset : Int,
) -> DceHeader raise @frame.FrameError {
guard data.length() >= offset + 80 else {
raise @frame.FrameError::InvalidMacLength(data.length())
}
let drep = Bytes::from_array([
data[offset + 4],
data[offset + 5],
data[offset + 6],
])
DceHeader::{
version: data[offset],
packet_type: data[offset + 1],
flags1: data[offset + 2],
flags2: data[offset + 3],
drep,
serial_high: data[offset + 7],
object_uuid: Uuid::from_dce_bytes_le(data, offset + 8),
interface_uuid: Uuid::from_dce_bytes_le(data, offset + 24),
activity_uuid: Uuid::from_dce_bytes_le(data, offset + 40),
server_boot_time: read_u32_le(data, offset + 56),
interface_version: read_u32_le(data, offset + 60),
sequence_number: read_u32_le(data, offset + 64),
opnum: read_u16_le(data, offset + 68),
interface_hint: read_u16_le(data, offset + 70),
activity_hint: read_u16_le(data, offset + 72),
body_length: read_u16_le(data, offset + 74),
fragment_number: read_u16_le(data, offset + 76),
auth_proto: data[offset + 78],
serial_low: data[offset + 79],
}
}
///|
/// Format DCE header as human-readable summary.
pub fn format_dce_header(hdr : DceHeader) -> String {
let lines : Array[String] = []
lines.push("version=" + hdr.version.to_int().to_string())
lines.push("packet_type=" + packet_type_label(hdr.packet_type))
lines.push("object_uuid=" + hdr.object_uuid.to_hex())
lines.push("interface_uuid=" + hdr.interface_uuid.to_hex())
lines.push("activity_uuid=" + hdr.activity_uuid.to_hex())
lines.push("sequence_number=" + hdr.sequence_number.to_string())
lines.push("opnum=" + hdr.opnum.to_string())
lines.push("body_length=" + hdr.body_length.to_string())
lines.join("\n")
}
///|
/// IO Request structure — wraps RPC payload blocks.
pub(all) struct IoRequest {
args_maximum : Int
args_length : Int
max_count : Int
offset : Int
actual_count : Int
payload : Bytes
} derive(Eq, Debug)
///|
pub fn IoRequest::default() -> IoRequest {
IoRequest::{
args_maximum: 0xFE4,
args_length: 0,
max_count: 0xFE4,
offset: 0,
actual_count: 0,
payload: Bytes::default(),
}
}
///|
/// Encode an IO Request wrapper (20-byte header + payload).
pub fn encode_io_request(req : IoRequest) -> Bytes {
let output : Array[Byte] = []
push_u32_le(output, req.args_maximum)
push_u32_le(output, req.args_length)
push_u32_le(output, req.max_count)
push_u32_le(output, req.offset)
push_u32_le(output, req.actual_count)
append_bytes(output, req.payload)
Bytes::from_array(output)
}
///|
/// Parse an IO Request wrapper from bytes.
pub fn parse_io_request(
data : Bytes,
offset : Int,
) -> IoRequest raise @frame.FrameError {
guard data.length() >= offset + 20 else {
raise @frame.FrameError::InvalidMacLength(data.length())
}
let actual_count = read_u32_le(data, offset + 16)
let payload_end = if data.length() > offset + 20 + actual_count {
offset + 20 + actual_count
} else {
data.length()
}
let payload_bytes : Array[Byte] = []
for i = offset + 20; i < payload_end; i = i + 1 {
payload_bytes.push(data[i])
}
IoRequest::{
args_maximum: read_u32_le(data, offset),
args_length: read_u32_le(data, offset + 4),
max_count: read_u32_le(data, offset + 8),
offset: read_u32_le(data, offset + 12),
actual_count,
payload: Bytes::from_array(payload_bytes),
}
}
///|
/// IO Response structure — wraps RPC response blocks.
pub(all) struct IoResponse {
status : Int
args_length : Int
max_count : Int
offset : Int
actual_count : Int
payload : Bytes
} derive(Eq, Debug)
///|
/// Encode an IO Response wrapper (20-byte header + payload).
pub fn encode_io_response(res : IoResponse) -> Bytes {
let output : Array[Byte] = []
push_u32_le(output, res.status)
push_u32_le(output, res.args_length)
push_u32_le(output, res.max_count)
push_u32_le(output, res.offset)
push_u32_le(output, res.actual_count)
append_bytes(output, res.payload)
Bytes::from_array(output)
}
///|
/// Parse an IO Response wrapper from bytes.
pub fn parse_io_response(
data : Bytes,
offset : Int,
) -> IoResponse raise @frame.FrameError {
guard data.length() >= offset + 20 else {
raise @frame.FrameError::InvalidMacLength(data.length())
}
let actual_count = read_u32_le(data, offset + 16)
let payload_end = if data.length() > offset + 20 + actual_count {
offset + 20 + actual_count
} else {
data.length()
}
let payload_bytes : Array[Byte] = []
for i = offset + 20; i < payload_end; i = i + 1 {
payload_bytes.push(data[i])
}
IoResponse::{
status: read_u32_le(data, offset),
args_length: read_u32_le(data, offset + 4),
max_count: read_u32_le(data, offset + 8),
offset: read_u32_le(data, offset + 12),
actual_count,
payload: Bytes::from_array(payload_bytes),
}
}