hostfuncs

package
v0.2.0 Latest Latest
Warning

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

Go to latest
Published: Jan 25, 2026 License: Apache-2.0 Imports: 14 Imported by: 0

Documentation

Overview

Package hostfuncs provides pure Go implementations of host function logic. These implementations have NO WASM runtime dependencies (no wazero/wasmtime). They can be used by any WASM plugin host, not just Reglet.

The implementations are designed to be thin wrappers that consuming applications (like Reglet) can call from their WASM host function handlers. The SDK handles the core logic; the host handles wire format encoding/decoding and memory management.

Package hostfuncs provides pure Go implementations of host function logic. These implementations have NO WASM runtime dependencies (no wazero/wasmtime). They can be used by any WASM plugin host, not just Reglet.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type ByteHandler

type ByteHandler func(context.Context, []byte) ([]byte, error)

ByteHandler is a function that accepts raw bytes (JSON) and returns raw bytes (JSON). This is the common interface that WASM runtimes can easily use.

func NewJSONHandler

func NewJSONHandler[Req any, Resp any](fn HostFunc[Req, Resp]) ByteHandler

NewJSONHandler wraps a typed HostFunc into a ByteHandler. It handles the JSON unmarshalling of the request and marshaling of the response.

For infrastructure failures (malformed JSON, serialization errors), the handler returns a structured ErrorResponse JSON instead of a Go error. This ensures plugins always receive valid JSON and prevents WASM runtime traps.

Usage:

execHandler := hostfuncs.NewJSONHandler(func(ctx context.Context, req hostfuncs.ExecCommandRequest) hostfuncs.ExecCommandResponse {
    return hostfuncs.PerformExecCommand(ctx, req)
})

// In WASM runtime handler:
reqBytes := readMemory(ptr, len)
respBytes, err := execHandler(ctx, reqBytes)
writeMemory(respBytes)

type DNSError

type DNSError struct {
	Code    string `json:"code"`
	Message string `json:"message"`
}

DNSError represents a DNS lookup error.

func (*DNSError) Error

func (e *DNSError) Error() string

Error implements the error interface.

type DNSLookupRequest

type DNSLookupRequest struct {
	// Hostname is the domain name to resolve.
	Hostname string `json:"hostname"`

	// RecordType is the DNS record type (A, AAAA, CNAME, MX, TXT, NS).
	RecordType string `json:"type"`

	// Nameserver is the optional custom nameserver address (e.g., "8.8.8.8:53").
	// If empty, the system default resolver is used.
	Nameserver string `json:"nameserver,omitempty"`

	// Timeout is the query timeout in milliseconds. Default is 5000 (5s).
	Timeout int `json:"timeout_ms,omitempty"`
}

DNSLookupRequest contains parameters for a DNS lookup operation.

type DNSLookupResponse

type DNSLookupResponse struct {
	// Error contains error information if the lookup failed.
	Error *DNSError `json:"error,omitempty"`

	// Records contains the resolved records (IP addresses, strings, etc.).
	Records []string `json:"records,omitempty"`

	// MXRecords contains MX-specific records with preference values.
	MXRecords []MXRecord `json:"mx_records,omitempty"`
}

DNSLookupResponse contains the result of a DNS lookup operation.

func PerformDNSLookup

func PerformDNSLookup(ctx context.Context, req DNSLookupRequest, opts ...DNSOption) DNSLookupResponse

PerformDNSLookup performs a DNS lookup for the given request. This is a pure Go implementation with no WASM runtime dependencies.

Example usage from a WASM host:

func handleDNSLookup(req hostfuncs.DNSLookupRequest) hostfuncs.DNSLookupResponse {
    return hostfuncs.PerformDNSLookup(ctx, req)
}

type DNSOption

type DNSOption func(*dnsConfig)

DNSOption is a functional option for configuring DNS lookup behavior.

func WithDNSLookupTimeout

func WithDNSLookupTimeout(d time.Duration) DNSOption

