yaraxwasm

package module
v1.0.0 Latest Latest
Warning

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

Go to latest
Published: Mar 29, 2026 License: MIT Imports: 42 Imported by: 0

README

Tests Go Reference

yaraxwasm

yaraxwasm is a Go package that exposes YARA-X through a WebAssembly guest runtime hosted by wazero.

The project exists to make YARA-X easy to embed in Go programs without asking callers to manage a separate native shared library. Instead of linking directly to Rust code, the Go API talks to a bundled or caller-supplied WASM guest that contains the YARA-X engine.

Why This Exists

YARA-X is a modern YARA engine implemented in Rust. It is powerful, but wiring a Rust engine into Go usually means dealing with native build pipelines, ABI boundaries, or distribution of platform-specific artifacts.

yaraxwasm takes a different approach:

  • the host side stays in Go
  • the scanning engine runs inside a WASM guest
  • the default guest can be embedded directly into the Go binary
  • callers can still override the guest module when they need to

That gives Go applications a straightforward way to use YARA-X while keeping a clear runtime boundary between the Go host and the scanning engine.

Supported Features

  • Compile YARA-X rules from Go source strings.
  • Scan in-memory byte slices, files, and io.ReaderAt sources.
  • Load the scanning engine from an embedded guest module, a filesystem path, or an io.Reader.
  • Export and import compiled rules.
  • Create and verify signed compiled-rules containers.
  • Sign compiled rules with Ed25519 or x509/CMS.
  • Verify x509/CMS signatures with optional RFC3161 timestamp, EKU, custom EKU, and CRL enforcement.
  • Opt into experimental custom guest-memory allocators through github.com/niallnsec/yaraxwasm/experimental.

High-Level Design

At a high level, the library is split into two sides:

  1. The Go host API, which exposes familiar types such as Compiler, Rules, and Scanner.
  2. The YARA-X guest module, which is compiled to WASM and executed by wazero.

The normal workflow looks like this:

  1. Go code compiles or loads rules through yaraxwasm.
  2. The host runtime ensures the guest module is loaded.
  3. Rule compilation and scanning work is delegated to the guest.
  4. Results are translated back into Go types.

For deployments that need authenticated rule distribution, the library also supports signed compiled-rules containers. Those containers wrap the compiled rule bytes in a fixed header plus metadata and signature, so rules can be transported and verified before loading.

Quick Start

Compile and scan:

package main

import (
	"fmt"
	"log"

	"github.com/niallnsec/yaraxwasm"
)

func main() {
	rules, err := yaraxwasm.Compile(`
rule demo {
	strings:
		$needle = "hello"
	condition:
		$needle
}`)
	if err != nil {
		log.Fatal(err)
	}
	defer rules.Destroy()

	results, err := rules.Scan([]byte("hello from yaraxwasm"))
	if err != nil {
		log.Fatal(err)
	}

	for _, match := range results.MatchingRules() {
		fmt.Println(match.Identifier())
	}
}

Guest Module Loading

By default, the package uses an embedded guest module. If you want to supply your own guest build, you can do that explicitly with [Initialise] and either [GuestWASMPath] or [GuestWASMReader].

If no explicit source is given, initialization falls back in this order:

  1. the explicit option passed to Initialise
  2. YARAX_GUEST_WASM
  3. the embedded guest module

Example:

err := yaraxwasm.Initialise(
	yaraxwasm.GuestWASMPath("/absolute/path/to/yarax_guest.wasm"),
)
if err != nil {
	// handle error
}

You can also provide the module through the environment:

export YARAX_GUEST_WASM=/absolute/path/to/yarax_guest.wasm

Signed Compiled Rules

The library can wrap compiled rules in a signed container format so that a rule producer can export them and a consumer can verify them before loading.

Supported signing and verification flows include:

  • Ed25519 signatures over the signed container payload
  • x509/CMS detached signatures
  • optional RFC3161 timestamp verification
  • required EKU and custom EKU checks
  • optional CRL enforcement

Runnable examples for these flows live under examples/:

  • export and sign with Ed25519
  • export and sign with x509/CMS, timestamping, and custom EKU
  • verify and load Ed25519-signed compiled rules
  • verify and load x509/CMS-signed compiled rules

Initialize the example PKI with:

./examples/init-pki.sh

Then run the example programs with:

go run ./examples/ed25519_export_sign
go run ./examples/x509_export_sign
go run ./examples/ed25519_verify_load
go run ./examples/x509_verify_load

Experimental Memory Paths

The experimental package contains unstable extensions for advanced runtime configuration.

Today that primarily means custom guest-memory allocators that can enable more efficient file and io.ReaderAt scanning paths on supported platforms. These APIs are intentionally separated from the main package because they may evolve as the runtime design is refined.

Development

The repository includes the guest source used to build the WASM engine.

For a reproducible development environment, open the repository in the included devcontainer. It provides:

  • Go 1.26 plus golangci-lint and easyjson
  • Rust 1.94.1 with clippy, rustfmt, wasm32-wasip1, and nightly rust-src for the experimental memory64 wasm64-unknown-unknown path
  • native build dependencies such as clang, cmake, pkg-config, libssl-dev, and zstd
  • cargo-c plus persistent Go, Cargo target, and benchmark caches
  • privileged container settings so make test-userfaultfd-local works inside the devcontainer

Build the guest:

make guest-release

Regenerate the embedded guest artifact:

go generate ./...

Run the Go test suite:

go test ./...

Run the guest-backed test paths:

make test-local
make test-profiling-local
make test-userfaultfd-local

Run the benchmark comparison suite:

make bench-compare

The benchmark helper prepares its own temporary benchcmp modfile and comparison checkout, so benchcmp does not need a standalone go mod download during devcontainer startup. By default it compares against github.com/VirusTotal/yara-x on main. The extended compare suite also downloads the pinned YARA Forge full ruleset and refreshes the latest WordPress source tree under benchcmp/.tmp/datasets unless COMPARE_BENCH_DATA_DIR is set.

Run the linters:

golangci-lint run ./...
(cd guest && cargo clippy --tests --no-deps -- --deny clippy::all)
(cd guest && cargo fmt --all --check)

Run the same checks as the GitHub workflows locally:

make ci-local

Current Benchmark Results

