nasshp

package
v0.0.0-...-5f133c6 Latest Latest
Warning

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

Go to latest
Published: Apr 11, 2024 License: BSD-3-Clause, BSD-3-Clause Imports: 23 Imported by: 0

README

  • session archival and resume.
  • support for mosh
  • match on host name on the proxy
  • split confiugration, so only the map goes to the http proxy code.
  • ssh agent and client
  • redirect to the correct backend.
  • authenticate user using proxy.

options to use --proxy-host=gw.corp.enfabrica.net --proxy-port=... --resume-connection --use-ssl

implements protocol corp-relay@google.com

Documentation

Index

Examples

Constants

This section is empty.

Variables

View Source
var ErrorExpired = errors.New("timer expired")

ErrorExpired is returned by WaitFor when the timer expires without events.

View Source
var OriginMatcher = regexp.MustCompile(`^chrome(-extension)?://`)

Functions

func LogId

func LogId(sid string, r *http.Request, hostport string, c *oauth.CredentialsCookie) string

func NewBList

func NewBList() *blist

NewBList returns a newly initalized blist.

func ToAbsolute

func ToAbsolute(reference uint64, trunc uint32) uint64

Types

type AllowErrors

type AllowErrors struct {
	InvalidCookie     utils.Counter
	InvalidHostFormat utils.Counter
	InvalidHostName   utils.Counter
	Unauthorized      utils.Counter
}

type BlockingReceiveWindow

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

BlockingReceiveWindow allows to split the filling and emptying of a ReceiveWindow across different goroutines.

Specifically, it assumes that there is one goroutine calling ToFill and Fill, and another goroutine calling ToEmpty, Empty, and Reset.

Having more than one filling or more than one empting goroutine is unsupported.

func NewBlockingReceiveWindow

func NewBlockingReceiveWindow(pool *BufferPool, max uint64) *BlockingReceiveWindow

func (*BlockingReceiveWindow) Empty

func (b *BlockingReceiveWindow) Empty(size int)

func (*BlockingReceiveWindow) Fail

func (b *BlockingReceiveWindow) Fail(err error)

func (*BlockingReceiveWindow) Fill

func (b *BlockingReceiveWindow) Fill(size int) uint64

func (*BlockingReceiveWindow) Reset

func (b *BlockingReceiveWindow) Reset(wu uint32) error

func (*BlockingReceiveWindow) ToEmpty

func (b *BlockingReceiveWindow) ToEmpty() []byte

func (*BlockingReceiveWindow) ToFill

func (b *BlockingReceiveWindow) ToFill() []byte

func (*BlockingReceiveWindow) WaitToEmpty

func (b *BlockingReceiveWindow) WaitToEmpty() error

func (*BlockingReceiveWindow) WaitToFill

func (b *BlockingReceiveWindow) WaitToFill() error

type BlockingSendWindow

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

BlockingSendWindow allows to split the filling and emptying of a SendWindow across different goroutines.

Specifically, it assumes that there is one goroutine calling ToFill and Fill, and another goroutine calling ToEmpty, Empty, and possibly Reset and Acknowledge.

Note that the BlockingSendWindow still supports at most one sender and at most one receiver, not more.

func NewBlockingSendWindow

func NewBlockingSendWindow(pool *BufferPool, max uint64) *BlockingSendWindow

func (*BlockingSendWindow) AcknowledgeUntil

func (b *BlockingSendWindow) AcknowledgeUntil(wu uint32) (uint64, error)

func (*BlockingSendWindow) Empty

func (b *BlockingSendWindow) Empty(size int)

func (*BlockingSendWindow) Fail

func (b *BlockingSendWindow) Fail(err error)

func (*BlockingSendWindow) Fill

func (b *BlockingSendWindow) Fill(size int) uint64

func (*BlockingSendWindow) Reset

func (b *BlockingSendWindow) Reset(wu uint32) error

func (*BlockingSendWindow) ToEmpty

func (b *BlockingSendWindow) ToEmpty() []byte

func (*BlockingSendWindow) ToFill