WithDNSLookupTimeout sets the DNS query timeout.

func WithDNSNameserver

func WithDNSNameserver(ns string) DNSOption

WithDNSNameserver sets a custom nameserver for the lookup.

type ErrorResponse

type ErrorResponse struct {
	// Error is a machine-readable error type identifier (e.g., "VALIDATION_ERROR", "INTERNAL_ERROR").
	Error string `json:"error"`

	// Message is a human-readable error description.
	Message string `json:"message"`

	// Code is a numeric error code (e.g., 400, 500).
	Code int `json:"code"`
}

ErrorResponse represents a structured error that can be returned as JSON to plugins. This ensures plugins receive consistent, parseable errors instead of causing WASM traps.

func NewInternalError

func NewInternalError(message string) ErrorResponse

NewInternalError creates an error response for unexpected failures.

func NewNotFoundError

func NewNotFoundError(name string) ErrorResponse

NewNotFoundError creates an error response for unknown handler names.

func NewPanicError

func NewPanicError(panicValue any) ErrorResponse

NewPanicError creates an error response for recovered panics.

func NewValidationError

func NewValidationError(message string) ErrorResponse

NewValidationError creates an error response for bad input (e.g., malformed JSON).

func (ErrorResponse) ToJSON

func (e ErrorResponse) ToJSON() []byte

ToJSON serializes the ErrorResponse to JSON bytes. Returns nil if serialization fails (which should never happen for this simple type).

type ExecCommandRequest

type ExecCommandRequest struct {
	// Command is the command to execute.
	Command string `json:"command"`

	// Args contains command arguments.
	Args []string `json:"args"`

	// Dir is the working directory.
	Dir string `json:"dir,omitempty"`

	// Env contains environment variables (KEY=VALUE).
	Env []string `json:"env,omitempty"`

	// Timeout is the execution timeout in milliseconds. Default is 30000 (30s).
	Timeout int `json:"timeout_ms,omitempty"`
}

ExecCommandRequest contains parameters for a command execution.

type ExecCommandResponse

type ExecCommandResponse struct {
	// Error contains error information if execution failed to start.
	Error *ExecError `json:"error,omitempty"`

	// Stdout is the standard output.
	Stdout string `json:"stdout"`

	// Stderr is the standard error.
	Stderr string `json:"stderr"`

	// DurationMs is the execution duration in milliseconds.
	DurationMs int64 `json:"duration_ms,omitempty"`

	// ExitCode is the exit code.
	ExitCode int `json:"exit_code"`

	// IsTimeout indicates if the command timed out.
	IsTimeout bool `json:"is_timeout,omitempty"`
}

ExecCommandResponse contains the result of a command execution.

func PerformExecCommand

func PerformExecCommand(ctx context.Context, req ExecCommandRequest, opts ...ExecOption) ExecCommandResponse

PerformExecCommand executes a command on the host. This is a pure Go implementation with no WASM runtime dependencies.

type ExecError

type ExecError struct {
	Code    string `json:"code"`
	Message string `json:"message"`
}

ExecError represents an execution error.

func (*ExecError) Error

func (e *ExecError) Error() string

Error implements the error interface.

type ExecOption

type ExecOption func(*execConfig)

ExecOption is a functional option for configuring execution behavior.

func WithExecTimeout

func WithExecTimeout(d time.Duration) ExecOption

WithExecTimeout sets the execution timeout.

type HTTPError

type HTTPError struct {
	Code    string `json:"code"`
	Message string `json:"message"`
}

HTTPError represents an HTTP request error.

func (*HTTPError) Error

func (e *HTTPError) Error() string

Error implements the error interface.

type HTTPOption

type HTTPOption func(*httpConfig)

HTTPOption is a functional option for configuring HTTP request behavior.

func WithHTTPFollowRedirects

func WithHTTPFollowRedirects(follow bool) HTTPOption