These measurements were taken on March 29, 2026 on Linux arm64 inside Docker with make docker-bench-compare. The comparison target was github.com/VirusTotal/yara-x main at 2f193c33. Each value below is the median of 3 runs. The compare harness warms the WASM runtime before b.ResetTimer, and the steady-state scan benchmarks also create scanners and perform a warmup scan before timing starts, so the reported CPU, ns/op, B/op, and allocs/op figures exclude one-time WASM startup work.

Benchmark CGO ns/op WASM ns/op WASM/CGO CGO MB/s WASM MB/s CGO B/op WASM B/op CGO allocs/op WASM allocs/op
Scan reuse scanner 8,159 27,615 3.38x 1.59 0.47 4,514 2,276 149 35
New scanner 181,891 4,802,704 26.40x - - 99 15,675,610 2 19,505
Rules.Scan 192,072 4,898,888 25.51x 0.07 0.00 4,744 20,890,227 153 19,559
ReadFrom 1,939,326 984,739 0.51x - - 25,144 6,382,788 13 12,087
LoadRuleset 5,110,855,145 6,413,220,386 1.25x 3.76 2.99 272 2,322,163,920 6 643,548
ScanWordPressCorpus 4,699,412,364 8,733,536,876 1.86x 16.21 8.72 80,376 8,632,296 3,349 56,951
ScanWordPressCorpusBuffered 4,332,508,352 9,464,034,019 2.18x 17.58 8.05 1,407,584 2,369,768 16,745 56,946

Documentation

Overview

package yaraxwasm provides Go bindings for YARA-X backed by the bundled or configured WASM guest runtime.

Example (Basic)
// Compile some YARA rules.
rules, _ := Compile(`
rule foo {
  strings:
    $foo = "foo"
  condition:
    $foo
}

rule bar {
  strings:
    $bar = "bar"
  condition:
    $bar
}`)

// Use the compiled rules for scanning some data.
scanResults, _ := rules.Scan([]byte("foobar"))

// Iterate over the matching rules.
for _, r := range scanResults.MatchingRules() {
	fmt.Printf("rule %s matched\n", r.Identifier())
}
Output:
rule foo matched
rule bar matched
Example (CompilerAndScanner)
// Create a new compiler.
compiler, _ := NewCompiler()

// Add some rules to the compiler.
err := compiler.AddSource(`rule foo {
		strings:
		  $foo = "foo"
		condition:
          $foo
	}

    rule bar {
		strings:
		$bar = "bar"
		condition:
		$bar
	}`)
if err != nil {
	panic(err)
}

// Get the compiled rules.
rules := compiler.Build()

// Pass the compiled rules to a scanner.
scanner := NewScanner(rules)

// Use the scanner for scanning some data.
scanResults, _ := scanner.Scan([]byte("foobar"))

// Iterate over the matching rules.
for _, r := range scanResults.MatchingRules() {
	fmt.Printf("rule %s matched\n", r.Identifier())
}
Output:
rule foo matched
rule bar matched

Index

Examples

Constants

This section is empty.

Variables

View Source
var (
	ErrSignedRulesInvalidHeader         = errors.New("invalid signed rules header")
	ErrSignedRulesBadMagic              = errors.New("signed rules file magic mismatch")
	ErrSignedRulesUnsupportedVersion    = errors.New("unsupported signed rules header version")
	ErrSignedRulesInvalidCompiledArch   = errors.New("invalid compiled rules architecture")
	ErrSignedRulesArchMismatch          = errors.New("compiled rules architecture mismatch")
	ErrSignedRulesInvalidMetadataLayout = errors.New("invalid signed rules metadata layout")
	ErrSignedRulesMissingSignature      = errors.New("signed rules file is missing a signature")
	ErrSignedRulesUnsupportedSignature  = errors.New("unsupported signed rules signature scheme")
	ErrSignedRulesSignatureVerification = errors.New("signed rules signature verification failed")
	ErrSignedRulesInvalidTimeRange      = errors.New("signed rules generation time must be before or equal to signing time")
)
View Source
var (
	ErrX509SignedRulesInvalidMetadata   = errors.New("invalid x509 signed rules metadata")
	ErrX509SignedRulesTimestampRequired = errors.New("x509 signed rules timestamp is required")
	ErrX509SignedRulesCRLRequired       = errors.New("x509 signed rules CRL is required")
)
View Source
var ErrTimeout = errors.New("timeout")

ErrTimeout is returned when a scan operation exceeds the configured timeout.

Functions

func Initialise

func Initialise(opts ...InitialiseOption) error

Initialise eagerly loads and compiles the guest module so later API calls can reuse the prepared runtime without paying the one-time setup cost.

If no explicit source option is provided, the bootstrap falls back to `YARAX_GUEST_WASM` and then the embedded guest module. When built with the `no_embed_wasm` tag, callers must provide a path or reader source, or set `YARAX_GUEST_WASM`.

func VerifyX509SignedFrom

func VerifyX509SignedFrom(r io.Reader, opts X509VerifyOptions) (*VerifiedSignedRules, *X509VerificationResult, error)

VerifyX509SignedFrom verifies an x509/CMS-backed signed rules container.

func Version

func Version() (string, error)

Version returns the version of the underlying yaraxwasm library used by the guest.

func WithGenerationTime

func WithGenerationTime(t time.Time) signedTimeOption

WithGenerationTime sets the generation time written into the signed rules header.

func WithSignedMetadata

func WithSignedMetadata(metadata []byte) signedMetadataOption

WithSignedMetadata embeds opaque metadata in the signed rules container.

func WithSigningTime

func WithSigningTime(t time.Time) signedTimeOption

WithSigningTime sets the signing time written into the signed rules header.

Types

type CompileError

type CompileError struct {
	Type    CompileErrorType `json:"type"`
	Code    string           `json:"code"`
	Title   string           `json:"title"`
	Line    int              `json:"line"`
	Column  int              `json:"column"`
	Labels  []Label          `json:"labels,omitempty"`
	Footers []Footer         `json:"footers,omitempty"`
	Text    string           `json:"text"`
}

CompileError represents each of the errors returned by Compiler.Errors.

func (CompileError) CodeID

func (c CompileError) CodeID() CompileErrorCode

CodeID returns the compiler error code as a typed identifier.

func (CompileError) Error

func (c CompileError) Error() string

Error returns the error's full report.

func (CompileError) HasCode

func (c CompileError) HasCode(code CompileErrorCode) bool

