sigsci

package module
v1.13.0 Latest Latest
Warning

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

Go to latest
Published: Jul 6, 2023 License: MIT Imports: 18 Imported by: 1

README ¶

grc GoDoc

sigsci-module-golang

The Signal Sciences module in Golang allows for integrating your Golang application directly with the Signal Sciences agent at the source code level. It is written as a http.Handler wrapper. To integrate your application with the module, you will need to wrap your existing handler with the module handler.

🚨 NOTICE 🚨

Effective May 17th 2021 the default branch will change from master to main. Run the following commands to update a local clone:

git branch -m master main
git fetch origin
git branch -u origin/main main
git remote set-head origin -a

Installation

go get github.com/signalsciences/sigsci-module-golang@latest

Example Code Snippet

// Example existing http.Handler
mux := http.NewServeMux()
mux.HandleFunc("/", helloworld)

// Wrap the existing http.Handler with the SigSci module handler
wrapped, err := sigsci.NewModule(
    // Existing handler to wrap
    mux,

    // Any additional module options:
    //sigsci.Socket("unix", "/var/run/sigsci.sock"),
    //sigsci.Timeout(100 * time.Millisecond),
    //sigsci.AnomalySize(512 * 1024),
    //sigsci.AnomalyDuration(1 * time.Second),
    //sigsci.MaxContentLength(100000),
)
if err != nil {
    log.Fatal(err)
}

// Listen and Serve as usual using the wrapped sigsci handler
s := &http.Server{
    Handler: wrapped,
    Addr:    "localhost:8000",
}
log.Fatal(s.ListenAndServe())

Examples

The examples/helloworld directory contains complete example code.

To run the simple helloworld example:

# Syntax:
#   go run ./examples/helloworld <listener-address:port> [<sigsci-agent-rpc-address>]
#
# Run WITHOUT sigsci enabled
go run ./examples/helloworld localhost:8000
# Run WITH sigsci-agent listening via a UNIX Domain socket file
go run ./examples/helloworld localhost:8000 /var/run/sigsci.sock
# Run WITH sigsci-agent listening via a TCP address:port
go run ./examples/helloworld localhost:8000 localhost:9999

The above will run a HTTP listener on localhost:8000, which will send any traffic to this listener to a running sigsci-agent for inspection (if an agent address is configured).

Documentation ¶

Overview ¶

Example ¶
package main

import (
	"fmt"
	"log"
	"net/http"
	"time"

	sigsci "github.com/signalsciences/sigsci-module-golang"
)

func helloWorld(w http.ResponseWriter, r *http.Request) {
	fmt.Fprintf(w, "Hello, %s!", r.URL.Path[1:])
}

func main() {
	// Existing http.Handler
	mux := http.NewServeMux()
	mux.HandleFunc("/", helloWorld)

	// Wrap the existing http.Handler with the SigSci module handler
	wrapped, err := sigsci.NewModule(
		// Existing handler to wrap
		mux,

		// Any additional module options:
		sigsci.Socket("unix", "/var/run/sigsci.sock"),
		sigsci.Timeout(100*time.Millisecond),
		sigsci.AnomalySize(512*1024),
		sigsci.AnomalyDuration(1*time.Second),
		sigsci.MaxContentLength(100000),
	)

	if err != nil {
		log.Fatal(err)
	}

	// Listen and Serve as usual using the wrapped sigsci handler
	s := &http.Server{
		Handler: wrapped,
		Addr:    "localhost:8000",
	}

	log.Fatal(s.ListenAndServe())
}
Output:

Index ¶

Examples ¶

Constants ¶

This section is empty.

Variables ¶

View Source
var (
	// DefaultAllowUnknownContentLength is the default value
	DefaultAllowUnknownContentLength = false
	// DefaultAnomalyDuration is the default value
	DefaultAnomalyDuration = 1 * time.Second
	// DefaultAnomalySize is the default value
	DefaultAnomalySize = int64(512 * 1024)
	// DefaultDebug is the default value
	DefaultDebug = false
	// DefaultInspector is the default value
	DefaultInspector = Inspector(nil)
	// DefaultMaxContentLength is the default value
	DefaultMaxContentLength = int64(100000)
	// DefaultModuleIdentifier is the default value
	DefaultModuleIdentifier = "sigsci-module-golang " + version
	// DefaultRPCAddress is the default value
	DefaultRPCAddress = "/var/run/sigsci.sock"
	// DefaultRPCNetwork is the default value
	DefaultRPCNetwork = "unix"
	// DefaultTimeout is the default value
	DefaultTimeout = 100 * time.Millisecond
	// DefaultServerIdentifier is the default value
	DefaultServerIdentifier = runtime.Version()
	// DefaultServerFlavor is the default value
	DefaultServerFlavor = ""
)

Functions ¶

func NewMsgpClientCodec ¶

func NewMsgpClientCodec(conn io.ReadWriteCloser) rpc.ClientCodec

NewMsgpClientCodec creates a new rpc.ClientCodec from an existing connection

func Version ¶

func Version() string

Version returns a SemVer version string

Types ¶

type Inspector ¶

type Inspector interface {
	// ModuleInit can be called when the module starts up. This allows the module
	// data (e.g., `ModuleVersion`, `ServerVersion`, `ServerFlavor`, etc.) to be
	// sent to the collector so that the agent shows up initialized without having
	// to wait for data to be sent through the inspector. This should only be called
	// once when the app/module starts.
	ModuleInit(*RPCMsgIn, *RPCMsgOut) error
	// PreRequest is called before the request is processed by the app. The results
	// should be analyzed for any anomalies or blocking conditions. In addition, any
	// `RequestID` returned in the response should be recorded for future use.
	PreRequest(*RPCMsgIn, *RPCMsgOut) error
	// PostRequest is called after the request has been processed by the app and the
	// response data (e.g., status code, headers, etc.) is available. This should be
	// called if there was NOT a `RequestID` in the response to a previous `PreRequest`
	// call for the same transaction (if a `RequestID` was in the response, then it
	// should be used in an `UpdateRequest` call instead).
	PostRequest(*RPCMsgIn, *RPCMsgOut) error
	// UpdateRequest is called after the request has been processed by the app and the
	// response data (e.g., status code, headers, etc.) is available. This should be used
	// instead of a `PostRequest` call when a prior `PreRequest` call for the same
	// transaction included a `RequestID`. In this case, this call is updating the data
	// collected in the `PreRequest` with the given response data (e.g., status code,
	// headers, etc.).
	UpdateRequest(*RPCMsgIn2, *RPCMsgOut) error
}

Inspector is an interface to implement how the module communicates with the inspection engine.

type InspectorFiniFunc ¶

type InspectorFiniFunc func(*http.Request)

InspectorFiniFunc is called after any inspection on the request is completed

type InspectorInitFunc ¶

type InspectorInitFunc func(*http.Request) bool

InspectorInitFunc is called to decide if the request should be inspected Return true if inspection should occur for the request or false if inspection should be bypassed.

type Module ¶

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

Module is an http.Handler that wraps an existing handler with data collection and sends it to the Signal Sciences Agent for inspection.

func NewModule ¶

func NewModule(h http.Handler, options ...ModuleConfigOption) (*Module, error)

NewModule wraps an existing http.Handler with one that extracts data and sends it to the Signal Sciences Agent for inspection. The module is configured via functional options.

func (*Module) Inspector ¶

func (m *Module) Inspector() Inspector

Inspector returns the configured inspector

func (*Module) ModuleConfig ¶ added in v1.7.0

func (m *Module) ModuleConfig() *ModuleConfig

ModuleConfig returns the module configuration

func (*Module) ServeHTTP ¶

func (m *Module) ServeHTTP(w http.ResponseWriter, req *http.Request)

ServeHTTP satisfies the http.Handler interface

func (*Module) ServerVersion ¶

func (m *Module) ServerVersion() string

ServerVersion returns the server version string

func (*Module) Version ¶

func (m *Module) Version() string

Version returns the module version string

type ModuleConfig ¶ added in v1.7.0

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

ModuleConfig is a configuration object for a Module

func NewModuleConfig ¶ added in v1.7.0

func NewModuleConfig(options ...ModuleConfigOption) (*ModuleConfig, error)

NewModuleConfig returns an object with any options set

func (*ModuleConfig) AllowUnknownContentLength ¶ added in v1.7.0

func (c *ModuleConfig) AllowUnknownContentLength() bool

AllowUnknownContentLength returns the configuration value

func (*ModuleConfig) AltResponseCodes deprecated added in v1.7.0

func (c *ModuleConfig) AltResponseCodes() []int

AltResponseCodes returns the configuration value

Deprecated: The `AltResponseCodes` concept has been deprecated in favor of treating all response codes 300-599 as blocking codes. Due to this, this method will always return nil. It is left here to avoid breakage, but will eventually be removed.

func (*ModuleConfig) AnomalyDuration ¶ added in v1.7.0

func (c *ModuleConfig) AnomalyDuration() time.Duration

AnomalyDuration returns the configuration value

func (*ModuleConfig) AnomalySize ¶ added in v1.7.0

func (c *ModuleConfig) AnomalySize() int64

AnomalySize returns the configuration value

func (*ModuleConfig) Debug ¶ added in v1.7.0

func (c *ModuleConfig) Debug() bool

Debug returns the configuration value

func (*ModuleConfig) ExpectedContentTypes ¶ added in v1.11.0

func (c *ModuleConfig) ExpectedContentTypes() []string

ExpectedContentTypes returns the slice of additional custom content types

func (*ModuleConfig) Inspector ¶ added in v1.7.0

func (c *ModuleConfig) Inspector() Inspector

Inspector returns the inspector

func (*ModuleConfig) InspectorFini ¶ added in v1.7.0

func (c *ModuleConfig) InspectorFini() InspectorFiniFunc

InspectorFini returns the inspector fini function

func (*ModuleConfig) InspectorInit ¶ added in v1.7.0

func (c *ModuleConfig) InspectorInit() InspectorInitFunc

InspectorInit returns the inspector init function

func (*ModuleConfig) IsAllowCode ¶ added in v1.7.0

func (c *ModuleConfig) IsAllowCode(code int) bool

IsAllowCode returns true if the code is an allow code

func (*ModuleConfig) IsBlockCode ¶ added in v1.7.0

func (c *ModuleConfig) IsBlockCode(code int) bool

IsBlockCode returns true if the code is a configured block code

func (*ModuleConfig) IsExpectedContentType ¶ added in v1.11.0

func (c *ModuleConfig) IsExpectedContentType(s string) bool

IsExpectedContentType returns true if the given content type string is in the list of configured custom Content-Types

func (*ModuleConfig) MaxContentLength ¶ added in v1.7.0

func (c *ModuleConfig) MaxContentLength() int64

MaxContentLength returns the configuration value

func (*ModuleConfig) ModuleIdentifier ¶ added in v1.7.0

func (c *ModuleConfig) ModuleIdentifier() string

ModuleIdentifier returns the configuration value

func (*ModuleConfig) RPCAddress ¶ added in v1.7.0

func (c *ModuleConfig) RPCAddress() string

RPCAddress returns the configuration value

func (*ModuleConfig) RPCAddressString ¶ added in v1.7.0

func (c *ModuleConfig) RPCAddressString() string

RPCAddressString returns the RPCNetwork/RPCAddress as a combined string

func (*ModuleConfig) RPCNetwork ¶ added in v1.7.0

func (c *ModuleConfig) RPCNetwork() string

RPCNetwork returns the configuration value

func (*ModuleConfig) RawHeaderExtractor ¶ added in v1.12.0

func (c *ModuleConfig) RawHeaderExtractor() RawHeaderExtractorFunc

RawHeaderExtractor returns the configuration value

func (*ModuleConfig) ServerFlavor ¶ added in v1.9.0

func (c *ModuleConfig) ServerFlavor() string

ServerFlavor returns the configuration value

func (*ModuleConfig) ServerIdentifier ¶ added in v1.7.0

func (c *ModuleConfig) ServerIdentifier() string

ServerIdentifier returns the configuration value

func (*ModuleConfig) SetOptions ¶ added in v1.7.0

func (c *ModuleConfig) SetOptions(options ...ModuleConfigOption) error

SetOptions sets options specified as functional arguments

func (*ModuleConfig) Timeout ¶ added in v1.7.0

func (c *ModuleConfig) Timeout() time.Duration

Timeout returns the configuration value

type ModuleConfigOption ¶

type ModuleConfigOption func(*ModuleConfig) error

ModuleConfigOption is a functional config option for configuring the module See: https://dave.cheney.net/2014/10/17/functional-options-for-friendly-apis

func AllowUnknownContentLength ¶ added in v1.6.4

func AllowUnknownContentLength(allow bool) ModuleConfigOption

AllowUnknownContentLength is a function argument to set the ability to read the body when the content length is not specified.

NOTE: This can be dangerous (fill RAM) if set when the max content

length is not limited by the server itself. This is intended
for use with gRPC where the max message receive length is limited.
Do NOT enable this if there is no limit set on the request
content length!

func AltResponseCodes deprecated added in v1.7.0

func AltResponseCodes(codes ...int) ModuleConfigOption

AltResponseCodes is a function argument to set the alternative response codes from the agent that are considered "blocking"

Deprecated: The `AltResponseCodes` concept has been deprecated in favor of treating all response codes 300-599 as blocking codes. Due to this, this method will always return nil. It is left here to avoid breakage, but will eventually be removed.

func AnomalyDuration ¶

func AnomalyDuration(dur time.Duration) ModuleConfigOption

AnomalyDuration is a function argument to indicate when to send data to the inspector if the response was abnormally slow

func AnomalySize ¶

func AnomalySize(size int64) ModuleConfigOption

AnomalySize is a function argument to indicate when to send data to the inspector if the response was abnormally large

func CustomInspector ¶

func CustomInspector(insp Inspector, init InspectorInitFunc, fini InspectorFiniFunc) ModuleConfigOption

CustomInspector is a function argument that sets a custom inspector, an optional inspector initializer to decide if inspection should occur, and an optional inspector finalizer that can perform any post-inspection steps

func Debug ¶

func Debug(enable bool) ModuleConfigOption

Debug turns on debug logging

func ExpectedContentType ¶ added in v1.11.0

func ExpectedContentType(s string) ModuleConfigOption

ExpectedContentType is a function argument that adds a custom Content-Type that should have request bodies sent to the agent for inspection

func ExtendContentTypes ¶ added in v1.13.0

func ExtendContentTypes(v bool) ModuleConfigOption

ExtendContentTypes is a function argument to indicate that send request body of any content-type to the agent for inspection

func FromModuleConfig ¶ added in v1.7.0

func FromModuleConfig(mcfg *ModuleConfig) ModuleConfigOption

FromModuleConfig allow cloning the config

func MaxContentLength ¶

func MaxContentLength(size int64) ModuleConfigOption

MaxContentLength is a function argument to set the maximum post body length that will be processed

func ModuleIdentifier ¶

func ModuleIdentifier(name, version string) ModuleConfigOption

ModuleIdentifier is a function argument that sets the module name and version for custom setups. The version should be a sem-version (e.g., "1.2.3")

func RawHeaderExtractor ¶ added in v1.12.0

func RawHeaderExtractor(fn RawHeaderExtractorFunc) ModuleConfigOption

RawHeaderExtractor is a function argument that sets a function to extract an alternative header object from the request. It is primarily intended only for internal use.

func ServerFlavor ¶ added in v1.9.0

func ServerFlavor(serverFlavor string) ModuleConfigOption

ServerFlavor is a function argument that sets the server flavor for custom setups using revproxy.

func ServerIdentifier ¶

func ServerIdentifier(id string) ModuleConfigOption

ServerIdentifier is a function argument that sets the server identifier for custom setups

func Socket ¶

func Socket(network, address string) ModuleConfigOption

Socket is a function argument to set where to send data to the Signal Sciences Agent. The network argument should be `unix` or `tcp` and the corresponding address should be either an absolute path or an `address:port`, respectively.

func Timeout ¶

func Timeout(t time.Duration) ModuleConfigOption

Timeout is a function argument that sets the maximum time to wait until receiving a reply from the inspector. Once this timeout is reached, the module will fail open.

type RPCInspector ¶

type RPCInspector struct {
	Network           string
	Address           string
	Timeout           time.Duration
	Debug             bool
	InitRPCClientFunc func() (*rpc.Client, error)
	FiniRPCClientFunc func(*rpc.Client, error)
}

RPCInspector is an Inspector implemented as RPC calls to the agent

func (*RPCInspector) CloseRPCClient ¶

func (ri *RPCInspector) CloseRPCClient(client *rpc.Client, err error)

CloseRPCClient closes a RPC client

func (*RPCInspector) GetRPCClient ¶

func (ri *RPCInspector) GetRPCClient() (*rpc.Client, error)

GetRPCClient gets a RPC client

func (*RPCInspector) ModuleInit ¶

func (ri *RPCInspector) ModuleInit(in *RPCMsgIn, out *RPCMsgOut) error

ModuleInit sends a RPC.ModuleInit message to the agent

func (*RPCInspector) PostRequest ¶

func (ri *RPCInspector) PostRequest(in *RPCMsgIn, out *RPCMsgOut) error

PostRequest sends a RPC.PostRequest message to the agent

func (*RPCInspector) PreRequest ¶

func (ri *RPCInspector) PreRequest(in *RPCMsgIn, out *RPCMsgOut) error

PreRequest sends a RPC.PreRequest message to the agent

func (*RPCInspector) UpdateRequest ¶

func (ri *RPCInspector) UpdateRequest(in *RPCMsgIn2, out *RPCMsgOut) error

UpdateRequest sends a RPC.UpdateRequest message to the agent

type RPCMsgIn ¶

type RPCMsgIn struct {
	AccessKeyID    string      // AccessKeyID optional, what Site does this belong too (deprecated)
	ModuleVersion  string      // The module build version
	ServerVersion  string      // Main server identifier "apache 2.0.46..."
	ServerFlavor   string      // Any other webserver configuration info  (optional)
	ServerName     string      // As in request website URL
	Timestamp      int64       // Start of request in the number of seconds elapsed since January 1, 1970 UTC.
	NowMillis      int64       // Current time, the number of milliseconds elapsed since January 1, 1970 UTC.
	RemoteAddr     string      // Remote IP Address, from request socket
	Method         string      // GET/POST, etc...
	Scheme         string      // http/https
	URI            string      // /path?query
	Protocol       string      // HTTP protocol
	TLSProtocol    string      // e.g. TLSv1.2
	TLSCipher      string      // e.g. ECDHE-RSA-AES128-GCM-SHA256
	WAFResponse    int32       // Optional
	ResponseCode   int32       // HTTP Response Status Code, -1 if unknown
	ResponseMillis int64       // HTTP Milliseconds - How many milliseconds did the full request take, -1 if unknown
	ResponseSize   int64       // HTTP Response size, -1 if unknown
	HeadersIn      [][2]string // HTTP Request headers (slice of name/value pairs); nil ok
	HeadersOut     [][2]string // HTTP Response headers (slice of name/value pairs); nil ok
	PostBody       string      // HTTP Request body; empty string if none
}

RPCMsgIn is the primary message from the webserver module to the agent

func NewRPCMsgIn ¶

func NewRPCMsgIn(mcfg *ModuleConfig, r *http.Request, postbody []byte, code int, size int64, dur time.Duration) *RPCMsgIn

NewRPCMsgIn creates a message from a go http.Request object End-users of the golang module never need to use this directly and it is only exposed for performance testing

func (*RPCMsgIn) DecodeMsg ¶

func (z *RPCMsgIn) DecodeMsg(dc *msgp.Reader) (err error)

DecodeMsg implements msgp.Decodable

func (*RPCMsgIn) EncodeMsg ¶

func (z *RPCMsgIn) EncodeMsg(en *msgp.Writer) (err error)

EncodeMsg implements msgp.Encodable

func (*RPCMsgIn) MarshalMsg ¶

func (z *RPCMsgIn) MarshalMsg(b []byte) (o []byte, err error)

MarshalMsg implements msgp.Marshaler

func (*RPCMsgIn) Msgsize ¶

func (z *RPCMsgIn) Msgsize() (s int)

Msgsize returns an upper bound estimate of the number of bytes occupied by the serialized message

func (*RPCMsgIn) UnmarshalMsg ¶

func (z *RPCMsgIn) UnmarshalMsg(bts []byte) (o []byte, err error)

UnmarshalMsg implements msgp.Unmarshaler

type RPCMsgIn2 ¶

type RPCMsgIn2 struct {
	RequestID      string // The request id (UUID)
	ResponseCode   int32  // HTTP status code did the webserver send back
	ResponseMillis int64  // How many milliseconds did the full request take
	ResponseSize   int64  // how many bytes did the webserver send back
	HeadersOut     [][2]string
}

RPCMsgIn2 is a follow-up message from the webserver to the Agent Note there is no formal response to this message

func (*RPCMsgIn2) DecodeMsg ¶

func (z *RPCMsgIn2) DecodeMsg(dc *msgp.Reader) (err error)

DecodeMsg implements msgp.Decodable

func (*RPCMsgIn2) EncodeMsg ¶

func (z *RPCMsgIn2) EncodeMsg(en *msgp.Writer) (err error)

EncodeMsg implements msgp.Encodable

func (*RPCMsgIn2) MarshalMsg ¶

func (z *RPCMsgIn2) MarshalMsg(b []byte) (o []byte, err error)

MarshalMsg implements msgp.Marshaler

func (*RPCMsgIn2) Msgsize ¶

func (z *RPCMsgIn2) Msgsize() (s int)

Msgsize returns an upper bound estimate of the number of bytes occupied by the serialized message

func (*RPCMsgIn2) UnmarshalMsg ¶

func (z *RPCMsgIn2) UnmarshalMsg(bts []byte) (o []byte, err error)

UnmarshalMsg implements msgp.Unmarshaler

type RPCMsgOut ¶

type RPCMsgOut struct {
	WAFResponse    int32
	RequestID      string      `json:",omitempty"` // Set if the server expects an UpdateRequest with this ID (UUID)
	RequestHeaders [][2]string `json:",omitempty"` // Any additional information in the form of additional request headers
}

RPCMsgOut is sent back to the webserver

func (*RPCMsgOut) DecodeMsg ¶

func (z *RPCMsgOut) DecodeMsg(dc *msgp.Reader) (err error)

DecodeMsg implements msgp.Decodable

func (*RPCMsgOut) EncodeMsg ¶

func (z *RPCMsgOut) EncodeMsg(en *msgp.Writer) (err error)

EncodeMsg implements msgp.Encodable

func (*RPCMsgOut) MarshalMsg ¶

func (z *RPCMsgOut) MarshalMsg(b []byte) (o []byte, err error)

MarshalMsg implements msgp.Marshaler

func (*RPCMsgOut) Msgsize ¶

func (z *RPCMsgOut) Msgsize() (s int)

Msgsize returns an upper bound estimate of the number of bytes occupied by the serialized message

func (*RPCMsgOut) UnmarshalMsg ¶

func (z *RPCMsgOut) UnmarshalMsg(bts []byte) (o []byte, err error)

UnmarshalMsg implements msgp.Unmarshaler

type RawHeaderExtractorFunc ¶ added in v1.12.0

type RawHeaderExtractorFunc func(*http.Request) [][2]string

RawHeaderExtractorFunc is a header extraction function

type ResponseWriter ¶

type ResponseWriter interface {
	http.ResponseWriter
	BaseResponseWriter() http.ResponseWriter
	StatusCode() int
	BytesWritten() int64
}

ResponseWriter is a http.ResponseWriter allowing extraction of data needed for inspection

func NewResponseWriter ¶

func NewResponseWriter(base http.ResponseWriter) ResponseWriter

NewResponseWriter returns a ResponseWriter or ResponseWriterFlusher depending on the base http.ResponseWriter.

type ResponseWriterFlusher ¶

type ResponseWriterFlusher interface {
	ResponseWriter
	http.Flusher
}

ResponseWriterFlusher is a ResponseWriter with a http.Flusher interface

Directories ¶

Path Synopsis
examples

Jump to

Keyboard shortcuts

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