proto

package
v0.3.1 Latest Latest
Warning

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

Go to latest
Published: Sep 22, 2015 License: MIT Imports: 9 Imported by: 2

Documentation

Index

Examples

Constants

View Source
const (
	TLSMajor        = tls.VersionTLS12 >> 8
	TLSHighestMinor = tls.VersionTLS12 & 0xFF // Bump when new releases are made available
	TLSHandshake    = 0x16
	TLSClientHello  = 0x01
)

TLS field constants

Variables

View Source
var (
	// HTTPMethods are the HTTP method names that can be used for detection,
	// sorted by length.
	HTTPMethods = [][]byte{
		[]byte("GET"),
		[]byte("PUT"),
		[]byte("HEAD"),
		[]byte("POST"),
		[]byte("PATCH"),
		[]byte("TRACE"),
		[]byte("DELETE"),
		[]byte("CONNECT"),
		[]byte("OPTIONS"),
	}
)

Functions

This section is empty.

Types

type Chain

type Chain struct {
	Handler     func(net.Conn) (net.Conn, error)
	Checkers    []func([]byte, []interface{}) (bool, int)
	Description string
}

Chain allows for easy chaining of multiple checks, which all must pass before the handler is called. For performance, have the easiest checks first in the line of checkers.

func NewChain

func NewChain(handler func(net.Conn) (net.Conn, error), checkers ...func([]byte, []interface{}) (bool, int)) *Chain

NewChain returns a Chain initialized with the provided handler and list of checkers.

Example
package main

import (
	"net"

	"github.com/joushou/serve2"
	"github.com/joushou/serve2/proto"
	"github.com/joushou/serve2/utils"
)

func main() {
	server := serve2.New()

	handler := func(c net.Conn) (net.Conn, error) {
		return nil, utils.DialAndProxy(c, "tcp", "localhost:80")
	}

	sm := proto.NewSimpleMatcher(proto.HTTPMethods, handler)
	tm := &proto.TLSMatcher{}
	cm := proto.NewChain(sm.Handle, tm.Check, sm.Check)
	cm.Description = "HTTPS"

	server.AddHandlers(cm)
	l, err := net.Listen("tcp", ":8080")
	if err != nil {
		panic(err)
	}

	server.Serve(l)
}
Output:

func (*Chain) Check

func (c *Chain) Check(header []byte, hints []interface{}) (bool, int)

Check alls all the provided checkers in order, returning the output of the first failing check. If all checkers pass, Check returns (true, 0).

func (*Chain) Handle

func (c *Chain) Handle(conn net.Conn) (net.Conn, error)

Handle calls the provided Handler.

func (*Chain) String

func (c *Chain) String() string

type ListenProxy

type ListenProxy struct {
	Checker     func([]byte, []interface{}) (bool, int)
	Description string
	// contains filtered or unexported fields
}

ListenProxy provides a net.Listener whose Accept will only return matched protocols.

func NewHTTP

func NewHTTP(handler http.Handler) *ListenProxy

NewHTTP returns a ListenProxy with a http as the listening service. This is a convenience wrapper kept in place for compatibility with older checkouts. Might be removed in the future.

Example
package main

import (
	"fmt"
	"net"
	"net/http"

	"github.com/joushou/serve2"
	"github.com/joushou/serve2/proto"
)

type HTTPHandler struct{}

func (h *HTTPHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	if r.Method == "OPTIONS" || r.Method == "HEAD" {
		return
	}

	fmt.Fprintf(w, "<!DOCTYPE html><html><head></head><body>Welcome to %s</body></html>", r.URL.Path)
}

func main() {
	server := serve2.New()

	// Insert your http.Handler here
	http := proto.NewHTTP(&HTTPHandler{})

	server.AddHandlers(http)
	l, err := net.Listen("tcp", ":8080")
	if err != nil {
		panic(err)
	}

	server.Serve(l)
}
Output:

func NewListenProxy

func NewListenProxy(checker func([]byte, []interface{}) (bool, int), buffer int) *ListenProxy

NewListenProxy returns a fully initialized ListenProxy.

Example
package main

import (
	"bytes"
	"fmt"
	"net"
	"net/http"

	"github.com/joushou/serve2"
	"github.com/joushou/serve2/proto"
)

type HTTPHandler struct{}

func (h *HTTPHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	if r.Method == "OPTIONS" || r.Method == "HEAD" {
		return
	}

	fmt.Fprintf(w, "<!DOCTYPE html><html><head></head><body>Welcome to %s</body></html>", r.URL.Path)
}

func main() {
	server := serve2.New()

	checker := func(header []byte, _ []interface{}) (match bool, required int) {
		if len(header) < 3 {
			return false, 3
		}

		if bytes.Compare(header[:3], []byte("GET")) == 0 {
			return true, 0
		}
		return false, 0
	}

	lp := proto.NewListenProxy(checker, 10)
	lp.Description = "HTTP"

	go http.Serve(lp.Listener(), &HTTPHandler{})

	server.AddHandlers(lp)
	l, err := net.Listen("tcp", ":8080")
	if err != nil {
		panic(err)
	}

	server.Serve(l)
}
Output:

func (*ListenProxy) Check

func (lp *ListenProxy) Check(header []byte, hints []interface{}) (bool, int)

Check just calls the ListenChecker.

func (*ListenProxy) Handle

func (lp *ListenProxy) Handle(c net.Conn) (net.Conn, error)

Handle pushes the connection to the ListenProxy server.

func (*ListenProxy) Listener

func (lp *ListenProxy) Listener() net.Listener

Listener returns the proxy net.Listener.

func (*ListenProxy) String

func (lp *ListenProxy) String() string

type SimpleMatcher

type SimpleMatcher struct {
	Matches     [][]byte
	Handler     func(net.Conn) (net.Conn, error)
	Description string
}

SimpleMatcher matches the provided bytes against a list of potential matches, quickly dismissing impossible matches.

func NewDiscard

func NewDiscard() *SimpleMatcher

NewDiscard returns a new Discard protocol handler. Discard is a simple protocol for testing purposes. It requires that the connection is initiated by writing "DISCARD", as protocol recognition would not work otherwise, but after that, it simply reads and discards everything it receives, hence the name.

Example
package main

import (
	"net"

	"github.com/joushou/serve2"
	"github.com/joushou/serve2/proto"
)

func main() {
	server := serve2.New()

	// If we send "DISCARD" first, then everything is discarded afterwards
	server.AddHandlers(proto.NewDiscard())
	l, err := net.Listen("tcp", ":8080")
	if err != nil {
		panic(err)
	}

	server.Serve(l)
}
Output:

func NewEcho

func NewEcho() *SimpleMatcher

NewEcho returns a new ECHO protocol handler. Echo is a simple protocol for testing purposes. It requires that the connection is initiated by writing "Echo", as protocol recognition would not work otherwise, but after that, it simply reads and echoes everything it receives, hence the name.

Example
package main

import (
	"net"

	"github.com/joushou/serve2"
	"github.com/joushou/serve2/proto"
)

func main() {
	server := serve2.New()

	// If we send "ECHO" first, then everything is echoed afterwards
	server.AddHandlers(proto.NewEcho())
	l, err := net.Listen("tcp", ":8080")
	if err != nil {
		panic(err)
	}

	server.Serve(l)
}
Output:

func NewMultiProxy

func NewMultiProxy(matches [][]byte, proto, dest string) *SimpleMatcher

NewMultiProxy returns a SimpleMatcher set up to call DialAndProxy.

Example
package main

import (
	"net"

	"github.com/joushou/serve2"
	"github.com/joushou/serve2/proto"
)

func main() {
	server := serve2.New()

	httpMethods := [][]byte{
		[]byte("GET"),
		[]byte("POST"),
	}

	mp := proto.NewMultiProxy(httpMethods, "tcp", "localhost:80")

	server.AddHandlers(mp)
	l, err := net.Listen("tcp", ":8080")
	if err != nil {
		panic(err)
	}

	server.Serve(l)
}
Output:

func NewProxy

func NewProxy(match []byte, proto, dest string) *SimpleMatcher

NewProxy returns a SimpleMatcher set up to call DialAndProxy.

Example
package main

import (
	"net"

	"github.com/joushou/serve2"
	"github.com/joushou/serve2/proto"
)

func main() {
	server := serve2.New()

	// SSH just so happens to send "SSH" and version number as the first thing
	proxy := proto.NewProxy([]byte("SSH"), "tcp", "localhost:22")

	server.AddHandlers(proxy)
	l, err := net.Listen("tcp", ":8080")
	if err != nil {
		panic(err)
	}

	server.Serve(l)

}
Output:

func NewSimpleMatcher

func NewSimpleMatcher(matches [][]byte, handler func(net.Conn) (net.Conn, error)) *SimpleMatcher

NewSimpleMatcher returns a SimpleMatcher with the provided matches and handler, matches already sorted, and Description initialized to "SimpleMatcher". Do note that this modified the provided matches slice to sort it by length.

Example
package main

import (
	"net"

	"github.com/joushou/serve2"
	"github.com/joushou/serve2/proto"
	"github.com/joushou/serve2/utils"
)

func main() {
	server := serve2.New()

	handler := func(c net.Conn) (net.Conn, error) {
		return nil, utils.DialAndProxy(c, "tcp", "localhost:80")
	}

	sm := proto.NewSimpleMatcher(proto.HTTPMethods, handler)
	sm.Description = "HTTP"

	server.AddHandlers(sm)
	l, err := net.Listen("tcp", ":8080")
	if err != nil {
		panic(err)
	}

	server.Serve(l)
}
Output:

func (*SimpleMatcher) Check

