pdu
import "github.com/TheManticoreProject/Manticore/network/dcerpc/v4/pdu"
Package pdu models connectionless (datagram) DCE/RPC protocol data units (PDUs): the fixed 80-octet common header and the bodies of the connectionless PDU types (request, ping, response, working, nocall, reject, ack, fault, cl_cancel, fack, cancel_ack) ([C706] chapter 12).
The codec is two-layered. The generic PDU type (pdu.go) frames any connectionless PDU as a Header plus an opaque body whose length is the header’s len field; this round-trips every PDU type at the wire level. The bodies that have a defined internal structure get their own typed codecs: FackBody (also used by nocall), CancelBody (cl_cancel), CancelAckBody (cancel_ack), and the status-code body shared by fault and reject (fault.go).
Only the little-endian data representation (the high nibble of drep[0] == 1) is supported, matching the connection-oriented codec under network/dcerpc/v5/pdu; a big-endian drep is rejected on Unmarshal rather than silently mis-parsed. The three header UUIDs are encoded with the standard DCE uuid_t little-endian layout via windows/guid.
References:
- [C706] section 12.6.3 (connectionless PDU common header fields): https://pubs.opengroup.org/onlinepubs/9629399/chap12.htm
- [C706] chapter 10 (connectionless RPC protocol machines): https://pubs.opengroup.org/onlinepubs/9629399/chap10.htm
Index
- Constants
- Variables
- func MarshalStatusBody(status uint32) []byte
- func UnmarshalStatusBody(data []byte) (uint32, error)
- type CancelAckBody
- type CancelBody
- type FackBody
- type Flags1
- type Flags2
- type Header
- type PDU
- type PacketType
Constants
CancelAckBodySize is the size, in octets, of a non-empty cancel_ack body.
const CancelAckBodySize = 9
CancelBodySize is the size, in octets, of a cl_cancel body.
const CancelBodySize = 8
HeaderSize is the size, in bytes, of the connectionless common header.
const HeaderSize = 80
NoHint is the reserved “no hint available” value for the ihint and ahint fields.
const NoHint uint16 = 0xFFFF
StatusBodySize is the size, in octets, of a fault or reject body.
const StatusBodySize = 4
Variables
DataRepresentationLittleEndian is the canonical 3-octet connectionless drep for little-endian integers, ASCII characters, and IEEE floating point. Note the connectionless drep is 3 octets, unlike the 4-octet connection-oriented packed drep.
var DataRepresentationLittleEndian = [3]byte{0x10, 0x00, 0x00}
func MarshalStatusBody
func MarshalStatusBody(status uint32) []byte
MarshalStatusBody encodes the body shared by the fault and reject PDUs: a single NDR unsigned long status code indicating why the operation faulted or why the request was rejected ([C706] section 12.6.4.6 fault, 12.6.4.7 reject).
func UnmarshalStatusBody
func UnmarshalStatusBody(data []byte) (uint32, error)
UnmarshalStatusBody decodes a fault or reject body into its status code.
type CancelAckBody
CancelAckBody is the optional body of a cancel_ack PDU ([C706] section 12.6.4.3, cancel_ack_body_t at body format version 0). A cancel_ack with no body is an orphan acknowledgement; when a body is present it carries the fields below.
Wire layout (little-endian):
0-3 vers uint32 (body format version, 0)
4-7 cancel_id uint32 (cancel event being acknowledged)
8 server_is_accepting boolean (non-zero if the server accepts cancels)
type CancelAckBody struct {
Version uint32
CancelID uint32
ServerIsAccepting bool
}
func (*CancelAckBody) Marshal
func (b *CancelAckBody) Marshal() ([]byte, error)
Marshal serializes the cancel_ack body into its 9-octet wire form.
func (*CancelAckBody) Unmarshal
func (b *CancelAckBody) Unmarshal(data []byte) (int, error)
Unmarshal parses a cancel_ack body from data and returns the bytes consumed.
type CancelBody
CancelBody is the body of a cl_cancel PDU ([C706] section 12.6.4.4, cancel_body_t at body format version 0).
Wire layout (little-endian):
0-3 vers uint32 (body format version, 0)
4-7 cancel_id uint32 (identifies the cancel event)
type CancelBody struct {
Version uint32
CancelID uint32
}
func (*CancelBody) Marshal
func (b *CancelBody) Marshal() ([]byte, error)
Marshal serializes the cl_cancel body into its 8-octet wire form.
func (*CancelBody) Unmarshal
func (b *CancelBody) Unmarshal(data []byte) (int, error)
Unmarshal parses a cl_cancel body from data and returns the bytes consumed.
type FackBody
FackBody is the body of a fack PDU (and the optional body of a nocall PDU), carrying flow-control and selective-acknowledgement information ([C706] section 12.6.4.5, fack_body_t at body format version 0).
Wire layout (little-endian):
0 vers uint8 (body format version, 0)
1 pad1 uint8 (unused)
2-3 window_size uint16 (receiver window, in fragments)
4-7 max_tsdu uint32 (largest local transport service data unit)
8-11 max_frag_size uint32 (largest accepted fragment size)
12-13 serial_num uint16 (serial number being acknowledged)
14-15 selack_len uint16 (number of selack elements that follow)
16... selack[] uint32[] (selective-ack bitmasks, selack_len elements)
type FackBody struct {
Version uint8
Pad1 uint8
WindowSize uint16
MaxTSDU uint32
MaxFragSize uint32
SerialNum uint16
// SelAck holds the selective-acknowledgement bitmasks. Its length is encoded on
// the wire as selack_len.
SelAck []uint32
}
func (*FackBody) Marshal
func (b *FackBody) Marshal() ([]byte, error)
Marshal serializes the fack body into its wire form.
func (*FackBody) Unmarshal
func (b *FackBody) Unmarshal(data []byte) (int, error)
Unmarshal parses a fack body from data and returns the number of bytes consumed.
type Flags1
Flags1 is the first set of connectionless PDU flags (the flags1 field of the common header).
References:
- [C706] section 12.6.3.2 (flags1): https://pubs.opengroup.org/onlinepubs/9629399/chap12.htm
type Flags1 uint8
const (
// Flags1Reserved01 is reserved for implementations; must be ignored.
Flags1Reserved01 Flags1 = 0x01
// Flags1LastFrag marks the last fragment of a multi-PDU transmission.
Flags1LastFrag Flags1 = 0x02
// Flags1Frag marks a fragment of a multi-PDU transmission.
Flags1Frag Flags1 = 0x04
// Flags1NoFack tells the receiver not to send a fack for this fragment.
Flags1NoFack Flags1 = 0x08
// Flags1Maybe marks a "maybe" request (no response expected). Client-to-server.
Flags1Maybe Flags1 = 0x10
// Flags1Idempotent marks an idempotent request. Client-to-server.
Flags1Idempotent Flags1 = 0x20
// Flags1Broadcast marks a broadcast request. Client-to-server.
Flags1Broadcast Flags1 = 0x40
// Flags1Reserved80 is reserved for implementations; must be ignored.
Flags1Reserved80 Flags1 = 0x80
)
func (Flags1) Has
func (f Flags1) Has(flag Flags1) bool
Has reports whether all bits in flag are set.
func (Flags1) String
func (f Flags1) String() string
String returns a “|”-joined list of set flag names, or “none”.
type Flags2
Flags2 is the second set of connectionless PDU flags (the flags2 field of the common header). Only one bit is defined; the rest are reserved and must be zero.
References:
- [C706] section 12.6.3.3 (flags2): https://pubs.opengroup.org/onlinepubs/9629399/chap12.htm
type Flags2 uint8
const (
// Flags2Reserved01 is reserved for implementations; must be ignored.
Flags2Reserved01 Flags2 = 0x01
// Flags2CancelPending indicates a cancel was pending at the time the call
// completed.
Flags2CancelPending Flags2 = 0x02
)
func (Flags2) Has
func (f Flags2) Has(flag Flags2) bool
Has reports whether all bits in flag are set.
func (Flags2) String
func (f Flags2) String() string
String returns a “|”-joined list of set flag names, or “none”.
type Header
Header is the connectionless common header present at the start of every PDU ([C706] section 12.6.3.1, IDL type dc_rpc_cl_pkt_hdr_t).
Wire layout (offsets in octets):
0 rpc_vers uint8 (version in 4 LSBs)
1 ptype uint8 (type in 5 LSBs)
2 flags1 uint8
3 flags2 uint8
4-6 drep byte[3]
7 serial_hi uint8
8-23 object uuid_t (16)
24-39 if_id uuid_t (16)
40-55 act_id uuid_t (16)
56-59 server_boot uint32
60-63 if_vers uint32
64-67 seqnum uint32
68-69 opnum uint16
70-71 ihint uint16
72-73 ahint uint16
74-75 len uint16 (length of the body that follows)
76-77 fragnum uint16
78 auth_proto uint8
79 serial_lo uint8
type Header struct {
RPCVersion uint8
PacketType PacketType
Flags1 Flags1
Flags2 Flags2
DataRepresentation [3]byte
SerialHi uint8
ObjectID guid.GUID
InterfaceID guid.GUID
ActivityID guid.GUID
ServerBoot uint32
InterfaceVersion uint32
SequenceNumber uint32
OpNum uint16
InterfaceHint uint16
ActivityHint uint16
// BodyLength is the len field: the size, in octets, of the body following the
// header. PDU.Marshal sets it from the body length, so callers normally leave it
// zero.
BodyLength uint16
FragmentNumber uint16
AuthProto uint8
SerialLo uint8
}
func NewHeader
func NewHeader(pt PacketType) Header
NewHeader returns a header initialized for connectionless protocol version 4 with little-endian data representation, the given packet type, and no interface/activity hint. The caller fills in the UUIDs, sequence number, opnum, and fragmentation fields as needed.
func (*Header) Marshal
func (h *Header) Marshal() ([]byte, error)
Marshal serializes the header into its 80-octet wire form.
func (*Header) Serial
func (h *Header) Serial() uint16
Serial reassembles the 16-bit serial number from its high and low halves, which are stored at opposite ends of the header (serial_hi at octet 7, serial_lo at octet 79).
func (*Header) String
func (h *Header) String() string
String returns a human-readable one-line summary of the header.
func (*Header) Unmarshal
func (h *Header) Unmarshal(data []byte) (int, error)
Unmarshal parses a header from the start of data and returns the bytes consumed (always HeaderSize on success).
type PDU
PDU is a complete connectionless DCE/RPC protocol data unit: the common Header followed by an opaque body of Header.BodyLength octets. It is the generic framing layer that round-trips every connectionless PDU type; the structured contents of the bodies that have a defined layout are parsed by the typed body codecs (FackBody, CancelBody, CancelAckBody) and the fault/reject status helpers.
The ping, ack, and working PDUs carry no body, so Body is nil for them. The request and response bodies are NDR-marshalled stub data (opaque to this layer).
Authentication verifiers are not modelled: a non-zero auth_proto means an auth_verifier trailer follows the body, which this codec does not interpret.
type PDU struct {
Header Header
Body []byte
}
func (*PDU) Marshal
func (p *PDU) Marshal() ([]byte, error)
Marshal serializes the PDU into its wire form. It sets Header.BodyLength from the body length before encoding the header, so callers do not need to maintain it.
func (*PDU) String
func (p *PDU) String() string
String returns a human-readable one-line summary of the PDU.
func (*PDU) Unmarshal
func (p *PDU) Unmarshal(data []byte) (int, error)
Unmarshal parses a complete PDU (header plus the Header.BodyLength body octets that follow) from data and returns the number of bytes consumed. Any trailing bytes beyond the body (for example an authentication verifier when auth_proto is non-zero) are left for the caller.
type PacketType
PacketType identifies the kind of a connectionless DCE/RPC PDU, as carried in the 5 least significant bits of the ptype field of the common header.
The connectionless ptype values differ from the connection-oriented ones (which reuse 0-10 for an overlapping but not identical set and add bind/alter_context at 11+). The values below are the complete connectionless set.
References:
- [C706] section 12.6.4 (PDU types) and table in section 12.5: https://pubs.opengroup.org/onlinepubs/9629399/chap12.htm
type PacketType uint8
const (
PacketTypeRequest PacketType = 0
PacketTypePing PacketType = 1
PacketTypeResponse PacketType = 2
PacketTypeFault PacketType = 3
PacketTypeWorking PacketType = 4
PacketTypeNoCall PacketType = 5
PacketTypeReject PacketType = 6
PacketTypeAck PacketType = 7
PacketTypeClCancel PacketType = 8
PacketTypeFack PacketType = 9
PacketTypeCancelAck PacketType = 10
)
func (PacketType) String
func (t PacketType) String() string
String returns the mnemonic name of the packet type.