Generated from Manticore v1.1.6 • 388 packages. View on pkg.go.dev

nbdgm

import "github.com/TheManticoreProject/Manticore/network/netbios/nbdgm"

Package nbdgm implements the NetBIOS Datagram Service (RFC 1002 4.4, UDP port 138): the datagram header codec, the DIRECT_UNIQUE / DIRECT_GROUP / BROADCAST datagrams, the DATAGRAM ERROR packet, the DATAGRAM QUERY REQUEST and POSITIVE / NEGATIVE DATAGRAM QUERY RESPONSE packets, and FIRST/MORE fragmentation and reassembly of the USER_DATA payload.

This is the connectionless transport that the Browser protocol and mailslots ride on top of; only the datagram transport layer lives here. The NetBIOS name encoding for the SOURCE_NAME / DESTINATION_NAME fields is reused from the sibling name-service package (network/netbios/nbns).

Index

Constants

Datagram MSG_TYPE values (RFC 1002 4.4.1). The message type is the first byte of every datagram and selects both the semantics and the trailer layout.

const (
    MsgTypeDirectUnique          uint8 = 0x10 // DIRECT_UNIQUE DATAGRAM
    MsgTypeDirectGroup           uint8 = 0x11 // DIRECT_GROUP DATAGRAM
    MsgTypeBroadcast             uint8 = 0x12 // BROADCAST DATAGRAM
    MsgTypeError                 uint8 = 0x13 // DATAGRAM ERROR
    MsgTypeQueryRequest          uint8 = 0x14 // DATAGRAM QUERY REQUEST
    MsgTypePositiveQueryResponse uint8 = 0x15 // DATAGRAM POSITIVE QUERY RESPONSE
    MsgTypeNegativeQueryResponse uint8 = 0x16 // DATAGRAM NEGATIVE QUERY RESPONSE
)

FLAGS field bit layout (RFC 1002 4.4.1). The one-byte FLAGS field is drawn in the RFC as

0   1   2   3   4   5   6   7
+---+---+---+---+---+---+---+---+
| 0 | 0 | 0 | 0 |  SNT  | F | M |
+---+---+---+---+---+---+---+---+

where bit 0 is the most-significant bit. In terms of the numeric byte value M (MORE) is therefore the least-significant bit (0x01), F (FIRST) is 0x02, and SNT (source end-node type) occupies bits 2-3 (mask 0x0C).

const (
    FlagMore  uint8 = 0x01 // M: set when more fragments of this datagram follow
    FlagFirst uint8 = 0x02 // F: set on the first (or only) fragment of a datagram

)

SNT source end-node type values carried in the FLAGS field (RFC 1002 4.4.1).

const (
    NodeTypeB    uint8 = 0x00 // B node (broadcast)
    NodeTypeP    uint8 = 0x01 // P node (point-to-point)
    NodeTypeM    uint8 = 0x02 // M node (mixed)
    NodeTypeNBDD uint8 = 0x03 // NetBIOS Datagram Distribution server
)

DATAGRAM ERROR ERROR_CODE values (RFC 1002 4.4.2).

const (
    ErrorDestinationNameNotPresent uint8 = 0x82 // DESTINATION NAME NOT PRESENT
    ErrorInvalidSourceNameFormat   uint8 = 0x83 // INVALID SOURCE NAME FORMAT
    ErrorInvalidDestNameFormat     uint8 = 0x84 // INVALID DESTINATION NAME FORMAT
)

Listener socket timeouts and buffer size. MaxUDPSize is the RFC 1001 minimum reassembly buffer, the largest single UDP datagram a conforming datagram service must accept; larger logical datagrams arrive fragmented.

const (
    UDPReadTimeout = 5 * time.Second
    MaxUDPSize     = 576
)

Reassembly bounds. The datagram service fragments a datagram whose names plus USER_DATA do not fit in a single UDP packet (RFC 1002 4.4.1); a receiver reassembles the pieces keyed by (source, DGM_ID). These constants bound the memory and lifetime of the reassembly state so a hostile or lossy sender cannot exhaust memory with partial datagrams.

