greet

package module
v1.0.4 Latest Latest
Warning

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

Go to latest
Published: Jul 11, 2026 License: MIT Imports: 9 Imported by: 0

README

Greet is a lightweight Go library to test greet / ping / handshake process in TCP, UDP and other popular protocols based on them.

Goals

  • Fast: The library only performs handshake without entering full session
  • Secure: The process ends before authentication / authorization step
  • Lightweight: The library constructs raw command from scratch and does not depend on third-party service clients
  • Tracing: The library outputs helpful errors from connection init to handshake

Playground

Try Greet directly in your browser: https://greet-playground.vercel.app/

Installation

Library

go get github.com/crystade/greet@latest

CLI

go install github.com/crystade/greet/cmd/greet@latest

Documentation

  • Core — library API, supported protocols, options, error handling, timing model, and how to add new protocols.
  • CLI — command-line usage, flags, output formats (human-readable & JSON), scripting examples.
  • JSON API — JSON request/response model, protocol-specific data schemas, and integration guide.

License

This project is licensed under the MIT License - see the LICENSE file for details.

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func ParseTarget

func ParseTarget(target string, defaultPort int) (string, int, error)

ParseTarget splits a target string into host and port. Accepted formats: "host", "host:port", "[::1]:port". If no port is specified, defaultPort is used. Port is validated to be in the range 1–65535.

Types

type AppLayer added in v1.0.3

type AppLayer interface {
	// Name returns the protocol slug (e.g. "tls", "minecraft").
	Name() string

	// Description is a one-line human-readable summary.
	Description() string

	// DefaultPort is the well-known port for this application protocol.
	DefaultPort() int

	// BaseTransport declares which transport this layer requires (tcp or udp).
	BaseTransport() Transport

	// Handshake performs the application-level exchange over conn.
	// start is the shared timing anchor owned by the engine; TTFB and TTLB
	// must be measured as time.Since(start) so timings are relative to the
	// same origin as the transport RTT and any lower app layers.
	// host and port are the original target (not the resolved IP).
	// cfg is the per-layer config retrieved via GreetConfig.LayerConfig(name).
	// Returns the (possibly upgraded) connection to pass to the next layer,
	// protocol-specific data, timing anchored from the shared start, and any error.
	// The caller (engine) owns closing the original transport conn; layers that
	// upgrade conn (e.g. TLS) must not close it — the engine's defer handles it.
	Handshake(ctx context.Context, start time.Time, conn net.Conn, host string, port int, cfg *GreetConfig) (next net.Conn, data LayerData, timing LayerTiming, err error)
}

AppLayer runs an application-level handshake over an existing connection. tls, minecraft, postgresql, ssh, http, and https implement this interface.

type DNSResult added in v1.0.2

type DNSResult struct {
	Address string        // resolved IP address
	TTDR    time.Duration // time to DNS resolved
}

DNSResult holds the outcome of DNS resolution.

func ResolveHost added in v1.0.2

func ResolveHost(ctx context.Context, host string) (*DNSResult, error)

ResolveHost resolves a hostname to an IP address and measures TTDR. If host is already an IP address, it returns immediately with TTDR ≈ 0.

type Engine added in v1.0.3

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

Engine is an isolated greet instance with its own protocol registry. Create one via NewEngine() and register protocols with RegisterTransport(), RegisterApp(), and RegisterStack().

func NewEngine added in v1.0.3

func NewEngine() *Engine

NewEngine creates a new empty Engine.

func (*Engine) Greet added in v1.0.3

func (e *Engine) Greet(ctx context.Context, protocol, target string, opts ...GreetOption) (*GreetResult, error)

Greet resolves the named protocol to its layer stack, parses the target, and executes the layered handshake engine. It is the primary entry point.

protocol is a registered name such as "tcp", "tls", "minecraft", "ssh", "postgresql", or "udp". The name implies its full stack:

  • "tls" → [tcp, tls]
  • "minecraft" → [tcp, minecraft]
  • "tcp" → [tcp]
  • "udp" → [udp]