HasCode reports whether the compiler error uses the requested code.

func (CompileError) HasType

func (c CompileError) HasType(t CompileErrorType) bool

HasType reports whether the compiler error is the requested concrete type.

func (CompileError) Is

func (c CompileError) Is(target error) bool

Is lets callers match compiler errors with errors.Is using any subset of Type, Code, or Title, for example: errors.Is(err, &CompileError{Type: CompileErrorTypeUnknownIdentifier}).

type CompileErrorCode

type CompileErrorCode string

CompileErrorCode identifies a compiler error code emitted by yaraxwasm.

const (
	CompileErrorCodeArbitraryRegexpPrefix      CompileErrorCode = "E045"
	CompileErrorCodeAssignmentMismatch         CompileErrorCode = "E005"
	CompileErrorCodeCircularIncludes           CompileErrorCode = "E046"
	CompileErrorCodeConflictingRuleIdentifier  CompileErrorCode = "E013"
	CompileErrorCodeCustomError                CompileErrorCode = "E100"
	CompileErrorCodeDuplicateModifier          CompileErrorCode = "E020"
	CompileErrorCodeDuplicatePattern           CompileErrorCode = "E023"
	CompileErrorCodeDuplicateRule              CompileErrorCode = "E012"
	CompileErrorCodeDuplicateTag               CompileErrorCode = "E021"
	CompileErrorCodeEmptyPatternSet            CompileErrorCode = "E016"
	CompileErrorCodeEntrypointUnsupported      CompileErrorCode = "E017"
	CompileErrorCodeIncludeError               CompileErrorCode = "E042"
	CompileErrorCodeIncludeNotAllowed          CompileErrorCode = "E044"
	CompileErrorCodeIncludeNotFound            CompileErrorCode = "E043"
	CompileErrorCodeInvalidBase64Alphabet      CompileErrorCode = "E026"
	CompileErrorCodeInvalidEscapeSequence      CompileErrorCode = "E029"
	CompileErrorCodeInvalidFloat               CompileErrorCode = "E028"
	CompileErrorCodeInvalidInteger             CompileErrorCode = "E027"
	CompileErrorCodeInvalidMetadata            CompileErrorCode = "E037"
	CompileErrorCodeInvalidModifier            CompileErrorCode = "E033"
	CompileErrorCodeInvalidModifierCombination CompileErrorCode = "E019"
	CompileErrorCodeInvalidPattern             CompileErrorCode = "E024"
	CompileErrorCodeInvalidRange               CompileErrorCode = "E011"
	CompileErrorCodeInvalidRegexp              CompileErrorCode = "E014"
	CompileErrorCodeInvalidRegexpModifier      CompileErrorCode = "E030"
	CompileErrorCodeInvalidRuleName            CompileErrorCode = "E039"
	CompileErrorCodeInvalidTag                 CompileErrorCode = "E041"
	CompileErrorCodeInvalidUTF8                CompileErrorCode = "E032"
	CompileErrorCodeMethodNotAllowedInWith     CompileErrorCode = "E036"
	CompileErrorCodeMismatchingTypes           CompileErrorCode = "E003"
	CompileErrorCodeMissingMetadata            CompileErrorCode = "E038"
	CompileErrorCodeMixedGreediness            CompileErrorCode = "E015"
	CompileErrorCodeNumberOutOfRange           CompileErrorCode = "E007"
	CompileErrorCodePotentiallySlowLoop        CompileErrorCode = "E034"
	CompileErrorCodeSlowPattern                CompileErrorCode = "E018"
	CompileErrorCodeSyntaxError                CompileErrorCode = "E001"
	CompileErrorCodeTooManyPatterns            CompileErrorCode = "E035"
	CompileErrorCodeUnexpectedEscapeSequence   CompileErrorCode = "E031"
	CompileErrorCodeUnexpectedNegativeNumber   CompileErrorCode = "E006"
	CompileErrorCodeUnknownField               CompileErrorCode = "E008"
	CompileErrorCodeUnknownIdentifier          CompileErrorCode = "E009"
	CompileErrorCodeUnknownModule              CompileErrorCode = "E010"
	CompileErrorCodeUnknownPattern             CompileErrorCode = "E025"
	CompileErrorCodeUnknownTag                 CompileErrorCode = "E040"
	CompileErrorCodeUnusedPattern              CompileErrorCode = "E022"
	CompileErrorCodeWrongArguments             CompileErrorCode = "E004"
	CompileErrorCodeWrongType                  CompileErrorCode = "E002"
)

type CompileErrorType

type CompileErrorType string

CompileErrorType identifies a concrete compiler error variant emitted by yaraxwasm.