func (b *BlockingSendWindow) ToFill() []byte

func (*BlockingSendWindow) WaitToEmpty

func (b *BlockingSendWindow) WaitToEmpty(d time.Duration) error

func (*BlockingSendWindow) WaitToFill

func (b *BlockingSendWindow) WaitToFill() error

type BrowserWindowCounters

type BrowserWindowCounters struct {
	BrowserWindowReset    utils.Counter
	BrowserWindowResumed  utils.Counter
	BrowserWindowStarted  utils.Counter
	BrowserWindowOrphaned utils.Counter
	BrowserWindowStopped  utils.Counter
	BrowserWindowReplaced utils.Counter
	BrowserWindowClosed   utils.Counter
}

type BufferPool

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

BufferPool is a sync.Pool of buffers, used to allocate (and free) nodes used by the window implementation below.

func NewBufferPool

func NewBufferPool(size int) *BufferPool

func (*BufferPool) Get

func (bp *BufferPool) Get() *buffer

func (*BufferPool) Put

func (bp *BufferPool) Put(b *buffer)

func (*BufferPool) Stats

func (bp *BufferPool) Stats() (uint64, uint64, uint64)

Stats returns statistics about the pool.

Specifically, it returns the number of times Get() was called, the number of times Put() was called, and the number of times a new object had to be greated.

The delta between Get()s and Put()s indicates how many buffers have been allocated but not returned to the pool. This does not necessarily mean a memory leak: the garbage collector is still able to free those objects if unreferenced - they just won't be reused through the pool.

Together with the number of new called, though, it can provide a good signal toward the efficacy of the pool.

type ExpirationPolicy

type ExpirationPolicy struct {
	// How often to run session garbage collection.
	Every time.Duration

	// If number of orphaned sessions exceed this threshold, the oldest
	// orphaned sessions will be terminated until fewer than this limit are
	// left, no matter what. This is meant to be a last resort option.
	RuthlessThreshold int

	// If number of orphaned sessions exceed this threshold, the oldest
	// sessions that have been orphaned for longer than OrphanLimit are
	// expired until either the number of sessions goes below
	// OrphanThreshold, or there are no orphaned sessions that have been
	// around longer than OrphanLimit.
	//
	// Tl;Dr: this only expires the oldest sessions that have been orphaned
	// for longer than OrphanLimit.
	OrphanThreshold int
	OrphanLimit     time.Duration
}

func DefaultExpirationPolicy

func DefaultExpirationPolicy() *ExpirationPolicy

func (*ExpirationPolicy) Expire

func (ep *ExpirationPolicy) Expire(ctx context.Context, clock utils.Clock, sessions *sessions, counters *ExpireCounters)

func (*ExpirationPolicy) Register

func (ep *ExpirationPolicy) Register(set kflags.FlagSet, prefix string)

type ExpireCounters

type ExpireCounters struct {
	ExpireRuns     utils.Counter
	ExpireDuration utils.Counter

	ExpireAboveOrphanThresholdRuns  utils.Counter
	ExpireAboveOrphanThresholdTotal utils.Counter
	ExpireAboveOrphanThresholdFound utils.Counter

	ExpireRaced utils.Counter

	ExpireOrphanClosed   utils.Counter
	ExpireRuthlessClosed utils.Counter
	ExpireLifetimeTotal  utils.Counter

	ExpireYoungest utils.Counter
}

type FailEmptyHost

type FailEmptyHost struct{}

FailEmptyHost is a Resolver that errors if host is empty, but otherwise returns the host and port unmodified.

func (*FailEmptyHost) Resolve

func (r *FailEmptyHost) Resolve(host, port string) (string, string, error)

type FailEmptyPort

type FailEmptyPort struct{}

FailEmptyPort is a Resolver that errors if port is empty, but otherwise returns the host and port unmodified.

func (*FailEmptyPort) Resolve

func (r *FailEmptyPort) Resolve(host, port string) (string, string, error)

type Filter

type Filter func(proto string, hostport string, creds *oauth.CredentialsCookie) utils.Verdict