WithHTTPFollowRedirects controls whether to follow redirects.

func WithHTTPMaxBodySize

func WithHTTPMaxBodySize(size int64) HTTPOption

WithHTTPMaxBodySize sets the maximum response body size.

func WithHTTPMaxRedirects

func WithHTTPMaxRedirects(n int) HTTPOption

WithHTTPMaxRedirects sets the maximum number of redirects to follow.

func WithHTTPRequestTimeout

func WithHTTPRequestTimeout(d time.Duration) HTTPOption

WithHTTPRequestTimeout sets the HTTP request timeout.

type HTTPRequest

type HTTPRequest struct {
	// Headers contains request headers.
	Headers map[string]string `json:"headers,omitempty"`

	// FollowRedirects controls whether to follow redirects. Default is true.
	FollowRedirects *bool `json:"follow_redirects,omitempty"`

	// Method is the HTTP method (GET, POST, PUT, DELETE, etc.).
	Method string `json:"method"`

	// URL is the target URL.
	URL string `json:"url"`

	// Body is the request body (for POST, PUT, etc.).
	Body []byte `json:"body,omitempty"`

	// Timeout is the request timeout in milliseconds. Default is 30000 (30s).
	Timeout int `json:"timeout_ms,omitempty"`

	// MaxRedirects is the maximum number of redirects to follow. Default is 10.
	MaxRedirects int `json:"max_redirects,omitempty"`
}

HTTPRequest contains parameters for an HTTP request.

type HTTPResponse

type HTTPResponse struct {
	// Headers contains response headers.
	Headers map[string][]string `json:"headers,omitempty"`

	// Error contains error information if the request failed.
	Error *HTTPError `json:"error,omitempty"`

	// Body is the response body.
	Body []byte `json:"body,omitempty"`

	// StatusCode is the HTTP status code.
	StatusCode int `json:"status_code"`

	// LatencyMs is the request latency in milliseconds.
	LatencyMs int64 `json:"latency_ms,omitempty"`

	// BodyTruncated indicates if the body was truncated due to size limits.
	BodyTruncated bool `json:"body_truncated,omitempty"`
}

HTTPResponse contains the result of an HTTP request.

func PerformHTTPRequest

func PerformHTTPRequest(ctx context.Context, req HTTPRequest, opts ...HTTPOption) HTTPResponse

PerformHTTPRequest performs an HTTP request. This is a pure Go implementation with no WASM runtime dependencies.

Example usage from a WASM host:

func handleHTTPRequest(req hostfuncs.HTTPRequest) hostfuncs.HTTPResponse {
    return hostfuncs.PerformHTTPRequest(ctx, req)
}

type HandlerRegistry

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

HandlerRegistry is an immutable collection of named host functions. Once created via NewRegistry, handlers cannot be added or removed. This ensures thread safety and lock-free lookups during execution.

func NewRegistry

func NewRegistry(opts ...RegistryOption) (*HandlerRegistry, error)

NewRegistry creates an immutable HandlerRegistry with the given options. Returns an error if any handler name is registered twice.

Example usage:

registry, err := NewRegistry(
    WithMiddleware(PanicRecoveryMiddleware()),
    WithBundle(AllBundles()),
    WithHandler("custom", customHandler),
)

func (*HandlerRegistry) Has

func (r *HandlerRegistry) Has(name string) bool

Has returns true if a handler with the given name is registered.

func (*HandlerRegistry) Invoke

func (r *HandlerRegistry) Invoke(ctx context.Context, name string, payload []byte) ([]byte, error)

Invoke dispatches a host function call by name. Returns the JSON response bytes, or an ErrorResponse JSON if the handler is not found.

func (*HandlerRegistry) Names

func (r *HandlerRegistry) Names() []string

Names returns a sorted list of all registered handler names.

type HostContext