func (*Engine) GreetStack added in v1.0.3

func (e *Engine) GreetStack(ctx context.Context, stack *Stack, host string, port int, opts ...GreetOption) *GreetResult

GreetStack executes an already-resolved Stack against host:port. Use this when you have built a Stack directly via Resolve or ResolveStack.

Execution:

  1. Dial the transport layer (DNS + TCP/UDP + RTT).
  2. For each app layer in order, run Handshake over the shared connection.
  3. On first error: mark that layer failed, abort remaining layers, set result.Error, and return.
  4. Close the connection when done.

func (*Engine) ListAll added in v1.0.3

func (e *Engine) ListAll() []LayerInfo

ListAll returns every registered transport and app layer as a flat list of (name, description, defaultPort, transport) tuples, sorted by name.

func (*Engine) ListProtocols added in v1.0.3

func (e *Engine) ListProtocols() []string

ListProtocols returns all registered protocol names (transports + app layers), sorted.

func (*Engine) RegisterApp added in v1.0.3

func (e *Engine) RegisterApp(a AppLayer)

RegisterApp adds an AppLayer to the engine's registry.

func (*Engine) RegisterStack added in v1.0.3

func (e *Engine) RegisterStack(name string, layers []string, defaultPort int, description string)

RegisterStack registers a pre-built composite stack under a given name. layers must be an ordered slice starting with a transport name followed by app-layer names (e.g. ["tcp", "tls", "http"]). defaultPort overrides the outermost layer's default port (pass 0 to use the outermost layer's port).

func (*Engine) RegisterTransport added in v1.0.3

func (e *Engine) RegisterTransport(t TransportLayer)

RegisterTransport adds a TransportLayer to the engine's registry.

func (*Engine) Resolve added in v1.0.3

func (e *Engine) Resolve(name string) (*Stack, error)

Resolve returns the execution Stack for the given protocol name. If name matches a transport (e.g. "tcp", "udp"), the stack has no app layers. If name matches an app layer (e.g. "tls", "minecraft"), the stack is [required transport] + [app layer]. If name matches a composite stack (e.g. "https"), the pre-built stack is returned.

func (*Engine) ResolveStack added in v1.0.3

func (e *Engine) ResolveStack(names []string) (*Stack, error)

ResolveStack builds a Stack from an explicit ordered list of layer names. The first name must be a transport; subsequent names must be app layers compatible with that transport.

type ErrorCode

type ErrorCode string

ErrorCode is a human-readable error category string. Code always compares against named constants; the string value is immediately readable in logs and debug prints.

const (
	ErrResolveHostFailed ErrorCode = "resolve_host_failed"
	ErrInvalidAddress    ErrorCode = "invalid_address"
	ErrUnknownProtocol   ErrorCode = "unknown_protocol"
	ErrInvalidConfig     ErrorCode = "invalid_config"
)

Common error codes shared by every protocol.

const (
	ErrConnectionRefused  ErrorCode = "connection_refused"
	ErrConnectionTimeout  ErrorCode = "connection_timeout"
	ErrConnectionReset    ErrorCode = "connection_reset"
	ErrNetworkUnreachable ErrorCode = "network_unreachable"
	ErrConnectionFailed   ErrorCode = "connection_failed"
)

Generic TCP error codes shared by all TCP-based protocols.

const (
	ErrSendFailed      ErrorCode = "send_failed"
	ErrReceiveTimeout  ErrorCode = "receive_timeout"
	ErrPortUnreachable ErrorCode = "port_unreachable"
)

func (ErrorCode) String

func (c ErrorCode) String() string

String returns the human-readable error code.

type GreetConfig

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

GreetConfig holds resolved options for a Greet call.

func ResolveOptions

func ResolveOptions(opts ...GreetOption) GreetConfig

ResolveOptions applies functional options and fills defaults.

func (*GreetConfig) LayerConfig added in v1.0.3