const (
	CompileErrorTypeArbitraryRegexpPrefix      CompileErrorType = "ArbitraryRegexpPrefix"
	CompileErrorTypeAssignmentMismatch         CompileErrorType = "AssignmentMismatch"
	CompileErrorTypeCircularIncludes           CompileErrorType = "CircularIncludes"
	CompileErrorTypeConflictingRuleIdentifier  CompileErrorType = "ConflictingRuleIdentifier"
	CompileErrorTypeCustomError                CompileErrorType = "CustomError"
	CompileErrorTypeDuplicateModifier          CompileErrorType = "DuplicateModifier"
	CompileErrorTypeDuplicatePattern           CompileErrorType = "DuplicatePattern"
	CompileErrorTypeDuplicateRule              CompileErrorType = "DuplicateRule"
	CompileErrorTypeDuplicateTag               CompileErrorType = "DuplicateTag"
	CompileErrorTypeEmptyPatternSet            CompileErrorType = "EmptyPatternSet"
	CompileErrorTypeEntrypointUnsupported      CompileErrorType = "EntrypointUnsupported"
	CompileErrorTypeIncludeError               CompileErrorType = "IncludeError"
	CompileErrorTypeIncludeNotAllowed          CompileErrorType = "IncludeNotAllowed"
	CompileErrorTypeIncludeNotFound            CompileErrorType = "IncludeNotFound"
	CompileErrorTypeInvalidBase64Alphabet      CompileErrorType = "InvalidBase64Alphabet"
	CompileErrorTypeInvalidEscapeSequence      CompileErrorType = "InvalidEscapeSequence"
	CompileErrorTypeInvalidFloat               CompileErrorType = "InvalidFloat"
	CompileErrorTypeInvalidInteger             CompileErrorType = "InvalidInteger"
	CompileErrorTypeInvalidMetadata            CompileErrorType = "InvalidMetadata"
	CompileErrorTypeInvalidModifier            CompileErrorType = "InvalidModifier"
	CompileErrorTypeInvalidModifierCombination CompileErrorType = "InvalidModifierCombination"
	CompileErrorTypeInvalidPattern             CompileErrorType = "InvalidPattern"
	CompileErrorTypeInvalidRange               CompileErrorType = "InvalidRange"
	CompileErrorTypeInvalidRegexp              CompileErrorType = "InvalidRegexp"
	CompileErrorTypeInvalidRegexpModifier      CompileErrorType = "InvalidRegexpModifier"
	CompileErrorTypeInvalidRuleName            CompileErrorType = "InvalidRuleName"
	CompileErrorTypeInvalidTag                 CompileErrorType = "InvalidTag"
	CompileErrorTypeInvalidUTF8                CompileErrorType = "InvalidUTF8"
	CompileErrorTypeMethodNotAllowedInWith     CompileErrorType = "MethodNotAllowedInWith"
	CompileErrorTypeMismatchingTypes           CompileErrorType = "MismatchingTypes"
	CompileErrorTypeMissingMetadata            CompileErrorType = "MissingMetadata"
	CompileErrorTypeMixedGreediness            CompileErrorType = "MixedGreediness"
	CompileErrorTypeNumberOutOfRange           CompileErrorType = "NumberOutOfRange"
	CompileErrorTypePotentiallySlowLoop        CompileErrorType = "PotentiallySlowLoop"
	CompileErrorTypeSlowPattern                CompileErrorType = "SlowPattern"
	CompileErrorTypeSyntaxError                CompileErrorType = "SyntaxError"
	CompileErrorTypeTooManyPatterns            CompileErrorType = "TooManyPatterns"
	CompileErrorTypeUnexpectedEscapeSequence   CompileErrorType = "UnexpectedEscapeSequence"
	CompileErrorTypeUnexpectedNegativeNumber   CompileErrorType = "UnexpectedNegativeNumber"
	CompileErrorTypeUnknownField               CompileErrorType = "UnknownField"
	CompileErrorTypeUnknownIdentifier          CompileErrorType = "UnknownIdentifier"
	CompileErrorTypeUnknownModule              CompileErrorType = "UnknownModule"
	CompileErrorTypeUnknownPattern             CompileErrorType = "UnknownPattern"
	CompileErrorTypeUnknownTag                 CompileErrorType = "UnknownTag"
	CompileErrorTypeUnusedPattern              CompileErrorType = "UnusedPattern"
	CompileErrorTypeWrongArguments             CompileErrorType = "WrongArguments"
	CompileErrorTypeWrongType                  CompileErrorType = "WrongType"
)

type CompileOption

type CompileOption func(c *Compiler) error

A CompileOption represents an option passed to NewCompiler and Compile.

func BanModule

func BanModule(module string, errTitle string, errMessage string) CompileOption

BanModule is an option for NewCompiler and Compile that allows banning the use of a given module.

func ConditionOptimization

func ConditionOptimization(yes bool) CompileOption

ConditionOptimization is an option for NewCompiler and Compile that enables the optimization of rule conditions.

func EnableIncludes

func EnableIncludes(yes bool) CompileOption

EnableIncludes allows the compiler to process include directives in YARA rules.

func ErrorOnSlowLoop

func ErrorOnSlowLoop(yes bool) CompileOption

ErrorOnSlowLoop is an option for NewCompiler and Compile that tells the compiler to treat slow loops as errors instead of warnings.

func ErrorOnSlowPattern

func ErrorOnSlowPattern(yes bool) CompileOption

ErrorOnSlowPattern is an option for NewCompiler and Compile that tells the compiler to treat slow patterns as errors instead of warnings.

func Globals

func Globals(vars map[string]any) CompileOption

The Globals option for NewCompiler and Compile allows you to define global variables.

func IgnoreModule

func IgnoreModule(module string) CompileOption

IgnoreModule is an option for NewCompiler and Compile that allows ignoring a given module.

func IncludeDir

func IncludeDir(path string) CompileOption

IncludeDir is an option for NewCompiler and Compile that tells the compiler where to look for included files.

func RelaxedReSyntax

func RelaxedReSyntax(yes bool) CompileOption

RelaxedReSyntax is an option for NewCompiler and Compile that determines whether the compiler should adopt a more relaxed approach while parsing regular expressions.

func RequiredMetadataLinter

func RequiredMetadataLinter(identifier string, errOnFail bool) CompileOption

RequiredMetadataLinter adds a linter that requires metadata in every rule.

func RuleNameLinter

func RuleNameLinter(regex string, errOnFail bool) CompileOption

RuleNameLinter adds a linter that enforces a rule-name regular expression.

func TagRegexLinter

func TagRegexLinter(regex string, errOnFail bool) CompileOption

TagRegexLinter adds a linter that enforces a tag regular expression.

func TagsAllowedLinter

func TagsAllowedLinter(tags []string, errOnFail bool) CompileOption

TagsAllowedLinter adds a linter that restricts tags to the provided list.

func WithFeature

func WithFeature(feature string) CompileOption

WithFeature enables a feature while compiling rules.

NOTE: This API is still experimental and subject to change.

type Compiler

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

Compiler represents a YARA compiler.

func NewCompiler

func NewCompiler(opts ...CompileOption) (*Compiler, error)

NewCompiler creates a new compiler.

func (*Compiler) AddRequiredMetadataLinter

func (c *Compiler) AddRequiredMetadataLinter(identifier string, errOnFail bool) error

AddRequiredMetadataLinter requires every rule to contain the given metadata.

func (*Compiler) AddRuleNameLinter

func (c *Compiler) AddRuleNameLinter(regex string, errOnFail bool) error

AddRuleNameLinter makes rule names match the given regular expression.

func (*Compiler) AddSource

func (c *Compiler) AddSource(src string, opts ...SourceOption) error

AddSource adds YARA source code to be compiled.

func (*Compiler) AddTagRegexLinter

func (c *Compiler) AddTagRegexLinter(regex string, errOnFail bool) error

AddTagRegexLinter makes every rule tag match the given regular expression.

func (*Compiler) AddTagsAllowedLinter