const (
    // MaxUserDataSize caps the reassembled USER_DATA of a single datagram. A
    // DGM_ID whose fragments would exceed it is dropped.
    MaxUserDataSize = 65535

    // DefaultReassemblyTimeout is how long an incomplete datagram is retained
    // before its fragments are discarded.
    DefaultReassemblyTimeout = 30 * time.Second

    // DefaultMaxPending bounds the number of distinct in-progress datagrams held
    // at once. Once reached, a new datagram is only admitted after expired
    // entries are evicted.
    DefaultMaxPending = 1024
)

DefaultDatagramPort is the well-known UDP port of the NetBIOS Datagram Service (RFC 1002 4.4 / RFC 1001 5.4). All datagrams are exchanged on it.

const DefaultDatagramPort = 138

DefaultMaxFragmentSize is the maximum size of a single outbound UDP datagram (header plus trailer) when the sender fragments an oversized USER_DATA. It is the RFC 1001 minimum reassembly buffer size (576), which every conforming receiver must accept.

const DefaultMaxFragmentSize = 576

LimitedBroadcastAddr is the IPv4 limited-broadcast address a BROADCAST datagram is sent to (RFC 1002 5.4). With DefaultDatagramPort it forms the destination 255.255.255.255:138.

const LimitedBroadcastAddr = "255.255.255.255"

type Datagram

Datagram is a decoded NetBIOS datagram. Which trailer fields are meaningful depends on MsgType: the DIRECT/BROADCAST types carry DgmLength, PacketOffset, SourceName, DestinationName and UserData; DATAGRAM ERROR carries ErrorCode; the query request/response types carry only DestinationName.

type Datagram struct {
    MsgType    uint8
    Flags      uint8
    DgmID      uint16
    SourceIP   net.IP
    SourcePort uint16

    // DIRECT_UNIQUE / DIRECT_GROUP / BROADCAST fields.
    DgmLength       uint16 // length of the trailer (names + user data) in this packet
    PacketOffset    uint16 // offset of this fragment's USER_DATA in the reassembled datagram
    SourceName      Name
    DestinationName Name
    UserData        []byte

    // DATAGRAM ERROR field.
    ErrorCode uint8
}

func (*Datagram) HasMore

func (d *Datagram) HasMore() bool

HasMore reports whether the MORE (M) flag is set, i.e. further fragments of this datagram follow.

func (*Datagram) IsFirst

func (d *Datagram) IsFirst() bool

IsFirst reports whether the FIRST (F) flag is set.

func (*Datagram) Marshal

func (d *Datagram) Marshal() ([]byte, error)

Marshal serialises the datagram to its RFC 1002 4.4 wire form. For the DIRECT/BROADCAST types the DGM_LENGTH field is computed as the length of the emitted trailer (names, when the FIRST flag is set, plus USER_DATA), matching how a receiver validates it; the caller-supplied DgmLength is ignored.

func (*Datagram) NodeType

func (d *Datagram) NodeType() uint8

NodeType returns the SNT source end-node type encoded in the FLAGS field.

func (*Datagram) SetNodeType

func (d *Datagram) SetNodeType(nt uint8)

SetNodeType sets the SNT source end-node type bits of the FLAGS field.

func (*Datagram) Unmarshal

func (d *Datagram) Unmarshal(data []byte) (int, error)

Unmarshal parses a datagram from data and returns the number of bytes consumed. It never panics on short or malformed input, reporting an error instead. For a DIRECT/BROADCAST datagram only the DGM_LENGTH trailer bytes are consumed, so trailing padding in an oversized buffer is ignored.

type DatagramHandler

DatagramHandler is invoked for each fully received datagram. For the DIRECT/BROADCAST types the datagram is delivered only once fully reassembled, with the complete USER_DATA and decoded SOURCE_NAME/DESTINATION_NAME; the query request/response and error types are delivered as they arrive. source is the sender’s UDP address.

type DatagramHandler func(source *net.UDPAddr, d *Datagram)

type Listener

Listener receives NetBIOS datagrams on a UDP socket (port 138 by default), reassembles fragmented DIRECT/BROADCAST datagrams, and hands each complete datagram to a callback. It mirrors the nbns UDP server: Start spawns a serve goroutine and Stop shuts it down. A Listener is the inbound counterpart to Sender.

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

func NewListener

func NewListener(addr string, handler DatagramHandler) (*Listener, error)

NewListener creates a datagram Listener bound to addr (e.g. “:138” or “127.0.0.1:0” for an ephemeral port) that delivers received datagrams to handler.

func (*Listener) LocalAddr