func (c *GreetConfig) LayerConfig(name string) LayerConfig

LayerConfig returns the per-layer config registered under name, or nil. Each layer type-asserts the result to its own config type.

func (*GreetConfig) LayerTimeout added in v1.0.3

func (c *GreetConfig) LayerTimeout(name string) time.Duration

LayerTimeout returns the per-layer timeout for the named layer, or 0 if none.

type GreetError

type GreetError struct {
	Code     ErrorCode
	Message  string
	Protocol string // protocol name; empty for common errors
	Cause    error  // underlying OS or network error
}

GreetError is the structured error type returned by all protocol implementations. It carries a machine-readable code, a human message, the originating protocol name, and the underlying OS / network error.

func (*GreetError) Error

func (e *GreetError) Error() string

Error implements the error interface.

func (*GreetError) Unwrap

func (e *GreetError) Unwrap() error

Unwrap returns the underlying cause, enabling errors.Is / errors.As chains.

type GreetOption

type GreetOption func(*GreetConfig)

GreetOption is a functional option for configuring a Greet call.

func WithLayerConfig added in v1.0.3

func WithLayerConfig(name string, cfg LayerConfig) GreetOption

WithLayerConfig attaches a typed, per-layer config value. name must match the layer's Name() return value exactly. Each layer retrieves its config via cfg.LayerConfig(name) and type-asserts it.

Example:

greet.WithLayerConfig("minecraft", &minecraft.Config{ProtocolVersion: 775})

func WithLayerTimeout added in v1.0.3

func WithLayerTimeout(name string, d time.Duration) GreetOption

WithLayerTimeout sets an independent timeout for a specific layer's handshake. This timeout is NOT capped by any global deadline — the caller controls global timeout via context.WithTimeout on the context passed to Greet/GreetStack.

type GreetResult

type GreetResult struct {
	// Protocol is the name of the outermost (application) layer, e.g. "tls".
	// For a bare TCP probe this is "tcp".
	Protocol string

	// Transport is the base transport used (tcp or udp).
	Transport Transport

	// TTDR is the time to DNS resolution, shared across all layers.
	TTDR time.Duration

	// RTT is the time to establish the transport connection.
	RTT time.Duration

	// Success is true only when every layer in the stack succeeded.
	Success bool

	// Layers contains per-layer results in stack order. Layers[0] is always the
	// base transport (tcp/udp) with TTFB = TTLB = RTT, followed by each
	// application layer in execution order.
	Layers []LayerResult

	// Error is the error from the failing layer, if any.
	// When Success is false and Error is non-nil, the Layers slice contains
	// partial results up to and including the failed layer.
	Error error
}

GreetResult holds the aggregated outcome of a layered protocol stack execution.

Timing anchors (all share the same start time):

|------|           TTDR: DNS resolved
|------|--|        RTT:  transport connection established
        per-layer TTFB/TTLB tracked in Layers[i]

func (*GreetResult) Layer added in v1.0.3

func (r *GreetResult) Layer(name string) (LayerResult, bool)

Layer returns the LayerResult for the named layer, and whether it was found.

type LayerConfig added in v1.0.3

type LayerConfig interface {
	LayerConfigName() string
}

LayerConfig is the interface that all protocol-specific config types must implement.

type LayerData added in v1.0.3

type LayerData interface {
	LayerDataName() string
}

LayerData is the interface that all protocol-specific result types must implement.

type LayerInfo added in v1.0.3

type LayerInfo struct {
	Name        string
	Description string
	DefaultPort int
	Transport   Transport
}

LayerInfo describes a registered layer.

type LayerResult added in v1.0.3

type LayerResult struct {
	// Name is the layer slug (e.g. "tcp", "tls", "minecraft").
	Name string

	// TTFB is the time from the shared start anchor to the first byte of the
	// layer's response. For the transport layer, TTFB equals RTT.
	TTFB time.Duration

	// TTLB is the time from the shared start anchor to the last byte of the
	// layer's response. For the transport layer, TTLB equals RTT.
	TTLB time.Duration

	// Success indicates whether this layer completed without error.
	Success bool

	// Data holds the protocol-specific payload for this layer (e.g. *tls.TLSResult).
	// Nil for transport-only layers (tcp, udp).
	Data LayerData
}