func (c *Compiler) AddTagsAllowedLinter(tags []string, errOnFail bool) error

AddTagsAllowedLinter restricts rule tags to the provided allowed list.

func (*Compiler) Build

func (c *Compiler) Build() *Rules

Build creates a Rules object containing a compiled version of all the YARA rules previously added to the compiler.

func (*Compiler) DefineGlobal

func (c *Compiler) DefineGlobal(ident string, value any) error

DefineGlobal defines a global variable and sets its initial value.

func (*Compiler) Destroy

func (c *Compiler) Destroy()

Destroy destroys the compiler.

func (*Compiler) EmitWasmFile

func (c *Compiler) EmitWasmFile(path string) error

EmitWasmFile writes the compiler-generated WASM module to the given path.

Like Compiler.Build, this consumes the currently added sources and resets the compiler so it can be reused.

func (*Compiler) Errors

func (c *Compiler) Errors() []CompileError

Errors returns the errors that occurred during compilation across multiple calls to Compiler.AddSource.

func (*Compiler) NewNamespace

func (c *Compiler) NewNamespace(namespace string)

NewNamespace creates a new namespace for subsequently added sources.

func (*Compiler) Warnings

func (c *Compiler) Warnings() []Warning

Warnings returns the warnings that occurred during compilation across multiple calls to Compiler.AddSource.

type Ed25519SignedRulesSigner

type Ed25519SignedRulesSigner struct {
	PrivateKey ed25519.PrivateKey
}

Ed25519SignedRulesSigner signs signed-rules payloads with an Ed25519 key.

func (Ed25519SignedRulesSigner) HashAlgorithm

HashAlgorithm implements SignedRulesSigner.

func (Ed25519SignedRulesSigner) SignSignedRules

func (s Ed25519SignedRulesSigner) SignSignedRules(_ SignedRulesHeader, _ []byte, signedBytes []byte) ([]byte, error)

SignSignedRules implements SignedRulesSigner.

func (Ed25519SignedRulesSigner) SignatureType

func (s Ed25519SignedRulesSigner) SignatureType() SignatureType

SignatureType implements SignedRulesSigner.

type Ed25519SignedRulesVerifier

type Ed25519SignedRulesVerifier struct {
	PublicKey ed25519.PublicKey
}

Ed25519SignedRulesVerifier verifies signed-rules payloads with an Ed25519 public key.

func (Ed25519SignedRulesVerifier) VerifySignedRules

func (v Ed25519SignedRulesVerifier) VerifySignedRules(header SignedRulesHeader, _ []byte, signedBytes []byte, signature []byte) error

VerifySignedRules implements SignedRulesVerifier.

type Footer struct {
	Level string `json:"level"`
	Text  string `json:"text"`
}

Footer represents a footer in a CompileError.

type GuestFileMapper

type GuestFileMapper interface {
	wazeroexperimental.MemoryAllocator

	// MapFileToGuest replaces the guest-memory range `[guestOffset,
	// guestOffset+mappedLength)` with a mapping of the given local file.
	//
	// The supplied `mappedLength` is page-rounded. Callers still scan only the
	// original file length.
	MapFileToGuest(mem api.Memory, guestOffset, mappedLength uint32, path string) (GuestMappedRegion, error)
}

GuestFileMapper is an optional extension for custom guest-memory allocators that can map a local file directly into a guest linear-memory subrange.

When configured via WithMemoryAllocator, Scanner.ScanFile may use this to avoid copying file contents into guest memory.

type GuestMappedRegion

type GuestMappedRegion interface {
	// Close removes the temporary mapping and restores the underlying guest
	// memory region.
	Close() error
}

GuestMappedRegion represents a temporary guest-memory mapping managed by a custom wazeroexperimental.MemoryAllocator.

This is an advanced extension point intended for experimental guest-memory backends. Callers should prefer higher-level APIs.

type GuestReaderAtMapper

type GuestReaderAtMapper interface {
	wazeroexperimental.MemoryAllocator

	// MapReaderAtToGuest prepares the guest-memory range `[guestOffset,
	// guestOffset+mappedLength)` so that reads from it are served by `src`.
	//
	// The supplied `mappedLength` is page-rounded, while `size` is the logical
	// scan length requested by the caller.
	MapReaderAtToGuest(mem api.Memory, guestOffset, mappedLength uint32, src io.ReaderAt, size int64) (GuestMappedRegion, error)
}

GuestReaderAtMapper is an optional extension for custom guest-memory allocators that can expose an io.ReaderAt through a guest linear-memory subrange.

When configured via WithMemoryAllocator, Scanner.ScanReaderAt may use this to scan data without copying it into guest memory first.

type InitialiseOption

type InitialiseOption interface {
	// contains filtered or unexported methods
}

InitialiseOption configures how Initialise loads the guest WASM module.

func GuestWASMPath

func GuestWASMPath(path string) InitialiseOption

GuestWASMPath tells Initialise to load the guest WASM module from the given filesystem path instead of the environment variable or embedded copy.

func GuestWASMReader

func GuestWASMReader(r io.Reader) InitialiseOption

GuestWASMReader tells Initialise to load the guest WASM module from the provided reader instead of the environment variable or embedded copy.

func WithMemoryAllocator

func WithMemoryAllocator(allocator wazeroexperimental.MemoryAllocator) InitialiseOption

WithMemoryAllocator tells Initialise to instantiate guest modules with the provided wazero linear-memory allocator.

This is primarily intended for advanced and experimental use cases, such as custom virtual-memory-backed guest buffers from github.com/niallnsec/yaraxwasm/experimental.

type Label

type Label struct {
	Level      string `json:"level"`
	CodeOrigin string `json:"code_origin"`
	Line       int64  `json:"line"`
	Column     int64  `json:"column"`
	Span       Span   `json:"span"`
	Text       string `json:"text"`
}

Label represents a label in a CompileError.

type Match

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

Match contains information about the offset where a match occurred and the length of the match.

func (*Match) Length

func (m *Match) Length() uint64

Length returns the length of a match in bytes.

func (*Match) Offset

func (m *Match) Offset() uint64

Offset returns the offset within the scanned data where a match occurred.

type Metadata

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

Metadata represents a metadata in a Rule.

func (*Metadata) Identifier

func (m *Metadata) Identifier() string

Identifier returns the metadata identifier.

func (*Metadata) Value