type HostContext interface {
	context.Context

	// FunctionName returns the name of the host function being invoked.
	FunctionName() string

	// SetValue stores a request-scoped value. Unlike context.WithValue,
	// this mutates the existing HostContext for performance.
	SetValue(key, value any)

	// GetValue retrieves a request-scoped value set by SetValue.
	GetValue(key any) (value any, ok bool)
}

HostContext wraps a standard context.Context with host function-specific helpers. It provides access to the invoked function name and allows middleware to store request-scoped values without polluting the standard context.

func HostContextFrom

func HostContextFrom(ctx context.Context, funcName string) HostContext

HostContextFrom extracts a HostContext from a context.Context. If the context is already a HostContext, it is returned directly. Otherwise, a new HostContext is created wrapping the given context.

func NewHostContext

func NewHostContext(ctx context.Context, funcName string) HostContext

NewHostContext creates a new HostContext wrapping the given context.

type HostFunc

type HostFunc[Req any, Resp any] func(context.Context, Req) Resp

HostFunc is a generic function signature for host functions. It accepts a context and a typed request, and returns a typed response.

type HostFuncBundle

type HostFuncBundle interface {
	// Handlers returns a map of handler names to ByteHandler functions.
	Handlers() map[string]ByteHandler
}

HostFuncBundle is a pre-configured set of related host functions. Bundles allow registering multiple handlers at once for common use cases.

func AllBundles

func AllBundles() HostFuncBundle

AllBundles returns a bundle containing all built-in host functions. Includes: dns_lookup, tcp_connect, http_request, exec_command, smtp_send, ssrf_check.

func ExecBundle

func ExecBundle() HostFuncBundle

ExecBundle returns a bundle with command execution host functions: exec_command.

func NetfilterBundle

func NetfilterBundle() HostFuncBundle

NetfilterBundle returns a bundle with network security host functions: ssrf_check.

func NetworkBundle

func NetworkBundle() HostFuncBundle

NetworkBundle returns a bundle with network-related host functions: dns_lookup, tcp_connect, http_request.

func SMTPBundle

func SMTPBundle() HostFuncBundle

SMTPBundle returns a bundle with email-related host functions: smtp_connect.

type MXRecord

type MXRecord struct {
	Host string `json:"host"`
	Pref uint16 `json:"pref"`
}

MXRecord represents a DNS MX record.

type Middleware

type Middleware func(next ByteHandler) ByteHandler

Middleware is a function that wraps a ByteHandler to add cross-cutting behavior. Middleware executes in FIFO order (first registered wraps first, onion model).

Example usage:

loggingMiddleware := func(next ByteHandler) ByteHandler {
    return func(ctx context.Context, payload []byte) ([]byte, error) {
        log.Printf("invoking handler...")
        return next(ctx, payload)
    }
}

func LoggingMiddleware

func LoggingMiddleware(logFn func(format string, args ...any)) Middleware

LoggingMiddleware returns a middleware that logs host function invocations. This is provided as an example; production code should use a structured logger.

func PanicRecoveryMiddleware

func PanicRecoveryMiddleware() Middleware

PanicRecoveryMiddleware returns a middleware that catches panics and converts them to structured ErrorResponse JSON instead of crashing the host.

type NetfilterOption

type NetfilterOption func(*netfilterConfig)

NetfilterOption is a functional option for configuring netfilter behavior.

func WithAllowedPorts

func WithAllowedPorts(ports ...int) NetfilterOption

WithAllowedPorts restricts connections to specific ports.

func WithAllowlist

func WithAllowlist(addresses ...string) NetfilterOption

WithAllowlist sets explicitly allowed addresses or CIDRs. Allowed addresses bypass all other checks.

func WithBlockLinkLocal

func WithBlockLinkLocal(block bool) NetfilterOption

WithBlockLinkLocal enables/disables blocking of link-local addresses.

func WithBlockLocalhost

func WithBlockLocalhost(block bool) NetfilterOption

WithBlockLocalhost enables/disables blocking of localhost/loopback.

func WithBlockPrivate

