Documentation
¶
Overview ¶
Package routing provides bytecode based routing rules for Gonnect middleware.
The package can build gonnect.RouterCfg, tun.SplitRouter, and sniffer.Sniffer control callbacks from immutable bytecode tables or from a small text rule format.
Index ¶
- Constants
- func NewBytecodeSniffer(config sniffer.SnifferConfig, rules SnifferBytecodeRules) (*sniffer.Sniffer, error)
- type BytecodeRules
- type IPv4Subnet
- type NamedSniffClassifier
- type NamedSniffClassifierConstructor
- type RouterCfg
- type SlotReporter
- type SniffClassifierConstructor
- type SniffClassifierOption
- type SnifferBytecodeRules
- type SnifferCallMutation
- type SnifferControls
- type SnifferRouteAction
- type SplitBytecodeRules
- type SplitRouter
Constants ¶
const ( // OP_DROP pops a boolean value and routes to slot 0 when it is true. OP_DROP byte = iota // OP_SLOT pops a boolean value and routes to the following uint8 slot when it is true. OP_SLOT // OP_TRUE pushes true onto the boolean stack. OP_TRUE // OP_FALSE pushes false onto the boolean stack. OP_FALSE // OP_NOT inverts the boolean value on top of the stack. OP_NOT // OP_AND replaces the two top stack values with their logical conjunction. OP_AND // OP_OR replaces the two top stack values with their logical disjunction. OP_OR // OP_NET4 pushes whether the operation is for IPv4 or has an IPv4 address. OP_NET4 // OP_NET6 pushes whether the operation is for IPv6 or has an IPv6 address. OP_NET6 // OP_UDP pushes whether the operation uses a UDP network. OP_UDP // OP_TCP pushes whether the operation uses a TCP network. OP_TCP // OP_FQDN pushes whether the remote address is a hostname rather than an IP. OP_FQDN // OP_LFQDN pushes whether the local address is a hostname rather than an IP. OP_LFQDN // OP_ADDR_S pushes whether the remote address host equals a string table value. OP_ADDR_S // OP_LADDR_S pushes whether the local address host equals a string table value. OP_LADDR_S // OP_ADDR_RE pushes whether the remote address host matches a regexp table value. OP_ADDR_RE // OP_LADDR_RE pushes whether the local address host matches a regexp table value. OP_LADDR_RE // OP_ADDR4 pushes whether the remote address equals an IPv4 table value. OP_ADDR4 // OP_LADDR4 pushes whether the local address equals an IPv4 table value. OP_LADDR4 // OP_ADDR6 pushes whether the remote address equals an IPv6 table value. OP_ADDR6 // OP_LADDR6 pushes whether the local address equals an IPv6 table value. OP_LADDR6 // OP_SNET4 pushes whether the remote IPv4 address is in an IPv4 subnet table value. OP_SNET4 // OP_LSNET4 pushes whether the local IPv4 address is in an IPv4 subnet table value. OP_LSNET4 // OP_SNET6 pushes whether the remote IPv6 address is in an IPv6 subnet table value. OP_SNET6 // OP_LSNET6 pushes whether the local IPv6 address is in an IPv6 subnet table value. OP_LSNET6 // OP_PORT pushes whether the remote address port equals the following uint16 port. OP_PORT // OP_LPORT pushes whether the local address port equals the following uint16 port. OP_LPORT // OP_RULE pushes whether the packet flow matches a sysnet rule. OP_RULE // OP_DIAL pushes whether the RouterCfg method is DialTCP, DialUDP, or RouteUDP. OP_DIAL // OP_LISTEN pushes whether the RouterCfg method is ListenTCP. OP_LISTEN // OP_LOOKUP pushes whether the RouterCfg method is Lookup. OP_LOOKUP // OP_INTERCEPT pops a boolean value and asks sniffer.Sniffer to sniff the // TCP stream when it is true. It is valid only in Sniffer control bytecode. OP_INTERCEPT // OP_SNIFF pushes whether the sniff result matched the named classifier // referenced by the following uint16 classifier table index. OP_SNIFF // OP_SNIFF_NONE pushes whether sniffing found no matching classifier. OP_SNIFF_NONE // OP_ROUTE pops a boolean value, mutates a sniffer call, and routes to // a route-action slot when it is true. OP_ROUTE )
Variables ¶
This section is empty.
Functions ¶
func NewBytecodeSniffer ¶ added in v0.39.0
func NewBytecodeSniffer( config sniffer.SnifferConfig, rules SnifferBytecodeRules, ) (*sniffer.Sniffer, error)
NewBytecodeSniffer validates rules and returns callbacks that can be used by sniffer.NewSniffer. Existing Control, SniffControl, and Classifiers fields in config are replaced with the bytecode-backed values.
Types ¶
type BytecodeRules ¶
type BytecodeRules struct {
Strings []string
Regexps []*regexp.Regexp
IPv4Addrs []uint32
IPv4Subnets []IPv4Subnet
IPv6Addrs []netip.Addr
IPv6Subnets []netip.Prefix
DNSCacheStorage gdns.CacheStorage
DialTCP []byte
ListenTCP []byte
DialUDP []byte
RouteUDP []byte
Lookup []byte
}
BytecodeRules contains the immutable tables and bytecode programs used to build a gonnect.RouterCfg.
Each program is encoded as one-byte opcodes followed by the opcode parameter when it has one. OP_SLOT uses one uint8 parameter. String, regexp, address, subnet, and port operations use one little-endian uint16 parameter. A program routes to slot 0 when it finishes without a matching OP_DROP or OP_SLOT. OP_DIAL, OP_LISTEN, and OP_LOOKUP push the current RouterCfg method class: DialTCP, DialUDP, and RouteUDP are dial operations; ListenTCP is a listen operation; Lookup is a lookup operation.
Every bytecode slice is validated by NewBytecodeRouterCfg. The constructor copies all slices, so later changes to BytecodeRules do not affect routing. When DNSCacheStorage is set, cached reverse DNS names are matched exactly as stored; names produced by github.com/asciimoth/gonnect/dns.Cache are usually absolute names with a trailing dot, such as "example.test.".
func NewBytecodeRules ¶
func NewBytecodeRules( dialTCP, listenTCP, dialUDP, routeUDP, lookup string, ) (BytecodeRules, error)
NewBytecodeRules parses the simple routing rules language into BytecodeRules.
func NewBytecodeRulesProgram ¶ added in v0.39.0
func NewBytecodeRulesProgram(program string) (BytecodeRules, error)
NewBytecodeRulesProgram parses one routing rules program and derives the five RouterCfg method programs from it.
The input is split into independent segments. A segment ends at a DROP or SLOT operation, matched case-insensitively, or at the end of the string. Each derived method program receives only the segments that can still affect that method:
- segments without DIAL, LISTEN, or LOOKUP are copied to every method;
- segments with method operations are omitted only when their terminal DROP or SLOT condition is provably false for that method.
The proof is intentionally conservative. Method operations are evaluated as constants for the target method, TRUE/FALSE/NOT/AND/OR are evaluated exactly, and every runtime-dependent predicate is treated as unknown. Unknown, invalid, or unterminated segments are kept and then validated normally by NewBytecodeRouterCfg.
type IPv4Subnet ¶
IPv4Subnet is an IPv4 CIDR subnet used by bytecode routing rules.
Addr is the canonical big-endian 32-bit IPv4 address. Bits is the CIDR prefix length and must be in the range 0..32.
type NamedSniffClassifier ¶ added in v0.39.0
NamedSniffClassifier binds a rule-language name to a Sniffer classifier factory.
Name must be non-empty and must not contain white space. Factory can be any implementation of sniffer.Factory. Rules can refer to the name with SNIFF <name>.
type NamedSniffClassifierConstructor ¶ added in v0.39.0
type NamedSniffClassifierConstructor struct {
Name string
Constructor SniffClassifierConstructor
}
NamedSniffClassifierConstructor binds a constructor name to an inline SNIFF classifier constructor.
Name is case-sensitive and must be non-empty. It must not contain white space or ":". Constructor must not be nil.
func DefaultSniffClassifierConstructors ¶ added in v0.39.0
func DefaultSniffClassifierConstructors() []NamedSniffClassifierConstructor
DefaultSniffClassifierConstructors returns the built-in inline SNIFF classifier constructors.
The current collection contains HTTP and TLS. The returned slice is a copy and can be changed by the caller before it is passed to NewSnifferBytecodeRulesWithConstructors.
type RouterCfg ¶ added in v0.39.0
type RouterCfg interface {
gonnect.RouterCfg
SlotReporter
}
func NewBytecodeRouterCfg ¶
func NewBytecodeRouterCfg(rules BytecodeRules) (RouterCfg, error)
NewBytecodeRouterCfg validates rules and returns a gonnect.RouterCfg that evaluates stack-based bytecode for each Router operation.
type SlotReporter ¶ added in v0.39.0
type SlotReporter interface {
MentionedSlots() []int
}
SlotReporter is implemented by bytecode-backed routers that can report the non-drop slots mentioned by their rules.
type SniffClassifierConstructor ¶ added in v0.39.0
type SniffClassifierConstructor func( options []SniffClassifierOption, ) (canonical string, factory sniffer.Factory, err error)
SniffClassifierConstructor builds one Sniffer classifier factory from inline SNIFF options.
The returned canonical string must identify the effective options. It is used only for de-duplication, so equivalent option sets should return the same canonical string. Return an empty canonical string when no option is set.
type SniffClassifierOption ¶ added in v0.39.0
SniffClassifierOption is one KEY:VALUE option from an inline SNIFF classifier specification.
Constructor implementations receive keys after parser normalization. Values are not decoded or changed by the parser.
type SnifferBytecodeRules ¶ added in v0.39.0
type SnifferBytecodeRules struct {
Classifiers []NamedSniffClassifier
Strings []string
Regexps []*regexp.Regexp
IPv4Addrs []uint32
IPv4Subnets []IPv4Subnet
IPv6Addrs []netip.Addr
IPv6Subnets []netip.Prefix
DNSCacheStorage gdns.CacheStorage
// RouteActions contains the fixed call changes used by OP_ROUTE.
RouteActions []SnifferRouteAction
Control []byte
SniffControl []byte
}
SnifferBytecodeRules contains the immutable tables and bytecode programs used to build gonnect/sniffer control callbacks.
Control runs before sniffing. It can route directly with OP_SLOT, OP_DROP, or OP_ROUTE, or request TCP interception with OP_INTERCEPT. SniffControl runs after Sniffer restores inspected bytes. It can route with OP_SLOT, OP_DROP, or OP_ROUTE, and it can test the matched classifier with OP_SNIFF or OP_SNIFF_NONE.
NewSnifferBytecodeRules derives Control and SniffControl from one rule text. Sniffer-only segments are copied only to the phase where they make sense; normal address, network, method, and slot segments are copied to both.
Classifiers contains named classifiers supplied by the caller and generated inline classifiers built from SNIFF specs such as "SNIFF HTTP URL:/blocked".
func NewSnifferBytecodeRules ¶ added in v0.39.0
func NewSnifferBytecodeRules( classifiers []NamedSniffClassifier, program string, ) (SnifferBytecodeRules, error)
NewSnifferBytecodeRules parses one rules program and derives the Sniffer control and sniff-control programs from it.
INTERCEPT segments are copied only to Control. SNIFF and SNIFF_NONE segments are copied only to SniffControl. Segments that use neither Sniffer-only operation are copied to both programs. A segment that uses SNIFF and ends in INTERCEPT is rejected because it has no meaningful execution phase.
SNIFF can refer to a named classifier from classifiers, or to an inline classifier specification built by DefaultSniffClassifierConstructors.
func NewSnifferBytecodeRulesWithConstructors ¶ added in v0.39.0
func NewSnifferBytecodeRulesWithConstructors( classifiers []NamedSniffClassifier, constructors []NamedSniffClassifierConstructor, program string, ) (SnifferBytecodeRules, error)
NewSnifferBytecodeRulesWithConstructors parses one rules program like NewSnifferBytecodeRules, but uses constructors as the inline SNIFF classifier collection.
A SNIFF argument that matches a named classifier still refers to that classifier. Other arguments can use this form:
SNIFF <constructor> [<option>:<value> ...]
Constructor names are case-sensitive. Option names are normalized by each constructor. Repeated equivalent inline specifications share one generated classifier entry. Generated classifiers are appended after the named classifiers, in first-use order.
type SnifferCallMutation ¶ added in v0.39.0
type SnifferCallMutation struct {
SetNetwork bool
Network string
SetSrc bool
Src string
SetDst bool
Dst string
SetSrcAddr bool
SrcAddr string
SetSrcPort bool
SrcPort string
SetDstAddr bool
DstAddr string
SetDstPort bool
DstPort string
SetHost bool
Host string
SetService bool
Service string
SetProto bool
Proto string
}
SnifferCallMutation contains fixed values that OP_ROUTE can write to a sniffer.Call.
A Set field controls whether the paired value is written. Full endpoint replacements, Src and Dst, are applied before endpoint-part replacements.
type SnifferControls ¶ added in v0.39.0
type SnifferControls interface {
SlotReporter
Control(call *sniffer.Call) sniffer.Action
SniffControl(call *sniffer.SniffedCall) sniffer.Action
Classifiers() []sniffer.Factory
}
SnifferControls is the bytecode-backed control pair for sniffer.Sniffer.
func NewBytecodeSnifferControls ¶ added in v0.39.0
func NewBytecodeSnifferControls( rules SnifferBytecodeRules, ) (SnifferControls, error)
NewBytecodeSnifferControls validates rules and returns a reusable Sniffer control pair. Sniff errors always reject, independent of SniffControl bytecode.
type SnifferRouteAction ¶ added in v0.39.0
type SnifferRouteAction struct {
Slot uint8
Mutation SnifferCallMutation
}
SnifferRouteAction is a route target with call field changes.
Slot is the output slot returned by OP_ROUTE. Mutation is applied to the active sniffer.Call before the action is returned.
type SplitBytecodeRules ¶
type SplitBytecodeRules struct {
System sysnet.System
Rules []sysnet.Rule
// RuleCacheTTL controls how long OP_RULE matcher results are cached by
// flow. A zero value uses the default TTL; a negative value disables the
// cross-packet rule cache.
RuleCacheTTL time.Duration
// RuleCacheMaxEntries bounds the cross-packet OP_RULE cache. A zero value
// uses the default size; a negative value disables the cache.
RuleCacheMaxEntries int
// RouteCacheTTL controls how long whole bytecode route results are cached
// by packet flow. When RouteCacheTTL and RouteCacheMaxEntries are both
// zero, the route cache inherits the OP_RULE cache settings; this means
// disabling the rule cache also disables the default route cache. A negative
// value disables the route cache.
RouteCacheTTL time.Duration
// RouteCacheMaxEntries bounds the whole bytecode route-result cache. A zero
// value uses the inherited or default size; a negative value disables the
// route cache.
RouteCacheMaxEntries int
Strings []string
Regexps []*regexp.Regexp
IPv4Addrs []uint32
IPv4Subnets []IPv4Subnet
IPv6Addrs []netip.Addr
IPv6Subnets []netip.Prefix
DNSCacheStorage gdns.CacheStorage
Route []byte
}
SplitBytecodeRules contains the immutable tables and bytecode program used to build a tun.SplitRouter.
The packet router supports the common bytecode opcodes plus OP_RULE. OP_RULE indexes Rules and is evaluated by a sysnet.Matcher built from System. The RouterCfg method opcodes OP_DIAL, OP_LISTEN, and OP_LOOKUP are not valid for packet routing. The constructor validates and copies all slices before returning the router. When DNSCacheStorage is set, cached reverse DNS names are matched exactly as stored; names produced by github.com/asciimoth/gonnect/dns.Cache are usually absolute names with a trailing dot, such as "example.test.".
func NewSplitBytecodeRules ¶
func NewSplitBytecodeRules( system sysnet.System, route string, ) (SplitBytecodeRules, error)
NewSplitBytecodeRules parses the simple routing rules language into SplitBytecodeRules. RULE takes a sysnet rule type followed by the rule text:
RULE app org.example.App
The first field after RULE becomes sysnet.Rule.Type. Everything after the separating space or tab becomes sysnet.Rule.Rule verbatim, so rule text may contain spaces and tabs.
type SplitRouter ¶ added in v0.39.0
type SplitRouter interface {
tun.SplitRouter
SlotReporter
Close() error
}
func NewBytecodeSplitRouter ¶
func NewBytecodeSplitRouter(rules SplitBytecodeRules) (SplitRouter, error)
NewBytecodeSplitRouter validates rules and returns a SplitRouter that evaluates stack-based bytecode against IP packets. The returned router owns matchers built from rules.System; call Close when the router is no longer used.