func (m *Metadata) Value() any

Value returns the metadata value.

type Pattern

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

Pattern represents a pattern in a Rule.

func (*Pattern) Identifier

func (p *Pattern) Identifier() string

Identifier returns the pattern's identifier (i.e: $a, $foo).

func (*Pattern) Matches

func (p *Pattern) Matches() []Match

Matches returns the matches found for this pattern.

type ProfilingInfo

type ProfilingInfo struct {
	Namespace           string
	Rule                string
	PatternMatchingTime time.Duration
	ConditionExecTime   time.Duration
}

ProfilingInfo contains profiling information about a YARA rule.

type Rule

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

Rule represents a YARA rule.

func (*Rule) Identifier

func (r *Rule) Identifier() string

Identifier returns the rule's identifier.

func (*Rule) Metadata

func (r *Rule) Metadata() []Metadata

Metadata returns the rule's metadata.

func (*Rule) Namespace

func (r *Rule) Namespace() string

Namespace returns the rule's namespace.

func (*Rule) Patterns

func (r *Rule) Patterns() []Pattern

Patterns returns the patterns defined by this rule.

func (*Rule) Tags

func (r *Rule) Tags() []string

Tags returns the rule's tags.

type Rules

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

Rules represents a set of compiled YARA rules.

func Compile

func Compile(src string, opts ...CompileOption) (*Rules, error)

Compile receives YARA source code and returns compiled Rules that can be used for scanning data.

func ReadFrom

func ReadFrom(r io.Reader) (*Rules, error)

ReadFrom reads compiled rules from a reader.

The counterpart is Rules.WriteTo.

func ReadSignedFrom

func ReadSignedFrom(r io.Reader, verifier SignedRulesVerifier) (*Rules, error)

ReadSignedFrom verifies a signed container and loads the verified compiled rules into a Rules value.

func ReadX509SignedFrom

func ReadX509SignedFrom(r io.Reader, opts X509VerifyOptions) (*Rules, error)

ReadX509SignedFrom verifies an x509/CMS-backed signed rules container and loads the verified compiled rules.

func (*Rules) Count

func (r *Rules) Count() int

Count returns the total number of rules.

This is a more efficient alternative to len(rules.Slice()).

func (*Rules) Destroy

func (r *Rules) Destroy()

Destroy destroys the compiled YARA rules represented by Rules.

Calling this method directly is not necessary, it will be invoked by the garbage collector when the rules are not used anymore.

func (*Rules) Imports

func (r *Rules) Imports() []string

Imports returns the names of the imported modules.

func (*Rules) Scan

func (r *Rules) Scan(data []byte) (*ScanResults, error)

Scan scans data with the compiled rules.

func (*Rules) ScanReader

func (r *Rules) ScanReader(reader io.Reader) (*ScanResults, error)

ScanReader scans data streamed from an io.Reader.

func (*Rules) ScanReaderAt

func (r *Rules) ScanReaderAt(reader io.ReaderAt, size int64) (*ScanResults, error)

ScanReaderAt scans data exposed through an io.ReaderAt.

When the configured guest-memory allocator supports it, this may scan the data through a direct guest-memory mapping. Otherwise, the data is copied into guest memory before scanning.

func (*Rules) Slice

func (r *Rules) Slice() []*Rule

Slice returns a slice with all the individual rules contained in this set of compiled rules.

func (*Rules) WriteSignedTo

func (r *Rules) WriteSignedTo(w io.Writer, signer SignedRulesSigner, opts ...SignedRulesWriteOption) (int64, error)

WriteSignedTo writes the compiled rules to w inside a signed container.

func (*Rules) WriteTo

func (r *Rules) WriteTo(w io.Writer) (int64, error)

WriteTo writes the compiled rules into a writer.

The counterpart is ReadFrom.

func (*Rules) WriteX509SignedTo

func (r *Rules) WriteX509SignedTo(w io.Writer, signer crypto.Signer, chain []*x509.Certificate, opts ...X509SignOption) (int64, error)

WriteX509SignedTo writes the compiled rules into an x509/CMS-backed signed rules container.

type ScanResults

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

ScanResults contains the results of a call to Scanner.Scan or Rules.Scan.

func (ScanResults) MatchingRules

func (s ScanResults) MatchingRules() []*Rule

MatchingRules returns the rules that matched during the scan.

type Scanner

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

Scanner scans data with a set of compiled YARA rules.

func NewScanner

func NewScanner(r *Rules) *Scanner

NewScanner creates a Scanner that will use the provided YARA rules.

func (*Scanner) ClearProfilingData

func (s *Scanner) ClearProfilingData()

ClearProfilingData resets the profiling data collected during rule execution.

func (*Scanner) Destroy

func (s *Scanner) Destroy()

Destroy destroys the scanner.

func (*Scanner) Scan

func (s *Scanner) Scan(buf []byte) (*ScanResults, error)

Scan scans the provided data with the Rules associated to the Scanner.

func (*Scanner) ScanFile

func (s *Scanner) ScanFile(path string) (*ScanResults, error)

ScanFile scans a file with the Rules associated to the Scanner.

func (*Scanner) ScanReader

func (s *Scanner) ScanReader(r io.Reader) (*ScanResults, error)

ScanReader scans data streamed from an io.Reader.

This uses YARA-X block scanning internally, so it inherits the same limitations: imported modules are not supported, module outputs cannot be supplied, and matches that span block boundaries may be missed.

func (*Scanner) ScanReaderAt

func (s *Scanner) ScanReaderAt(reader io.ReaderAt, size int64) (*ScanResults, error)

ScanReaderAt scans data exposed through an io.ReaderAt.

When the configured guest-memory allocator supports it, the reader may be exposed directly through guest memory without copying. Otherwise, the input is copied into guest memory before scanning.

func (*Scanner) SetConsoleOutput

func (s *Scanner) SetConsoleOutput(w io.Writer)

SetConsoleOutput sets the destination for messages emitted by the `console` module during subsequent scans on this scanner.

Passing nil disables console output. If the writer also implements `Flush() error` or `Flush()`, it is flushed after each emitted message.

func (*Scanner) SetGlobal

func (s *Scanner) SetGlobal(ident string, value any) error

SetGlobal sets the value of a global variable.

func (*Scanner) SetModuleOutput

func (s *Scanner) SetModuleOutput(data proto.Message) error