type Flags

type Flags struct {
	*Timeouts
	*ExpirationPolicy

	SymmetricKey []byte
	BufferSize   int
	RelayHost    string
}

func DefaultFlags

func DefaultFlags() *Flags

func (*Flags) Register

func (fl *Flags) Register(set kflags.FlagSet, prefix string) *Flags

type Modifier

type Modifier func(*NasshProxy, *options) error

func FromFlags

func FromFlags(fl *Flags) Modifier

func WithBufferSize

func WithBufferSize(size int) Modifier

func WithExpirationPolicy

func WithExpirationPolicy(ep *ExpirationPolicy) Modifier

func WithFilter

func WithFilter(filter Filter) Modifier

func WithLogging

func WithLogging(log logger.Logger) Modifier

func WithOriginChecker

func WithOriginChecker(checker func(r *http.Request) bool) Modifier

func WithRelayHost

func WithRelayHost(relayHost string) Modifier

func WithResolver

func WithResolver(r Resolver) Modifier

func WithSymmetricOptions

func WithSymmetricOptions(mods ...token.SymmetricSetter) Modifier

func WithTimeouts

func WithTimeouts(timeouts *Timeouts) Modifier

type Modifiers

type Modifiers []Modifier

func (Modifiers) Apply

func (mods Modifiers) Apply(np *NasshProxy, o *options) error

type MultiResolver

type MultiResolver []Resolver

MultiResolver is a list of Resolvers that are applied in order until the list is exhausted or an error is encountered.

func (MultiResolver) Resolve

func (r MultiResolver) Resolve(host, port string) (string, string, error)

type MuxHandle

type MuxHandle func(pattern string, handler http.Handler)

MuxHandle is a function capable of instructing an http Mux to invoke an handler for a path.

pattern is a string representing a path without host (example: "/", or "/test"). No wildcards or field extraction is used by nasshp, only constants need to be supported by MuxHandle.

handler is the http.Handler to invoke for the specified path.

type NasshProxy

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

func New

func New(rng *rand.Rand, authenticator oauth.Authenticate, mods ...Modifier) (*NasshProxy, error)

New creates a new instance of a nasshp tunnel protocol.

rng MUST be a secure random number generator, use github.com/enfabrica/lib/srand in case of doubt to create one. authenticator is optional, can be left to nil to disable authentication.

mods MUST either contain FromFlags, to initialize all the nassh parameters from command line flags, or it MUST provide a symmetric key with nasshp.WithSymmetricOptions.

func (*NasshProxy) ExportMetrics

func (np *NasshProxy) ExportMetrics(register prometheus.Registerer) error

func (*NasshProxy) ProxySsh

func (np *NasshProxy) ProxySsh(logid string, r *http.Request, w http.ResponseWriter, sid string, rack, wack uint32, hostport string) error

func (*NasshProxy) Register

func (np *NasshProxy) Register(add MuxHandle)

Register is a convenience function to configure all the handlers in your favourite Mux.

It configures the http paths and corresponding handlers that are necessary for a nassh implementation to support.

Registering the paths can also be done manually. Rather than document the required paths in comments here,look at the source code of the function.

func (*NasshProxy) RelayHost

func (np *NasshProxy) RelayHost() string

func (*NasshProxy) Run

func (np *NasshProxy) Run(ctx context.Context)

Run starts nasshp background workers.

It should typically be started in a goroutine of its own.

It completes eiter when there are no workers to be run, or when the supplied ctx is canceled.

func (*NasshProxy) ServeConnect

func (np *NasshProxy) ServeConnect(w http.ResponseWriter, r *http.Request)

func (*NasshProxy) ServeCookie

func (np *NasshProxy) ServeCookie(w http.ResponseWriter, r *http.Request)

func (*NasshProxy) ServeProxy

func (np *NasshProxy) ServeProxy(w http.ResponseWriter, r *http.Request)

type ProxyCounters

type ProxyCounters struct {
	ReadWriterCounters

	SshProxyStarted utils.Counter
	SshProxyStopped utils.Counter
}

