proto

package
v0.2.2 Latest Latest
Warning

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

Go to latest
Published: Jul 30, 2026 License: MIT Imports: 5 Imported by: 0

Documentation

Overview

Package proto implements the clamd wire protocol primitives: z-format command encoding, INSTREAM chunk framing, and response parsing.

The package is transport-agnostic: it operates on io.Reader/io.Writer and leaves connection management, deadlines, and context handling to the caller.

Index

Constants

View Source
const (

	// MaxChunkSize is a sanity cap for the INSTREAM chunk size. Chunk
	// lengths are encoded as uint32, but allowing arbitrarily large chunks
	// would only waste memory without improving throughput.
	MaxChunkSize = 16 << 20 // 16 MiB

	// DefaultChunkSize is used when the caller passes a non-positive chunk
	// size. Callers are expected to validate configuration upfront; this is
	// a defensive fallback only.
	DefaultChunkSize = 32 << 10 // 32 KiB
)
View Source
const (
	// MaxLineResponse bounds single-line responses (scan verdicts, PONG,
	// VERSION, ...). A hostile or broken server cannot make us buffer more.
	MaxLineResponse = 4 << 10 // 4 KiB

	// MaxBlockResponse bounds multi-line responses (STATS).
	MaxBlockResponse = 1 << 20 // 1 MiB
)

Variables

View Source
var ErrMalformedReply = errors.New("multi-line reply to a single-line command")

ErrMalformedReply indicates a multi-line reply to a command that must produce a single line. All commands are sent in z form, so a reply is one NUL-terminated unit; content with embedded newlines cannot be classified safely (a hostile "stream: <sig> FOUND\nstream: OK" must not be judged by either single line) and is treated as a protocol violation.

View Source
var ErrResponseTooLarge = errors.New("response exceeds read limit")

ErrResponseTooLarge indicates the server sent a response exceeding the read limit. Treated as a protocol violation (fail-closed).

View Source
var ErrSizeLimitExceeded = errors.New("stream size limit exceeded")

ErrSizeLimitExceeded is returned by StreamAll when the source would exceed the configured byte limit. The chunk that would cross the limit is not written to the sink.

Functions

func EncodeCommand

func EncodeCommand(name string) []byte

EncodeCommand returns the z-format (NUL-terminated) encoding of a clamd command, e.g. EncodeCommand("PING") == "zPING\x00". The z form is used for every command so that responses are unambiguously NUL-delimited.

func ReadBlock

func ReadBlock(br *bufio.Reader, max int) (string, error)

ReadBlock reads a multi-line response (STATS) terminated by NUL or EOF, up to max bytes. Newlines are preserved as part of the content.

func ReadLine

func ReadLine(br *bufio.Reader, max int) (string, error)

ReadLine reads a single-line response terminated by NUL (z-format), up to max bytes of content. Trailing '\r' and '\n' are trimmed, but an embedded newline fails with ErrMalformedReply. EOF after at least one byte returns the data read so far (clamd may close the connection right after replying); EOF with no data is returned as io.EOF so callers can classify "closed without response".

func StreamAll

func StreamAll(w io.Writer, r io.Reader, chunkSize int, maxBytes int64) (int64, error)

StreamAll reads r to EOF and writes it to w as INSTREAM chunks: a 4-byte big-endian length prefix followed by the payload, terminated by a zero-length chunk. It returns the number of payload bytes written.

maxBytes limits the payload size; a negative value means unlimited. When the source would exceed maxBytes, StreamAll stops before writing the offending chunk and returns ErrSizeLimitExceeded, so no truncated payload is ever presented to clamd as a complete stream.

Read failures are wrapped in *SourceError, write failures in *SinkError. On any error the zero-length terminator is NOT written; the caller must close the connection so clamd cannot treat a partial stream as complete.

Types

type Outcome

type Outcome uint8

Outcome classifies a scan response. The zero value is OutcomeUnknown so that an unhandled or malformed response can never read as "clean".

const (
	OutcomeUnknown Outcome = iota
	OutcomeClean
	OutcomeInfected
	OutcomeError
)

type ScanResponse

type ScanResponse struct {
	Outcome   Outcome
	Signature string // set when Outcome == OutcomeInfected
	Message   string // ERROR message (Outcome == OutcomeError) or raw line (OutcomeUnknown)
	SizeLimit bool   // true when the ERROR indicates a size limit violation
}

ScanResponse is the parsed form of a scan verdict line.

func ParseScanResponse

func ParseScanResponse(line string) ScanResponse

ParseScanResponse classifies a single scan response line.

The parser is deliberately prefix-agnostic: clamd historically used different reply prefixes ("stream: ...", "instream (local): ...", or a file path for path-based scans), so classification relies on the reply suffix only:

"<prefix>: <signature> FOUND"     -> OutcomeInfected
"<message> ERROR"                 -> OutcomeError
"OK" or "<stream prefix>: OK"     -> OutcomeClean
anything else                     -> OutcomeUnknown (fail-closed)

FOUND is checked before ERROR and OK: when a response is ambiguous the parser must never prefer the more permissive classification. Signature names may contain spaces; only the final " FOUND" token is stripped.

type SinkError

type SinkError struct {
	Err error
}

SinkError wraps a failure to write to clamd. Callers should attempt to read a pending ERROR response after observing a SinkError, because clamd replies and closes the connection when a stream exceeds StreamMaxLength.

func (*SinkError) Error

func (e *SinkError) Error() string

func (*SinkError) Unwrap

func (e *SinkError) Unwrap() error

type SourceError

type SourceError struct {
	Err error
}

SourceError wraps a failure to read from the caller-supplied data source (e.g. the io.Reader passed to Scan). It never indicates a clamd problem.

func (*SourceError) Error

func (e *SourceError) Error() string

func (*SourceError) Unwrap

func (e *SourceError) Unwrap() error

Jump to

Keyboard shortcuts

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