SetModuleOutput sets the serialized output for a module used by subsequent scans on this scanner.

func (*Scanner) SetTimeout

func (s *Scanner) SetTimeout(timeout time.Duration)

SetTimeout sets a timeout for scan operations.

func (*Scanner) SlowestRules

func (s *Scanner) SlowestRules(n int) []ProfilingInfo

SlowestRules returns information about the slowest rules.

type SignatureHashAlgorithm

type SignatureHashAlgorithm uint16

SignatureHashAlgorithm identifies the digest or hash selection associated with the signature.

const (
	SignatureHashAlgorithmUnknown SignatureHashAlgorithm = iota
	SignatureHashAlgorithmNone
	SignatureHashAlgorithmSHA256
	SignatureHashAlgorithmSHA384
	SignatureHashAlgorithmSHA512
)

type SignatureType

type SignatureType uint16

SignatureType identifies the signing envelope used for signed compiled rules.

const (
	SignatureTypeUnknown SignatureType = iota
	SignatureTypeEd25519Raw
	SignatureTypeCMSDetachedX509
)

type SignedRulesHeader

type SignedRulesHeader struct {
	HeaderVersion          uint32
	HeaderSize             uint32
	CompiledArch           string
	RuleDataSize           uint64
	MetadataOffset         uint64
	MetadataSize           uint64
	GenerationTime         time.Time
	SigningTime            time.Time
	SignatureType          SignatureType
	SignatureHashAlgorithm SignatureHashAlgorithm
}

SignedRulesHeader describes the fixed header stored ahead of signed compiled rules binaries.

type SignedRulesSigner

type SignedRulesSigner interface {
	SignatureType() SignatureType
	HashAlgorithm() SignatureHashAlgorithm
	SignSignedRules(header SignedRulesHeader, metadata []byte, signedBytes []byte) ([]byte, error)
}

SignedRulesSigner signs the header and payload bytes of a signed rules file.

type SignedRulesSignerFunc

type SignedRulesSignerFunc struct {
	SignatureTypeValue SignatureType
	HashAlgorithmValue SignatureHashAlgorithm
	SignFunc           func(header SignedRulesHeader, metadata []byte, signedBytes []byte) ([]byte, error)
}

SignedRulesSignerFunc adapts a function into a SignedRulesSigner.

func (SignedRulesSignerFunc) HashAlgorithm

func (fn SignedRulesSignerFunc) HashAlgorithm() SignatureHashAlgorithm

HashAlgorithm implements SignedRulesSigner.

func (SignedRulesSignerFunc) SignSignedRules

func (fn SignedRulesSignerFunc) SignSignedRules(header SignedRulesHeader, metadata []byte, signedBytes []byte) ([]byte, error)

SignSignedRules implements SignedRulesSigner.

func (SignedRulesSignerFunc) SignatureType

func (fn SignedRulesSignerFunc) SignatureType() SignatureType

SignatureType implements SignedRulesSigner.

type SignedRulesVerifier

type SignedRulesVerifier interface {
	VerifySignedRules(header SignedRulesHeader, metadata []byte, signedBytes []byte, signature []byte) error
}

SignedRulesVerifier verifies a signed rules payload.

type SignedRulesVerifierFunc

type SignedRulesVerifierFunc func(header SignedRulesHeader, metadata []byte, signedBytes []byte, signature []byte) error

SignedRulesVerifierFunc adapts a function into a SignedRulesVerifier.

func (SignedRulesVerifierFunc) VerifySignedRules

func (fn SignedRulesVerifierFunc) VerifySignedRules(header SignedRulesHeader, metadata []byte, signedBytes []byte, signature []byte) error

VerifySignedRules implements SignedRulesVerifier.

type SignedRulesWriteOption

type SignedRulesWriteOption interface {
	// contains filtered or unexported methods
}

SignedRulesWriteOption configures Rules.WriteSignedTo.

type SourceOption

type SourceOption func(opt *sourceOptions) error

A SourceOption represents an option passed to Compiler.AddSource.

func WithOrigin

func WithOrigin(origin string) SourceOption

WithOrigin is an option for Compiler.AddSource that specifies the origin of the source code.

type Span

type Span struct {
	Start int `json:"start"`
	End   int `json:"end"`
}

Span represents the starting and ending point of some piece of source code.

type TimestampAuthority

type TimestampAuthority interface {
	Timestamp(requestDER []byte) ([]byte, error)
}

TimestampAuthority acquires RFC3161 timestamp responses for detached CMS signatures.

func NewHTTPTimestampAuthority

func NewHTTPTimestampAuthority(url string, client *http.Client) TimestampAuthority

NewHTTPTimestampAuthority returns a TimestampAuthority that fetches RFC3161 timestamps over HTTP.

type VerifiedSignedRules

type VerifiedSignedRules struct {
	Header        SignedRulesHeader
	Metadata      []byte
	Signature     []byte
	CompiledRules []byte
}

VerifiedSignedRules contains a verified signed-rules container.

func VerifySignedFrom

func VerifySignedFrom(r io.Reader, verifier SignedRulesVerifier) (*VerifiedSignedRules, error)

VerifySignedFrom verifies a signed compiled rules container using the provided verifier.

type Warning

type Warning struct {
	Type    WarningType `json:"type"`
	Code    string      `json:"code"`
	Title   string      `json:"title"`
	Line    int         `json:"line"`
	Column  int         `json:"column"`
	Labels  []Label     `json:"labels,omitempty"`
	Footers []Footer    `json:"footers,omitempty"`
	Text    string      `json:"text"`
}

Warning represents each of the warnings returned by Compiler.Warnings.

func (Warning) CodeID

func (w Warning) CodeID() WarningCode

CodeID returns the warning code as a typed identifier.

func (Warning) HasCode

func (w Warning) HasCode(code WarningCode) bool

HasCode reports whether the warning uses the requested code.

func (Warning) HasType

func (w Warning) HasType(t WarningType) bool

HasType reports whether the warning is the requested concrete type.

type WarningCode

type WarningCode string

WarningCode identifies a compiler warning code emitted by yaraxwasm.