func (s *SimpleMatcher) Check(header []byte, _ []interface{}) (bool, int)

Check looks through the provided matches.

func (*SimpleMatcher) Handle

func (s *SimpleMatcher) Handle(c net.Conn) (net.Conn, error)

Handle calls the provided handler.

func (*SimpleMatcher) Sort

func (s *SimpleMatcher) Sort()

Sort sorts the provided matches by length.

func (*SimpleMatcher) String

func (s *SimpleMatcher) String() string

String returns the provided description.

type TLS

type TLS struct {
	Description string
	// contains filtered or unexported fields
}

TLS handles abstraction of TLS connections, in order to feed them back into the protocol detectors.

func NewTLS

func NewTLS(protos []string, cert, key string) (*TLS, error)

NewTLS returns an initialized TLS.

Example
package main

import (
	"net"

	"github.com/joushou/serve2"
	"github.com/joushou/serve2/proto"
)

func main() {
	server := serve2.New()

	// We just set NextProto to "echo". Cert and key required!
	tls, err := proto.NewTLS([]string{"echo"}, "cert.pem", "key.pem")
	if err != nil {
		panic(err)
	}

	// We add the echo handler too
	server.AddHandlers(tls, proto.NewEcho())
	l, err := net.Listen("tcp", ":8080")
	if err != nil {
		panic(err)
	}

	server.Serve(l)
}
Output:

func (*TLS) Check

func (t *TLS) Check(header []byte, _ []interface{}) (bool, int)

Check checks if the protocol is TLS

func (*TLS) Handle

func (t *TLS) Handle(c net.Conn) (net.Conn, error)

Handle returns a connection with TLS abstracted away. Adds the tls.Conn for the connection as a hint.

func (*TLS) Setup

func (t *TLS) Setup(protos []string, cert, key string) error

Setup loads the certificates and sets up supported protocols.

func (*TLS) String

func (t *TLS) String() string

type TLSMatcher

type TLSMatcher struct {
	ServerNames                []string
	NegotiatedProtocols        []string
	NegotiatedProtocolIsMutual bool
	PeerCertificates           []*x509.Certificate
	CipherSuites               []uint16
	Versions                   []uint16
	Checks                     TLSMatcherChecks
	Handler                    func(net.Conn) (net.Conn, error)
	Description                string
}

TLSMatcher is a TLS connection inspector, that will verify the tls.ConnectionState fields described by Checks. If no verifications are enabled, TLSMatcher will simply match the presence of a TLS transport.

func NewTLSMatcher

func NewTLSMatcher(handler func(net.Conn) (net.Conn, error)) *TLSMatcher

NewTLSMatcher returns a *TLSMatcher configured with the provided handler.

Example
package main

import (
	"crypto/tls"
	"net"

	"github.com/joushou/serve2"
	"github.com/joushou/serve2/proto"
	"github.com/joushou/serve2/utils"
)

func main() {
	server := serve2.New()

	handler := func(c net.Conn) (net.Conn, error) {
		return nil, utils.DialAndProxyTLS(c, "tcp", "http2.golang.org:443", &tls.Config{
			NextProtos: []string{"h2", "h2-14"},
			ServerName: "http2.golang.org",
		})
	}

	tls, err := proto.NewTLS([]string{"h2", "h2-14"}, "cert.pem", "key.pem")
	if err != nil {
		panic(err)
	}
	server.AddHandlers(tls)

	tm := proto.NewTLSMatcher(handler)
	tm.NegotiatedProtocols = []string{"h2", "h2-14"}
	tm.Checks = proto.TLSCheckNegotiatedProtocol
	tm.Description = "HTTP2"

	server.AddHandlers(tm)
	l, err := net.Listen("tcp", ":8080")
	if err != nil {
		panic(err)
	}

	server.Serve(l)
}
Output:

func (*TLSMatcher) Check

func (tc *TLSMatcher) Check(_ []byte, hints []interface{}) (bool, int)

Check inspects the last transport hint, checking if it is a TLS transport.

func (*TLSMatcher) Handle

func (tc *TLSMatcher) Handle(c net.Conn) (net.Conn, error)

Handle simply calls the provided handler.

func (*TLSMatcher) String

func (tc *TLSMatcher) String() string

type TLSMatcherChecks

type TLSMatcherChecks uint

TLSMatcherChecks is a bitmask describing what to verify.

const (
	TLSCheckServerName TLSMatcherChecks = 1 << iota
	TLSCheckNegotiatedProtocol
	TLSCheckNegotiatedProtocolIsMutual
	TLSCheckClientCertificate
	TLSCheckCipherSuite
	TLSCheckVersion
)

TLSMatcher verification flags.

func (TLSMatcherChecks) IsSet

func (tcv TLSMatcherChecks) IsSet(other TLSMatcherChecks) bool

IsSet checks the bitmask for the given bit.

Jump to

Keyboard shortcuts

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