LayerResult holds the outcome of a single layer within a stack. This includes the base transport layer (tcp/udp) as well as each application layer. Timing is anchored from the same start as the parent GreetResult.

type LayerTiming added in v1.0.3

type LayerTiming struct {
	TTFB time.Duration
	TTLB time.Duration
}

LayerTiming holds TTFB and TTLB for a single application layer's handshake. Both are measured from the same start anchor as the top-level GreetResult timings.

type Stack added in v1.0.3

type Stack struct {
	Transport TransportLayer
	Apps      []AppLayer
	// contains filtered or unexported fields
}

Stack is the resolved execution plan for a named protocol: the transport layer to dial, followed by zero or more application layers to run in order.

func (*Stack) DefaultPort added in v1.0.3

func (s *Stack) DefaultPort() int

DefaultPort returns the default port of the outermost layer. Composite stacks may override this (e.g. "https" uses 443 even though the outermost "http" layer defaults to 80).

func (*Stack) Name added in v1.0.3

func (s *Stack) Name() string

Name returns the name of the outermost (last) layer in the stack. For a bare transport (e.g. "tcp") this is the transport name. Composite stacks (e.g. "https") override this with their registered name.

type Transport

type Transport string

Transport is the network transport a layer operates over.

const (
	TransportTCP Transport = "tcp"
	TransportUDP Transport = "udp"
)

func (Transport) String

func (t Transport) String() string

String returns the human-readable transport name.

type TransportLayer added in v1.0.3

type TransportLayer interface {
	// Name returns the transport slug (e.g. "tcp", "udp").
	Name() string

	// DefaultPort is the fallback port when none is specified.
	DefaultPort() int

	// Transport returns TransportTCP or TransportUDP.
	Transport() Transport

	// Dial resolves host, establishes the connection, and returns it together
	// with DNS and RTT timings. The caller is responsible for closing conn.
	//
	// start is the shared timing anchor owned by the engine; RTT (and TTDR
	// where applicable) must be measured as time.Since(start) so every layer
	// in the stack reports timings relative to the same origin.
	Dial(ctx context.Context, start time.Time, host string, port int) (conn net.Conn, ttdr time.Duration, rtt time.Duration, err error)
}

TransportLayer establishes a network connection. It owns DNS resolution, dialing, RTT measurement, and connection-level error classification. tcp and udp implement this interface.

Directories

Path Synopsis
cmd
greet command
Package jsonapi provides JSON-serializable request and response models for the greet engine, together with mappers that convert to and from the domain models.
Package jsonapi provides JSON-serializable request and response models for the greet engine, together with mappers that convert to and from the domain models.
all
http
Package http provides the JSON-serializable model, mapper, and option decoder for the HTTP layer.
Package http provides the JSON-serializable model, mapper, and option decoder for the HTTP layer.
minecraft
Package minecraft provides the JSON-serializable model, mapper, and option decoder for the Minecraft layer.
Package minecraft provides the JSON-serializable model, mapper, and option decoder for the Minecraft layer.
postgresql
Package postgresql provides the JSON-serializable model, mapper, and option decoder for the PostgreSQL layer.
Package postgresql provides the JSON-serializable model, mapper, and option decoder for the PostgreSQL layer.
ssh
Package ssh provides the JSON-serializable model and mapper for the SSH layer's result.
Package ssh provides the JSON-serializable model and mapper for the SSH layer's result.
tls
Package tls provides the JSON-serializable model and mapper for the TLS layer's result.
Package tls provides the JSON-serializable model and mapper for the TLS layer's result.
protocols
all
ssh
tcp
tls
udp

Jump to

Keyboard shortcuts

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