const (
	WarningCodeAmbiguousExpression                WarningCode = "ambiguous_expr"
	WarningCodeBooleanIntegerComparison           WarningCode = "bool_int_comparison"
	WarningCodeConsecutiveJumps                   WarningCode = "consecutive_jumps"
	WarningCodeDeprecatedField                    WarningCode = "deprecated_field"
	WarningCodeDuplicateImport                    WarningCode = "duplicate_import"
	WarningCodeGlobalRuleMisuse                   WarningCode = "global_rule_misuse"
	WarningCodeIgnoredModule                      WarningCode = "unsupported_module"
	WarningCodeIgnoredRule                        WarningCode = "ignored_rule"
	WarningCodeInvalidMetadata                    WarningCode = "invalid_metadata"
	WarningCodeInvalidRuleName                    WarningCode = "invalid_rule_name"
	WarningCodeInvalidTag                         WarningCode = "invalid_tag"
	WarningCodeInvariantBooleanExpression         WarningCode = "invariant_expr"
	WarningCodeMissingMetadata                    WarningCode = "missing_metadata"
	WarningCodeNonBooleanAsBoolean                WarningCode = "non_bool_expr"
	WarningCodePotentiallySlowLoop                WarningCode = "potentially_slow_loop"
	WarningCodePotentiallyUnsatisfiableExpression WarningCode = "unsatisfiable_expr"
	WarningCodeRedundantCaseModifier              WarningCode = "redundant_modifier"
	WarningCodeSlowPattern                        WarningCode = "slow_pattern"
	WarningCodeTextPatternAsHex                   WarningCode = "text_as_hex"
	WarningCodeTooManyIterations                  WarningCode = "too_many_iterations"
	WarningCodeUnknownTag                         WarningCode = "unknown_tag"
	WarningCodeUnsatisfiableExpression            WarningCode = "unsatisfiable_expr"
	WarningCodeUnusedIdentifier                   WarningCode = "unused_identifier"
)

type WarningType

type WarningType string

WarningType identifies a concrete compiler warning variant emitted by yaraxwasm.

const (
	WarningTypeAmbiguousExpression                WarningType = "AmbiguousExpression"
	WarningTypeBooleanIntegerComparison           WarningType = "BooleanIntegerComparison"
	WarningTypeConsecutiveJumps                   WarningType = "ConsecutiveJumps"
	WarningTypeDeprecatedField                    WarningType = "DeprecatedField"
	WarningTypeDuplicateImport                    WarningType = "DuplicateImport"
	WarningTypeGlobalRuleMisuse                   WarningType = "GlobalRuleMisuse"
	WarningTypeIgnoredModule                      WarningType = "IgnoredModule"
	WarningTypeIgnoredRule                        WarningType = "IgnoredRule"
	WarningTypeInvalidMetadata                    WarningType = "InvalidMetadata"
	WarningTypeInvalidRuleName                    WarningType = "InvalidRuleName"
	WarningTypeInvalidTag                         WarningType = "InvalidTag"
	WarningTypeInvariantBooleanExpression         WarningType = "InvariantBooleanExpression"
	WarningTypeMissingMetadata                    WarningType = "MissingMetadata"
	WarningTypeNonBooleanAsBoolean                WarningType = "NonBooleanAsBoolean"
	WarningTypePotentiallySlowLoop                WarningType = "PotentiallySlowLoop"
	WarningTypePotentiallyUnsatisfiableExpression WarningType = "PotentiallyUnsatisfiableExpression"
	WarningTypeRedundantCaseModifier              WarningType = "RedundantCaseModifier"
	WarningTypeSlowPattern                        WarningType = "SlowPattern"
	WarningTypeTextPatternAsHex                   WarningType = "TextPatternAsHex"
	WarningTypeTooManyIterations                  WarningType = "TooManyIterations"
	WarningTypeUnknownTag                         WarningType = "UnknownTag"
	WarningTypeUnsatisfiableExpression            WarningType = "UnsatisfiableExpression"
	WarningTypeUnusedIdentifier                   WarningType = "UnusedIdentifier"
)

type X509CRLPolicy

type X509CRLPolicy uint8

X509CRLPolicy controls how CRLs are enforced during x509 verification.

const (
	X509CRLPolicyDisabled X509CRLPolicy = iota
	X509CRLPolicyUseIfPresent
	X509CRLPolicyRequireComplete
)

type X509SignOption

type X509SignOption interface {
	// contains filtered or unexported methods
}

X509SignOption configures Rules.WriteX509SignedTo.

func WithTimestampAuthority

func WithTimestampAuthority(authority TimestampAuthority) X509SignOption

WithTimestampAuthority configures an RFC3161 timestamp authority for Rules.WriteX509SignedTo.

func WithX509CRLs

func WithX509CRLs(crls ...[]byte) X509SignOption

WithX509CRLs embeds CRL DER blobs in the x509 metadata envelope written by Rules.WriteX509SignedTo.

type X509TimestampPolicy

type X509TimestampPolicy uint8

X509TimestampPolicy controls RFC3161 timestamp enforcement during x509 verification.

const (
	X509TimestampPolicyDisabled X509TimestampPolicy = iota
	X509TimestampPolicyVerifyIfPresent
	X509TimestampPolicyRequireRFC3161
)

type X509VerificationResult

type X509VerificationResult struct {
	Signer            *x509.Certificate
	Chain             []*x509.Certificate
	TimestampVerified bool
	TimestampTime     time.Time
}

X509VerificationResult describes the signer and timestamp state for a verified x509/CMS signed rules container.

type X509VerifyOptions

type X509VerifyOptions struct {
	Roots                   *x509.CertPool
	AdditionalIntermediates *x509.CertPool
	RequiredEKUs            []x509.ExtKeyUsage
	RequiredUnknownEKUs     []asn1.ObjectIdentifier
	CurrentTime             time.Time
	CRLPolicy               X509CRLPolicy
	AdditionalCRLs          [][]byte
	TimestampPolicy         X509TimestampPolicy
	TSARoots                *x509.CertPool
	TSAIntermediates        *x509.CertPool
	AllowedClockSkew        time.Duration
}

X509VerifyOptions configures VerifyX509SignedFrom.

Directories

Path Synopsis
examples
internal/exampleutil
Package exampleutil contains shared helpers used by the runnable examples.
Package exampleutil contains shared helpers used by the runnable examples.
Package experimental contains unstable extensions for advanced yaraxwasm runtime configuration.
Package experimental contains unstable extensions for advanced yaraxwasm runtime configuration.
internal

Jump to

Keyboard shortcuts

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