func (l *Listener) LocalAddr() *net.UDPAddr

LocalAddr returns the address the listener is bound to, useful when it was started on an ephemeral port ("…:0").

func (*Listener) Start

func (l *Listener) Start() error

Start begins listening for datagrams.

func (*Listener) Stop

func (l *Listener) Stop()

Stop gracefully shuts down the listener.

type Name

Name is a NetBIOS name as carried in a datagram SOURCE_NAME or DESTINATION_NAME field: the up-to-15-character base name, the one-byte service suffix (the 16th byte of the padded NetBIOS name), and an optional scope. On the wire it is the RFC 1002 4.2.1.2 second-level encoding.

type Name struct {
    Name   string // base name, up to 15 characters (may be the "*" wildcard)
    Suffix byte   // service suffix (16th byte of the padded NetBIOS name)
    Scope  string // optional NetBIOS scope ID, dot-separated ("" for the default)
}

type Reassembler

Reassembler reassembles fragmented NetBIOS datagrams. It is safe for concurrent use; a single Reassembler is shared by a Listener across the goroutines that handle inbound packets.

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

func NewReassembler

func NewReassembler() *Reassembler

NewReassembler returns a Reassembler using the default timeout.

func (*Reassembler) Add

func (r *Reassembler) Add(source string, d *Datagram) (assembled *Datagram, done bool, err error)

Add feeds one received DIRECT/BROADCAST datagram fragment into the reassembler. source identifies the sender (typically its “ip:port”). When the datagram is complete it returns the fully reassembled Datagram and done=true; otherwise it returns done=false and retains the fragment. A datagram that is both FIRST and not MORE is complete in a single packet and is returned directly without any retained state.

func (*Reassembler) SetTimeout

func (r *Reassembler) SetTimeout(d time.Duration)

SetTimeout overrides the retention time for incomplete datagrams. A non-positive value restores the default.

type Sender

Sender emits NetBIOS datagrams. It carries the source identity stamped into every datagram’s header (SOURCE_NAME, SOURCE_IP, SOURCE_PORT and the SNT node type) and fragments a USER_DATA payload too large for a single UDP datagram. A Sender is a lightweight value: each send opens its own short-lived UDP socket, so one Sender is safe to reuse across sequential sends.

type Sender struct {
    // SourceName is the sending application's NetBIOS name, carried as the
    // SOURCE_NAME of DIRECT/BROADCAST datagrams.
    SourceName Name

    // SourceIP and SourcePort populate the datagram header's SOURCE_IP and
    // SOURCE_PORT. SourceIP must be an IPv4 address. SourcePort is typically
    // DefaultDatagramPort.
    SourceIP   net.IP
    SourcePort uint16

    // NodeType is the SNT source end-node type stamped into the FLAGS field
    // (NodeTypeB by default).
    NodeType uint8

    // MaxFragmentSize bounds the size of each emitted UDP datagram. A
    // non-positive value uses DefaultMaxFragmentSize.
    MaxFragmentSize int
}

func (*Sender) Fragment

func (s *Sender) Fragment(msgType uint8, destName Name, userData []byte) ([][]byte, error)

Fragment builds the wire-form UDP payloads for a DIRECT/BROADCAST datagram, splitting userData across as many packets as the per-packet size limit requires. The first fragment carries SOURCE_NAME and DESTINATION_NAME and the FIRST flag; every fragment but the last sets the MORE flag; PACKET_OFFSET on each fragment is the byte offset of its USER_DATA within the whole payload. All fragments share one freshly generated DGM_ID.

func (*Sender) SendBroadcast

func (s *Sender) SendBroadcast(destName Name, userData []byte) error

SendBroadcast sends a BROADCAST datagram carrying userData to the IPv4 limited-broadcast address on port 138. userData is fragmented as needed.

func (*Sender) SendDirectGroup

func (s *Sender) SendDirectGroup(dest string, destName Name, userData []byte) error

SendDirectGroup sends a DIRECT_GROUP datagram carrying userData to dest (see SendDirectUnique for the dest and fragmentation semantics).

func (*Sender) SendDirectUnique

func (s *Sender) SendDirectUnique(dest string, destName Name, userData []byte) error

SendDirectUnique sends a DIRECT_UNIQUE datagram carrying userData to dest, which may be a bare host or host:port (the port defaults to 138). userData is fragmented across as many UDP datagrams as needed.