func WithBlockPrivate(block bool) NetfilterOption

WithBlockPrivate enables/disables blocking of RFC 1918 private addresses.

func WithBlockedPorts

func WithBlockedPorts(ports ...int) NetfilterOption

WithBlockedPorts blocks specific ports.

func WithBlocklist

func WithBlocklist(addresses ...string) NetfilterOption

WithBlocklist sets explicitly blocked addresses or CIDRs. Blocklist is checked before other rules.

func WithResolveDNS

func WithResolveDNS(resolve bool) NetfilterOption

WithResolveDNS enables/disables DNS resolution before checking.

type NetfilterResult

type NetfilterResult struct {
	// Reason provides the reason if the address was blocked.
	Reason string `json:"reason,omitempty"`

	// ResolvedIP is the resolved IP address if DNS resolution was performed.
	ResolvedIP string `json:"resolved_ip,omitempty"`

	// Allowed indicates whether the address is allowed.
	Allowed bool `json:"allowed"`
}

NetfilterResult represents the result of an address validation.

func ValidateAddress

func ValidateAddress(address string, opts ...NetfilterOption) NetfilterResult

ValidateAddress validates whether an address is allowed for outbound connections. This is the primary SSRF protection mechanism.

SECURITY CRITICAL: This function MUST be called before any outbound network connection.

Example usage:

result := hostfuncs.ValidateAddress("example.com:443")
if !result.Allowed {
    return fmt.Errorf("blocked: %s", result.Reason)
}

type RegistryOption

type RegistryOption func(*registryBuilder)

RegistryOption is a functional option for configuring a HandlerRegistry.

func WithBundle

func WithBundle(bundle HostFuncBundle) RegistryOption

WithBundle registers all handlers from a bundle.

func WithByteHandler

func WithByteHandler(name string, handler ByteHandler) RegistryOption

WithByteHandler registers a raw ByteHandler with the given name. Use WithHandler for type-safe registration with automatic JSON handling.

func WithHandler

func WithHandler[Req any, Resp any](name string, fn HostFunc[Req, Resp]) RegistryOption

WithHandler registers a typed host function with automatic JSON handling. The handler will be wrapped with NewJSONHandler for JSON serialization.

Example usage:

WithHandler("custom_func", func(ctx context.Context, req MyRequest) MyResponse {
    return MyResponse{Result: req.Input}
})

func WithMiddleware

func WithMiddleware(mw ...Middleware) RegistryOption

WithMiddleware adds middleware to the registry. Middleware executes in FIFO order (first added wraps first).

type SMTPConnectRequest

type SMTPConnectRequest struct {
	// Host is the SMTP server hostname.
	Host string `json:"host"`

	// Port is the SMTP server port (typically 25, 465, or 587).
	Port int `json:"port"`

	// UseTLS indicates whether to use implicit TLS (port 465).
	UseTLS bool `json:"use_tls,omitempty"`

	// UseSTARTTLS indicates whether to upgrade to TLS via STARTTLS (port 587).
	UseSTARTTLS bool `json:"use_starttls,omitempty"`

	// Timeout is the connection timeout in milliseconds. Default is 30000 (30s).
	Timeout int `json:"timeout_ms,omitempty"`
}

SMTPConnectRequest contains parameters for an SMTP connection test.

type SMTPConnectResponse

type SMTPConnectResponse struct {
	// Error contains error information if the connection failed.
	Error *SMTPError `json:"error,omitempty"`

	// Banner is the SMTP server banner (greeting message).
	Banner string `json:"banner,omitempty"`

	// TLSVersion is the TLS version if TLS is used.
	TLSVersion string `json:"tls_version,omitempty"`

	// LatencyMs is the connection latency in milliseconds.
	LatencyMs int64 `json:"latency_ms,omitempty"`

	// Connected indicates whether the connection was successful.
	Connected bool `json:"connected"`
}

SMTPConnectResponse contains the result of an SMTP connection test.

func PerformSMTPConnect

func PerformSMTPConnect(ctx context.Context, req SMTPConnectRequest, opts ...SMTPOption) SMTPConnectResponse

PerformSMTPConnect tests SMTP connectivity to the specified server. This is a pure Go implementation with no WASM runtime dependencies.

Example usage from a WASM host:

func handleSMTPConnect(req hostfuncs.SMTPConnectRequest) hostfuncs.SMTPConnectResponse {
    return hostfuncs.PerformSMTPConnect(ctx, req)
}

type SMTPError

type SMTPError struct {
	Code    string `json:"code"`
	Message string `json:"message"`
}

SMTPError represents an SMTP connection error.

func (*SMTPError) Error

func (e *SMTPError) Error() string

Error implements the error interface.

type SMTPOption

type SMTPOption func(*smtpConfig)

SMTPOption is a functional option for configuring SMTP connection behavior.

func WithSMTPTLSConfig

func WithSMTPTLSConfig(cfg *tls.Config) SMTPOption

WithSMTPTLSConfig sets custom TLS configuration.

func WithSMTPTimeout

func WithSMTPTimeout(d time.Duration) SMTPOption

WithSMTPTimeout sets the SMTP connection timeout.

type SSRFCheckRequest

type SSRFCheckRequest struct {
	// Address is the target address to validate (host:port format).
	Address string `json:"address"`
}

SSRFCheckRequest is the request type for SSRF validation.

type SSRFCheckResponse

type SSRFCheckResponse struct {
	// Reason explains why the address was blocked (if not allowed).
	Reason string `json:"reason,omitempty"`

	// ResolvedIP is the resolved IP address if DNS resolution was performed.
	ResolvedIP string `json:"resolved_ip,omitempty"`

	// Allowed indicates whether the address is safe for outbound connections.
	Allowed bool `json:"allowed"`
}

SSRFCheckResponse is the response type for SSRF validation.

type TCPConnectRequest

type TCPConnectRequest struct {
	// Host is the target hostname or IP address.
	Host string `json:"host"`

	// Port is the target port number.
	Port int `json:"port"`

	// Timeout is the connection timeout in milliseconds. Default is 5000 (5s).
	Timeout int `json:"timeout_ms,omitempty"`
}

TCPConnectRequest contains parameters for a TCP connection test.

type TCPConnectResponse

type TCPConnectResponse struct {
	// Error contains error information if the connection failed.
	Error *TCPError `json:"error,omitempty"`

	// RemoteAddr is the resolved remote address if connected.
	RemoteAddr string `json:"remote_addr,omitempty"`

	// LatencyMs is the connection latency in milliseconds.
	LatencyMs int64 `json:"latency_ms,omitempty"`

	// Connected indicates whether the connection was successful.
	Connected bool `json:"connected"`
}

TCPConnectResponse contains the result of a TCP connection test.

func PerformTCPConnect

func PerformTCPConnect(ctx context.Context, req TCPConnectRequest, opts ...TCPOption) TCPConnectResponse

PerformTCPConnect tests TCP connectivity to the specified host and port. This is a pure Go implementation with no WASM runtime dependencies.

Example usage from a WASM host:

func handleTCPConnect(req hostfuncs.TCPConnectRequest) hostfuncs.TCPConnectResponse {
    return hostfuncs.PerformTCPConnect(ctx, req)
}

type TCPError

type TCPError struct {
	Code    string `json:"code"`
	Message string `json:"message"`
}

TCPError represents a TCP connection error.

func (*TCPError) Error

func (e *TCPError) Error() string

Error implements the error interface.

type TCPOption

type TCPOption func(*tcpConfig)

TCPOption is a functional option for configuring TCP connection behavior.

func WithTCPTimeout

func WithTCPTimeout(d time.Duration) TCPOption

WithTCPTimeout sets the TCP connection timeout.

Jump to

Keyboard shortcuts

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