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 ¶
- type ByteHandler
- type DNSError
- type DNSLookupRequest
- type DNSLookupResponse
- type DNSOption
- type ErrorResponse
- type ExecCommandRequest
- type ExecCommandResponse
- type ExecError
- type ExecOption
- type HTTPError
- type HTTPOption
- type HTTPRequest
- type HTTPResponse
- type HandlerRegistry
- type HostContext
- type HostFunc
- type HostFuncBundle
- type MXRecord
- type Middleware
- type NetfilterOption
- func WithAllowedPorts(ports ...int) NetfilterOption
- func WithAllowlist(addresses ...string) NetfilterOption
- func WithBlockLinkLocal(block bool) NetfilterOption
- func WithBlockLocalhost(block bool) NetfilterOption
- func WithBlockPrivate(block bool) NetfilterOption
- func WithBlockedPorts(ports ...int) NetfilterOption
- func WithBlocklist(addresses ...string) NetfilterOption
- func WithResolveDNS(resolve bool) NetfilterOption
- type NetfilterResult
- type RegistryOption
- type SMTPConnectRequest
- type SMTPConnectResponse
- type SMTPError
- type SMTPOption
- type SSRFCheckRequest
- type SSRFCheckResponse
- type TCPConnectRequest
- type TCPConnectResponse
- type TCPError
- type TCPOption
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type ByteHandler ¶
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 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 ¶
WithDNSLookupTimeout sets the DNS query timeout.
func WithDNSNameserver ¶
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 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 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 ¶
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 ¶
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 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 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)
}