type ProxyErrors

type ProxyErrors struct {
	CookieInvalidParameters utils.Counter
	CookieInvalidAuth       utils.Counter

	ProxyInvalidAuth     utils.Counter
	ProxyInvalidHostPort utils.Counter
	ProxyCouldNotEncrypt utils.Counter
	ProxyAllow           AllowErrors

	ConnectInvalidSID utils.Counter
	ConnectInvalidAck utils.Counter
	ConnectInvalidPos utils.Counter
	ConnectAllow      AllowErrors

	SshFailedUpgrade utils.Counter
	SshResumeNoSID   utils.Counter
	SshCreateExists  utils.Counter
	SshDialFailed    utils.Counter
}

type ReadWriterCounters

type ReadWriterCounters struct {
	BrowserWindowCounters

	BrowserWriterStarted utils.Counter
	BrowserWriterStopped utils.Counter
	BrowserWriterError   utils.Counter

	BrowserReaderStarted utils.Counter
	BrowserReaderStopped utils.Counter
	BrowserReaderError   utils.Counter

	BrowserBytesRead  utils.Counter
	BackendBytesWrite utils.Counter

	BackendBytesRead  utils.Counter
	BrowserBytesWrite utils.Counter
}

type ReceiveWindow

type ReceiveWindow struct {
	Filled uint64 // Absolute counter of bytes Filled.

	Emptied uint64 // Absolute counter of bytes Emptied.
	// contains filtered or unexported fields
}

func NewReceiveWindow

func NewReceiveWindow(pool *BufferPool) *ReceiveWindow

func (*ReceiveWindow) Drop

func (sw *ReceiveWindow) Drop()

func (*ReceiveWindow) Empty

func (w *ReceiveWindow) Empty(size int)

func (*ReceiveWindow) Fill

func (w *ReceiveWindow) Fill(size int) uint64

func (*ReceiveWindow) Reset

func (w *ReceiveWindow) Reset(wack uint32) error

func (*ReceiveWindow) ToEmpty

func (w *ReceiveWindow) ToEmpty() []byte

func (*ReceiveWindow) ToFill

func (w *ReceiveWindow) ToFill() []byte

type ReplaceableBrowser

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

func NewReplaceableBrowser

func NewReplaceableBrowser(log logger.Logger, counters *BrowserWindowCounters) *ReplaceableBrowser

func (*ReplaceableBrowser) Close

func (gb *ReplaceableBrowser) Close(err error)

func (*ReplaceableBrowser) Error

func (gb *ReplaceableBrowser) Error(wc *websocket.Conn, err error)

func (*ReplaceableBrowser) Get

func (gb *ReplaceableBrowser) Get() (*websocket.Conn, error)

func (*ReplaceableBrowser) GetForReceive

func (gb *ReplaceableBrowser) GetForReceive() (*websocket.Conn, uint32, error)

func (*ReplaceableBrowser) GetForSend

func (gb *ReplaceableBrowser) GetForSend() (*websocket.Conn, uint32, uint32, error)

func (*ReplaceableBrowser) GetRack

func (gb *ReplaceableBrowser) GetRack() (*websocket.Conn, uint32, uint32, error)

func (*ReplaceableBrowser) GetWack

func (gb *ReplaceableBrowser) GetWack() (*websocket.Conn, uint32, uint32, error)

func (*ReplaceableBrowser) GetWriteReadUntil

func (gb *ReplaceableBrowser) GetWriteReadUntil() (uint32, uint32)

func (*ReplaceableBrowser) Init

func (gb *ReplaceableBrowser) Init(log logger.Logger, counters *BrowserWindowCounters)

func (*ReplaceableBrowser) PushReadUntil

func (gb *ReplaceableBrowser) PushReadUntil(ru uint32)

func (*ReplaceableBrowser) PushWrittenUntil

func (gb *ReplaceableBrowser) PushWrittenUntil(wu uint32)

func (*ReplaceableBrowser) Set

func (gb *ReplaceableBrowser) Set(wc *websocket.Conn, rack, wack uint32) waiter

