Documentation
¶
Overview ¶
Package tpkt implements TPKT framing as defined by RFC 1006.
TPKT is a simple header + payload packetization scheme used to carry ISO transport protocol data units (TPDUs) over a TCP byte stream. Each packet starts with a 4-byte header:
- byte 0: version (always 3 for this version of the protocol)
- byte 1: reserved (always 0)
- bytes 2–3: total packet length in octets, big-endian, including header
This package is intentionally limited to TPKT framing only. It does not interpret or construct TPDUs and it does not implement:
- COTP or CR/CC/DT TPDU semantics
- TSAP addressing or ISO session/presentation
- S7comm, MMS, or other application protocols
Callers are expected to build higher-level protocol stacks on top of the payload bytes returned by Decode, Parse, and Reader.ReadFrame, and to send payload bytes using Writer.WriteFrame.
The implementation follows RFC 1006 section 6 (Packet Format) and enforces:
- version == 3
- reserved == 0
- total length field within the legal range [7, 65535]
- consistency between the declared length and the actual buffer size
A total length of 7 bytes corresponds to a 4-byte TPKT header plus a 3-byte minimum TPDU for transport class 0. Frames declaring a length smaller than 7 (including a 4-byte header with no TPDU bytes) are rejected.
Validation and payload ownership:
- Decode and Parse validate packets against protocol structure only (version, reserved, length, and buffer consistency). They do not apply any additional caller-configurable maximum frame size.
- Reader.ReadFrame applies the same structural checks and also enforces a configurable maximum total packet size before allocating payload memory.
- Decode and Parse: the returned payload aliases the input buffer.
- Reader.ReadFrame: the returned slice is a newly allocated payload.
Reader and Writer are not safe for concurrent use from multiple goroutines without external synchronization.
Index ¶
Examples ¶
Constants ¶
const ( MinPacketLength = rfcMinPacketLength MaxPacketLength = rfcMaxPacketLength )
Exported protocol size bounds for callers that want to configure buffers or validation in terms of on-the-wire TPKT sizes.
const HeaderLength = 4
HeaderLength is the length in octets of the fixed TPKT header.
const Version byte = 3
Version is the TPKT protocol version supported by this package. RFC 1006 defines this value as 3.
Variables ¶
var ( // ErrTooShort indicates that a buffer is shorter than the 4-byte TPKT header. ErrTooShort = errors.New("tpkt: packet too short") // ErrInvalidVersion indicates a header with a version byte other than 3. ErrInvalidVersion = errors.New("tpkt: invalid version") // ErrInvalidReserved indicates a header with a non-zero reserved byte. ErrInvalidReserved = errors.New("tpkt: invalid reserved byte") // ErrInvalidLength indicates that the declared TPKT length is outside // the legal range or otherwise structurally invalid. ErrInvalidLength = errors.New("tpkt: invalid length field") // ErrLengthMismatch indicates that the declared TPKT length does not // match the actual size of the buffer. ErrLengthMismatch = errors.New("tpkt: length field does not match buffer size") // ErrFrameTooLarge indicates that a frame exceeds a configured or // protocol-defined maximum size. ErrFrameTooLarge = errors.New("tpkt: frame exceeds maximum allowed size") )
Exported sentinel errors. Callers should use errors.Is to classify failures.
Functions ¶
func Decode ¶
Decode validates a complete TPKT packet and returns only the payload.
The returned slice aliases pkt; callers must copy it if they need to retain it independently.
Example ¶
// A minimal valid TPKT packet: version=3, reserved=0, length=7, 3-byte payload.
pkt := []byte{0x03, 0x00, 0x00, 0x07, 0x01, 0x02, 0x03}
decoded, err := tpkt.Decode(pkt)
if err != nil {
panic(err)
}
fmt.Println(decoded)
Output: [1 2 3]
func Encode ¶
Encode builds a complete TPKT packet from the provided payload.
The returned slice contains the 4-byte TPKT header followed by the payload. The header is constructed according to RFC 1006 section 6.
Example ¶
payload := []byte{0x02, 0xf0, 0x80}
pkt, err := tpkt.Encode(payload)
if err != nil {
panic(err)
}
// Inspect header fields of the encoded packet.
version := pkt[0]
reserved := pkt[1]
length := int(binary.BigEndian.Uint16(pkt[2:4]))
fmt.Println(version, reserved, length == len(pkt))
Output: 3 0 true
Types ¶
type Frame ¶
type Frame struct {
Payload []byte
}
Frame represents a single TPKT-framed TPDU.
The Payload is treated as an opaque sequence of bytes by this package; higher level protocols (e.g. COTP, S7, MMS) are expected to interpret it. A Frame value by itself does not guarantee RFC 1006 validity: payloads that are too short or too large will be rejected when marshaled or encoded.
func Parse ¶
Parse validates a complete TPKT packet and returns a Frame.
The returned Frame.Payload aliases pkt; callers must copy it if they need to retain it independently.
func (Frame) Len ¶
Len reports HeaderLength + len(Payload), i.e. the total length the frame would occupy on the wire if encodable.
func (Frame) MarshalBinary ¶
MarshalBinary encodes the Frame into a complete TPKT packet.
The returned slice is a newly allocated buffer. If the encoded packet would be smaller than MinPacketLength or larger than MaxPacketLength, an error is returned.
type Reader ¶
type Reader struct {
// contains filtered or unexported fields
}
Reader reads TPKT-framed payloads from an underlying io.Reader.
It is safe for use with any streaming source such as a net.Conn. Reader is not safe for concurrent use from multiple goroutines without external synchronization.
func NewReader ¶
func NewReader(r io.Reader, opts ...ReaderOption) *Reader
NewReader constructs a Reader over r.
By default it accepts packets up to the RFC 1006 maximum. WithMaxFrameSize can be used to impose a stricter bound.
func (*Reader) ReadFrame ¶
ReadFrame reads the next TPKT frame from the stream and returns its payload.
It returns io.EOF when called at a frame boundary and the underlying reader has no more data. If the stream ends in the middle of a header or payload, it returns an error wrapping io.ErrUnexpectedEOF.
Example ¶
payload := []byte{0x01, 0x02, 0x03}
pkt, _ := tpkt.Encode(payload)
r := tpkt.NewReader(bytes.NewReader(pkt))
got, err := r.ReadFrame()
if err != nil {
panic(err)
}
fmt.Println(bytes.Equal(got, payload))
Output: true
type ReaderOption ¶
type ReaderOption func(*Reader)
ReaderOption configures a Reader.
func WithMaxFrameSize ¶
func WithMaxFrameSize(n int) ReaderOption
WithMaxFrameSize sets an upper bound on the total TPKT packet size (header plus payload) that the Reader will accept.
Values less than or equal to zero leave the default in place. Values greater than zero but smaller than MinPacketLength are clamped up to MinPacketLength.
type Writer ¶
type Writer struct {
// contains filtered or unexported fields
}
Writer writes payloads as TPKT-framed packets to an underlying io.Writer. It currently exposes only the WriteFrame helper; callers that wish to send a Frame should pass f.Payload explicitly. Writer is not safe for concurrent use from multiple goroutines without external synchronization.
func (*Writer) WriteFrame ¶
WriteFrame encodes payload as a TPKT packet and writes it in full.
It returns the total number of octets written (header plus payload). If the underlying writer performs a short write or returns an error, WriteFrame returns a non-nil error.
Example ¶
var buf bytes.Buffer
w := tpkt.NewWriter(&buf)
payload := []byte{0x01, 0x02, 0x03}
if _, err := w.WriteFrame(payload); err != nil {
panic(err)
}
expected, _ := tpkt.Encode(payload)
ok := bytes.Equal(buf.Bytes(), expected)
fmt.Println(ok)
Output: true