vhost

package module
v1.0.0 Latest Latest
Warning

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

Go to latest
Published: Aug 7, 2022 License: Apache-2.0 Imports: 11 Imported by: 341

README

go-vhost

go-vhost is a simple library that lets you implement virtual hosting functionality for different protocols (HTTP and TLS so far). go-vhost has a high-level and a low-level interface. The high-level interface lets you wrap existing net.Listeners with "muxer" objects. You can then Listen() on a muxer for a particular virtual host name of interest which will return to you a net.Listener for just connections with the virtual hostname of interest.

The lower-level go-vhost interface are just functions which extract the name/routing information for the given protocol and return an object implementing net.Conn which works as if no bytes had been consumed.

API Documentation
Usage
l, _ := net.Listen("tcp", *listen)

// start multiplexing on it
mux, _ := vhost.NewHTTPMuxer(l, muxTimeout)

// listen for connections to different domains
for _, v := range virtualHosts {
	vhost := v

	// vhost.Name is a virtual hostname like "foo.example.com"
	muxListener, _ := mux.Listen(vhost.Name())

	go func(vh virtualHost, ml net.Listener) {
		for {
			conn, _ := ml.Accept()
			go vh.Handle(conn)
		}
	}(vhost, muxListener)
}

for {
	conn, err := mux.NextError()

	switch err.(type) {
	case vhost.BadRequest:
		log.Printf("got a bad request!")
		conn.Write([]byte("bad request"))
	case vhost.NotFound:
		log.Printf("got a connection for an unknown vhost")
		conn.Write([]byte("vhost not found"))
	case vhost.Closed:
		log.Printf("closed conn: %s", err)
	default:
		if conn != nil {
			conn.Write([]byte("server error"))
		}
	}

	if conn != nil {
		conn.Close()
	}
}
Low-level API usage
// accept a new connection
conn, _ := listener.Accept()

// parse out the HTTP request and the Host header
if vhostConn, err = vhost.HTTP(conn); err != nil {
	panic("Not a valid http connection!")
}

fmt.Printf("Target Host: ", vhostConn.Host())
// Target Host: example.com

// vhostConn contains the entire request as if no bytes had been consumed
bytes, _ := ioutil.ReadAll(vhostConn)
fmt.Printf("%s", bytes)
// GET / HTTP/1.1
// Host: example.com
// User-Agent: ...
// ...
Advanced introspection

The entire HTTP request headers are available for inspection in case you want to mux on something besides the Host header:

// parse out the HTTP request and the Host header
if vhostConn, err = vhost.HTTP(conn); err != nil {
	panic("Not a valid http connection!")
}

httpVersion := vhost.Request.MinorVersion
customRouting := vhost.Request.Header["X-Custom-Routing-Header"]

Likewise for TLS, you can look at detailed information about the ClientHello message:

if vhostConn, err = vhost.TLS(conn); err != nil {
	panic("Not a valid TLS connection!")
}

cipherSuites := vhost.ClientHelloMsg.CipherSuites
sessionId := vhost.ClientHelloMsg.SessionId
Memory reduction with Free

After you're done muxing, you probably don't need to inspect the header data anymore, so you can make it available for garbage collection:

// look up the upstream host
upstreamHost := hostMapping[vhostConn.Host()]

// free up the muxing data
vhostConn.Free()

// vhostConn.Host() == ""
// vhostConn.Request == nil (HTTP)
// vhostConn.ClientHelloMsg == nil (TLS)

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type BadRequest

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

BadRequest is returned when extraction of the vhost name fails

type ClientHelloMsg

type ClientHelloMsg struct {
	Raw                []byte
	Vers               uint16
	Random             []byte
	SessionId          []byte
	CipherSuites       []uint16
	CompressionMethods []uint8
	NextProtoNeg       bool
	ServerName         string
	OcspStapling       bool
	SupportedCurves    []uint16
	SupportedPoints    []uint8
	TicketSupported    bool
	SessionTicket      []uint8
}

type Closed

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

Closed is returned when the underlying connection is closed

type Conn

type Conn interface {
	net.Conn
	Host() string
	Free()
}

type HTTPConn

type HTTPConn struct {
	Request *http.Request
	// contains filtered or unexported fields
}

func HTTP

func HTTP(conn net.Conn) (httpConn *HTTPConn, err error)

HTTP parses the head of the first HTTP request on conn and returns a new, unread connection with metadata for virtual host muxing

func (*HTTPConn) Free

func (c *HTTPConn) Free()

Free sets Request to nil so that it can be garbage collected

func (*HTTPConn) Host

func (c *HTTPConn) Host() string

func (HTTPConn) Read

func (c HTTPConn) Read(p []byte) (n int, err error)

type HTTPMuxer

type HTTPMuxer struct {
	*VhostMuxer
}

func NewHTTPMuxer

func NewHTTPMuxer(listener net.Listener, muxTimeout time.Duration) (*HTTPMuxer, error)

NewHTTPMuxer begins muxing HTTP connections on the given listener by inspecting the HTTP Host header in new connections.

func (*HTTPMuxer) HandleError

func (m *HTTPMuxer) HandleError(conn net.Conn, err error)

func (*HTTPMuxer) HandleErrors

func (m *HTTPMuxer) HandleErrors()

HandleErrors handles muxing errors by calling .NextError(). You must invoke this function if you do not want to handle the errors yourself.

type Listener

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

Listener is returned by a call to Listen() on a muxer. A Listener only receives connections that were made to the name passed into the muxer's Listen call.

Listener implements the net.Listener interface, so you can Accept() new connections and Close() it when finished. When you Close() a Listener, the parent muxer will stop listening for connections to the Listener's name.

func (*Listener) Accept

func (l *Listener) Accept() (net.Conn, error)

Accept returns the next mux'd connection for this listener and blocks until one is available.

func (*Listener) Addr

func (l *Listener) Addr() net.Addr

Addr returns the address of the bound listener used by the parent muxer.

func (*Listener) Close

func (l *Listener) Close() error

Close stops the parent muxer from listening for connections to the mux'd virtual host name.

func (*Listener) Name

func (l *Listener) Name() string

Name returns the name of the virtual host this listener receives connections on.

type NotFound

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

NotFound is returned when a vhost is not found

type TLSConn

type TLSConn struct {
	ClientHelloMsg *ClientHelloMsg
	// contains filtered or unexported fields
}

A Conn represents a secured connection. It implements the net.Conn interface.

func TLS

func TLS(conn net.Conn) (tlsConn *TLSConn, err error)

TLS parses the ClientHello message on conn and returns a new, unread connection with metadata for virtual host muxing

func (*TLSConn) Free

func (c *TLSConn) Free()

func (*TLSConn) Host

func (c *TLSConn) Host() string

func (TLSConn) Read

func (c TLSConn) Read(p []byte) (n int, err error)

type TLSMuxer

type TLSMuxer struct {
	*VhostMuxer
}

func NewTLSMuxer

func NewTLSMuxer(listener net.Listener, muxTimeout time.Duration) (*TLSMuxer, error)

NewTLSMuxer begins muxing TLS connections by inspecting the SNI extension.

func (*TLSMuxer) HandleErrors

func (m *TLSMuxer) HandleErrors()

HandleErrors is the default error handler for TLS muxers. At the moment, it simply closes connections which are invalid or destined for virtual host names that it is not listening for. You must invoke this function if you do not want to handle the errors yourself.

func (*TLSMuxer) Listen

func (m *TLSMuxer) Listen(name string) (net.Listener, error)

type VhostMuxer

type VhostMuxer struct {
	sync.RWMutex // protects the registry
	// contains filtered or unexported fields
}

func NewVhostMuxer

func NewVhostMuxer(listener net.Listener, vhostFn muxFn, muxTimeout time.Duration) (*VhostMuxer, error)

func (*VhostMuxer) Close

func (m *VhostMuxer) Close()

Close closes the underlying listener

func (*VhostMuxer) Listen

func (m *VhostMuxer) Listen(name string) (net.Listener, error)

Listen begins multiplexing the underlying connection to send new connections for the given name over the returned listener.

func (*VhostMuxer) NextError

func (m *VhostMuxer) NextError() (net.Conn, error)

NextError returns the next error encountered while mux'ing a connection. The net.Conn may be nil if the wrapped listener returned an error from Accept()

Jump to

Keyboard shortcuts

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