type Resolver

type Resolver interface {
	Resolve(host, port string) (string, string, error)
}

Resolver can resolve a host+port pair into a potentially different host+port pair.

type SRVResolver

type SRVResolver struct{}

SRVResolver is a Resolver that attempts to resolve the port via an SRV record if the port is empty.

func (*SRVResolver) Resolve

func (r *SRVResolver) Resolve(host, port string) (string, string, error)

type SendWindow

type SendWindow struct {
	Filled  uint64 // Absolute counter of bytes Filled.
	Emptied uint64 // Absolute counter of bytes consumed from this window.
	// contains filtered or unexported fields
}

func NewSendWindow

func NewSendWindow(pool *BufferPool) *SendWindow

func (*SendWindow) Acknowledge

func (w *SendWindow) Acknowledge(size int)

func (*SendWindow) AcknowledgeUntil

func (w *SendWindow) AcknowledgeUntil(trunc uint32) (uint64, error)

func (*SendWindow) Drop

func (sw *SendWindow) Drop()

func (*SendWindow) Empty

func (w *SendWindow) Empty(size int)

func (*SendWindow) Fill

func (w *SendWindow) Fill(size int) uint64

func (*SendWindow) Reset

func (w *SendWindow) Reset(trunc uint32) error

func (*SendWindow) ToEmpty

func (w *SendWindow) ToEmpty() []byte

func (*SendWindow) ToFill

func (w *SendWindow) ToFill() []byte

type SessionCounters

type SessionCounters struct {
	Resumed utils.Counter
	Invalid utils.Counter
	Created utils.Counter

	Orphaned utils.Counter
	Deleted  utils.Counter
}

type TerminatingError

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

func (*TerminatingError) Unwrap

func (te *TerminatingError) Unwrap() error

type Timeouts

type Timeouts struct {
	Now utils.TimeSource

	ResolutionTimeout time.Duration

	BrowserWriteTimeout time.Duration
	BrowserAckTimeout   time.Duration

	ConnWriteTimeout time.Duration
}

func DefaultTimeouts

func DefaultTimeouts() *Timeouts

type Waiter

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

Waiter is similar to sync.CondWait as it can be used exactly the same way, except:

  • it only supports a single waiter. Having more than one waiter will lead to undefined behavior.
  • it allows to configure wait timeouts.
  • it allows to propagate error failures.
Example
lock := &sync.Mutex{}
waiter := NewWaiter(lock)
wg := &sync.WaitGroup{}
wg.Add(2)

counter := 0
// Produces events: increments counter.
go func() {
	for i := 0; i < 10; i++ {
		time.Sleep(10 * time.Millisecond)
		lock.Lock()
		counter += 1
		waiter.Signal()
		lock.Unlock()
	}
	wg.Done()
}()

go func() {
	lock.Lock()
	defer lock.Unlock()
	for counter < 10 {
		waiter.Wait()
	}
	fmt.Println("counter is now >= 10")
	wg.Done()
}()
wg.Wait()
Output:

counter is now >= 10

func NewWaiter

func NewWaiter(l sync.Locker) *Waiter

NewWaiter creates a new Waiter.

func (*Waiter) Fail

func (w *Waiter) Fail(err error)

Fail will cause anyone waiting on Wait*() to receive the specified error. Do NOT hold the lock when invoking Fail().

func (*Waiter) Signal

func (w *Waiter) Signal()

Signal will notify anyone waiting on Wait*() to check the condition again. It can be invoked with or without the lock held.

func (*Waiter) Wait

func (w *Waiter) Wait() error

Wait for a signal to check that the desired condition has changed.

The specified lock MUST be held before calling Wait. Just like with CondWait(), wait can return spurious events, where error is nil, but none of the desired conditions has changed.

func (*Waiter) WaitFor

func (w *Waiter) WaitFor(d time.Duration) error

WaitFor is just like Wait(), but with a timeout.

The specified lock MUST be held before calling Wait. If the timeout expires, ErrorExpired is returned.

Jump to

Keyboard shortcuts

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