ndr

package module
v0.0.2 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Feb 19, 2026 License: Apache-2.0 Imports: 13 Imported by: 8

README

NDR

This project is a fork and extension of jcmturner/rpc/v2/ndr which is an NDR decoder trying to follow the specification of DCE 1.1:Remote Procedure Call - Transfer Syntax NDR. My addition to the fork is a partial implementation of an NDR encoder which is very much a work in progress and far from complete. I have also extended the decoder to better support top-level pointers.

Structs from IDL

Interface Definition Language (IDL)

Is an array conformant and/or varying?

An array is conformant if the IDL definition includes one of the following attributes:

  • min_is
  • max_is
  • size_is

An array is varying if the IDL definition includes one of the following attributes:

  • last_is
  • first_is
  • length_is
Examples:

SubAuthority[] is conformant in the example below:

 typedef struct _RPC_SID {
   unsigned char Revision;
   unsigned char SubAuthorityCount;
   RPC_SID_IDENTIFIER_AUTHORITY IdentifierAuthority;
   [size_is(SubAuthorityCount)] unsigned long SubAuthority[];
 } RPC_SID,
  *PRPC_SID,
  *PSID;

Buffer is a pointer to a conformant varying array in the example below:

 typedef struct _RPC_UNICODE_STRING {
   unsigned short Length;
   unsigned short MaximumLength;
   [size_is(MaximumLength/2), length_is(Length/2)] 
     WCHAR* Buffer;
 } RPC_UNICODE_STRING,
  *PRPC_UNICODE_STRING;

Algorith for deferral of referents

When deferring a referent, the data a pointer points to, the placement of the defered data in the octet stream defends on where the pointer is placed.

In general, a defered referent is placed after the structure the pointer is embedded in. For pointers inside nested structs, the referent is placed after the outermost struct.

If there are multiple defered referents, they are placed in the order the pointers occur in the structures.

A special case is a top-level pointer in which case the referent is NOT defered but written directly following the pointer. If a top-level pointer's referent contains embedded pointers, the embedded pointers's referent are placed after the top-level pointer's referent rather than after the top-level pointer's parent structure.

RPC_UNICODE_STRING

A simplification has been made to handle RPC_UNICODE_STRING structs as strings instead of byte buffers to represent the actual string. This introduces a problem because in NDR, strings must be null terminated, but since an RPC_UNIODE_STRING is actually a byte array, it should not be null terminated. So to handle this an additional tag has been introduced to indicate that a string field in a struct should NOT be null terminated which provides a bit more flexibility.

Top-level pointers

The RPC method arguments, or in this case, the fields in the request and response structs are considered top-level arguments. If any of these fields is a pointer, this should be treated as a top-level pointer which is handled differently from embedded pointers. By default, a top-level pointer is considered a referent pointer and is represented by the referent marshalled directly without any pointer representation first. If the IDL specification adds the unique or ptr attribute, this becomes a full top-level pointer in which case a 4 byte pointer representation is written and is directly followed by the representation of the referent. So in both cases, the referent is written directly and is NOT deferred to later.

If a top-level pointer points to a struct which contains pointers, those pointers are considered embedded pointers. The referent of embedded pointers are deferred until later in the byte stream by default, but in the case of embedded pointers in the referent of a top-level pointer, the embedded pointer's referent is placed directly after the top-level pointer's referent instead of after the parent structure.

To handle this, two additional tags have been introduced to mark a struct field as a top-level pointer and to indicate if it is a full pointer.

Documentation

Overview

Package ndr provides the ability to unmarshal NDR encoded byte steams into Go data structures

Index

Constants

View Source
const (
	TagConformant      = "conformant"
	TagVarying         = "varying"
	TagPointer         = "pointer"
	TagTopLevelPointer = "toppointer"
	TagFullPointer     = "fullpointer"
	TagPipe            = "pipe"
	TagSkipNull        = "skipnull"
)

Struct tag values

View Source
const (
	SizeBool   = 1
	SizeChar   = 1
	SizeUint8  = 1
	SizeUint16 = 2
	SizeUint32 = 4
	SizeUint64 = 8
	SizeEnum   = 2
	SizeSingle = 4
	SizeDouble = 8
	SizePtr    = 4
)

Byte sizes of primitive types

View Source
const (
	TagEncapsulated = "encapsulated"
	TagUnionTag     = "unionTag"
	TagUnionField   = "unionField"
)

Union related constants such as struct tag values

Variables

This section is empty.

Functions

This section is empty.

Types

type CommonHeader

type CommonHeader struct {
	Version             uint8
	Endianness          binary.ByteOrder
	CharacterEncoding   uint8
	FloatRepresentation uint8
	HeaderLength        uint16
	Filler              []byte
}

CommonHeader implements the NDR common header: https://msdn.microsoft.com/en-us/library/cc243889.aspx

type Decoder

type Decoder struct {
	// contains filtered or unexported fields
}

Decoder unmarshals NDR byte stream data into a Go struct representation

func NewDecoder

func NewDecoder(r io.Reader, includeHeader bool) *Decoder

NewDecoder creates a new instance of a NDR Decoder.

func (*Decoder) Decode

func (dec *Decoder) Decode(s interface{}) error

Decode unmarshals the NDR encoded bytes into the pointer of a struct provided.

func (*Decoder) SetEndianness

func (dec *Decoder) SetEndianness(order binary.ByteOrder)

type Encoder

type Encoder struct {
	// contains filtered or unexported fields
}

Decoder unmarshals NDR byte stream data into a Go struct representation

func NewEncoder

func NewEncoder(w *bytes.Buffer, includeHeaders bool) *Encoder

NewDecoder creates a new instance of a NDR Decoder.

func (*Encoder) Encode

func (enc *Encoder) Encode(s interface{}) (buf []byte, err error)

Encode marshals the provided structure into NDR encoded bytes.

func (*Encoder) GetBytes

func (enc *Encoder) GetBytes() []byte

func (*Encoder) SetEndianness

func (enc *Encoder) SetEndianness(order binary.ByteOrder)

func (*Encoder) ToUnicode

func (enc *Encoder) ToUnicode(input string) []byte

type Malformed

type Malformed struct {
	EText string
}

Malformed implements the error interface for malformed NDR encoding errors.

func Errorf

func Errorf(format string, a ...interface{}) Malformed

Errorf formats an error message into a malformed NDR error.

func (Malformed) Error

func (e Malformed) Error() string

Error implements the error interface on the Malformed struct.

type PrivateHeader

type PrivateHeader struct {
	ObjectBufferLength uint32
	Filler             []byte
}

PrivateHeader implements the NDR private header: https://msdn.microsoft.com/en-us/library/cc243919.aspx

type RawBytes

type RawBytes interface {
	Size(interface{}) int
}

RawBytes interface should be implemented if reading just a number of bytes from the NDR stream

type Union

type Union interface {
	SwitchFunc(t interface{}) string
}

Union interface must be implemented by structs that will be unmarshaled into from the NDR byte stream union representation. The union's discriminating tag will be passed to the SwitchFunc method. The discriminating tag field must have the struct tag: `ndr:"unionTag"` If the union is encapsulated the discriminating tag field must have the struct tag: `ndr:"encapsulated"` The possible value fields that can be selected from must have the struct tag: `ndr:"unionField"`

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL