sigsci

package module
v1.6.2 Latest Latest
Warning

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

Go to latest
Published: Aug 26, 2019 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 an http.Handler wrapper. To integrate your application with the module, you will need to wrap your existing handler with the module handler.

Installation

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

Example Code Snippet

// 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 directory contains complete example code.

To run the simple helloworld example:

go run examples/helloworld/main.go

Or, if your agent is running with a non-default rpc-address, you can pass the sigsci-agent address as an argument such as one of the following:

# Another UNIX Domain socket
go run examples/helloworld/main.go /tmp/sigsci.sock
# A TCP address:port
go run examples/helloworld/main.go localhost:9999

This will run an HTTP listener on localhost:8000, which will send any traffic to this listener to a running sigsci-agent for inspection.

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

This section is empty.

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) 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 ModuleConfigOption

type ModuleConfigOption func(*Module) 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 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 CustomHeaderExtractor added in v1.6.2

func CustomHeaderExtractor(fn func(r *http.Request) (http.Header, error)) ModuleConfigOption

CustomHeaderExtractor 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 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 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 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(r *http.Request, postbody []byte, code int, size int64, dur time.Duration, module, server string) *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 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