<|start_filename|>modules/l4tls/clienthello.go<|end_filename|>
// Copyright 2020 <NAME>
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package l4tls

import (
	"crypto/tls"
)

// ClientHelloInfo holds information about a TLS ClientHello.
// Our own parser collects a little more information than
// the standard library's struct holds.
type ClientHelloInfo struct {
	tls.ClientHelloInfo

	Version                      uint16
	Random                       []byte
	SessionID                    []byte
	SecureRenegotiationSupported bool
	SecureRenegotiation          []byte
	CompressionMethods           []byte

	Extensions []uint16

	OCSPStapling         bool
	TicketSupported      bool
	SessionTicket        []uint8
	SupportedSchemesCert []tls.SignatureScheme
	SCTs                 bool
	Cookie               []byte
	KeyShares            []KeyShare
	EarlyData            bool
	PSKModes             []uint8
	PSKIdentities        []PSKIdentity
	PSKBinders           [][]byte
}

// FillTLSClientConfig fills cfg (a client-side TLS config) with information
// from chi. It does not overwrite any fields in cfg that are already non-zero.
func (chi ClientHelloInfo) FillTLSClientConfig(cfg *tls.Config) {
	if cfg.NextProtos == nil {
		cfg.NextProtos = chi.ClientHelloInfo.SupportedProtos
	}
	if cfg.ServerName == "" {
		cfg.ServerName = chi.ClientHelloInfo.ServerName
	}
	if cfg.CipherSuites == nil {
		cfg.CipherSuites = chi.ClientHelloInfo.CipherSuites
	}
	if cfg.CurvePreferences == nil {
		cfg.CurvePreferences = chi.ClientHelloInfo.SupportedCurves
	}
	var minVer, maxVer uint16
	for _, ver := range chi.ClientHelloInfo.SupportedVersions {
		if minVer == 0 || ver < minVer {
			minVer = ver
		}
		if maxVer == 0 || ver > maxVer {
			maxVer = ver
		}
	}
	if cfg.MinVersion == 0 {
		cfg.MinVersion = minVer
	}
	if cfg.MaxVersion == 0 {
		cfg.MaxVersion = maxVer
	}
}


<|start_filename|>layer4/matchers.go<|end_filename|>
// Copyright 2020 <NAME>
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package layer4

import (
	"fmt"
	"net"
	"strings"

	"github.com/caddyserver/caddy/v2"
)

func init() {
	caddy.RegisterModule(MatchIP{})
}

// ConnMatcher is a type that can match a connection.
type ConnMatcher interface {
	// Match returns true if the given connection matches.
	// It should read from the connection as little as possible:
	// only as much as necessary to determine a match.
	Match(*Connection) (bool, error)
}

// MatcherSet is a set of matchers which
// must all match in order for the request
// to be matched successfully.
type MatcherSet []ConnMatcher

// Match returns true if the connection matches all matchers in mset
// or if there are no matchers. Any error terminates matching.
func (mset MatcherSet) Match(cx *Connection) (matched bool, err error) {
	for _, m := range mset {
		cx.record()
		matched, err = m.Match(cx)
		cx.rewind()
		if !matched || err != nil {
			return
		}
	}
	matched = true
	return
}

// RawMatcherSets is a group of matcher sets in their
// raw JSON form.
type RawMatcherSets []caddy.ModuleMap

// MatcherSets is a group of matcher sets capable of checking
// whether a connection matches any of the sets.
type MatcherSets []MatcherSet

// AnyMatch returns true if the connection matches any of the matcher sets
// in mss or if there are no matchers, in which case the request always
// matches. Any error terminates matching.
func (mss MatcherSets) AnyMatch(cx *Connection) (matched bool, err error) {
	for _, m := range mss {
		matched, err = m.Match(cx)
		if matched || err != nil {
			return
		}
	}
	matched = len(mss) == 0
	return
}

// FromInterface fills ms from an interface{} value obtained from LoadModule.
func (mss *MatcherSets) FromInterface(matcherSets interface{}) error {
	for _, matcherSetIfaces := range matcherSets.([]map[string]interface{}) {
		var matcherSet MatcherSet
		for _, matcher := range matcherSetIfaces {
			connMatcher, ok := matcher.(ConnMatcher)
			if !ok {
				return fmt.Errorf("decoded module is not a ConnMatcher: %#v", matcher)
			}
			matcherSet = append(matcherSet, connMatcher)
		}
		*mss = append(*mss, matcherSet)
	}
	return nil
}

// MatchIP matches requests by remote IP (or CIDR range).
type MatchIP struct {
	Ranges []string `json:"ranges,omitempty"`

	cidrs []*net.IPNet
}

// CaddyModule returns the Caddy module information.
func (MatchIP) CaddyModule() caddy.ModuleInfo {
	return caddy.ModuleInfo{
		ID:  "layer4.matchers.ip",
		New: func() caddy.Module { return new(MatchIP) },
	}
}

// Provision parses m's IP ranges, either from IP or CIDR expressions.
func (m *MatchIP) Provision(ctx caddy.Context) error {
	for _, str := range m.Ranges {
		if strings.Contains(str, "/") {
			_, ipNet, err := net.ParseCIDR(str)
			if err != nil {
				return fmt.Errorf("parsing CIDR expression: %v", err)
			}
			m.cidrs = append(m.cidrs, ipNet)
		} else {
			ip := net.ParseIP(str)
			if ip == nil {
				return fmt.Errorf("invalid IP address: %s", str)
			}
			mask := len(ip) * 8
			m.cidrs = append(m.cidrs, &net.IPNet{
				IP:   ip,
				Mask: net.CIDRMask(mask, mask),
			})
		}
	}
	return nil
}

// Match returns true if the connection is from one of the designated IP ranges.
func (m MatchIP) Match(cx *Connection) (bool, error) {
	clientIP, err := m.getClientIP(cx)
	if err != nil {
		return false, fmt.Errorf("getting client IP: %v", err)
	}
	for _, ipRange := range m.cidrs {
		if ipRange.Contains(clientIP) {
			return true, nil
		}
	}
	return false, nil
}

func (m MatchIP) getClientIP(cx *Connection) (net.IP, error) {
	remote := cx.Conn.RemoteAddr().String()

	ipStr, _, err := net.SplitHostPort(remote)
	if err != nil {
		ipStr = remote // OK; probably didn't have a port
	}

	ip := net.ParseIP(ipStr)
	if ip == nil {
		return nil, fmt.Errorf("invalid client IP address: %s", ipStr)
	}

	return ip, nil
}

// Interface guards
var (
	_ ConnMatcher       = (*MatchIP)(nil)
	_ caddy.Provisioner = (*MatchIP)(nil)
)


<|start_filename|>modules/l4proxy/upstream.go<|end_filename|>
// Copyright 2020 <NAME>
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package l4proxy

import (
	"crypto/tls"
	"fmt"
	"sync/atomic"

	"github.com/caddyserver/caddy/v2"
	"github.com/caddyserver/caddy/v2/modules/caddyhttp/reverseproxy"
)

// UpstreamPool is a collection of upstreams.
type UpstreamPool []*Upstream

// Upstream represents a proxy upstream.
type Upstream struct {
	// The network addresses to dial. Supports placeholders, but not port
	// ranges currently (each address must be exactly 1 socket).
	Dial []string `json:"dial,omitempty"`

	// Set this field to enable TLS to the upstream.
	TLS *reverseproxy.TLSConfig `json:"tls,omitempty"`

	// How many connections this upstream is allowed to
	// have before being marked as unhealthy (if > 0).
	MaxConnections int `json:"max_connections,omitempty"`

	peers             []*peer
	tlsConfig         *tls.Config
	healthCheckPolicy *PassiveHealthChecks
}

func (u *Upstream) provision(ctx caddy.Context, h *Handler) error {
	for _, dialAddr := range u.Dial {
		// parse and validate address
		addr, err := caddy.ParseNetworkAddress(dialAddr)
		if err != nil {
			return err
		}
		if addr.PortRangeSize() != 1 {
			return fmt.Errorf("%s: port ranges not currently supported", dialAddr)
		}

		// create or load peer info
		p := &peer{address: addr}
		existingPeer, loaded := peers.LoadOrStore(dialAddr, p)
		if loaded {
			p = existingPeer.(*peer)
		}
		u.peers = append(u.peers, p)
	}

	// set up TLS client
	if u.TLS != nil {
		var err error
		u.tlsConfig, err = u.TLS.MakeTLSClientConfig(ctx)
		if err != nil {
			return fmt.Errorf("making TLS client config: %v", err)
		}
	}

	// if the passive health checker has a non-zero UnhealthyConnectionCount
	// but the upstream has no MaxConnections set (they are the same thing,
	// but the passive health checker is a default value for for upstreams
	// without MaxConnections), copy the value into this upstream, since the
	// value in the upstream (MaxConnections) is what is used during
	// availability checks
	if h.HealthChecks != nil && h.HealthChecks.Passive != nil {
		h.HealthChecks.Passive.logger = h.logger.Named("health_checker.passive")
		if h.HealthChecks.Passive.UnhealthyConnectionCount > 0 &&
			u.MaxConnections == 0 {
			u.MaxConnections = h.HealthChecks.Passive.UnhealthyConnectionCount
		}
	}

	// upstreams need independent access to the passive
	// health check policy because passive health checks
	// run without access to h.
	if h.HealthChecks != nil {
		u.healthCheckPolicy = h.HealthChecks.Passive
	}

	return nil
}

// available returns true if the remote host
// is available to receive connections. This is
// the method that should be used by selection
// policies, etc. to determine if a backend
// is usable at the moment.
func (u *Upstream) available() bool {
	return u.healthy() && !u.full()
}

// healthy returns true if the remote host
// is currently known to be healthy or "up".
// It consults the circuit breaker, if any.
func (u *Upstream) healthy() bool {
	for _, p := range u.peers {
		if !p.healthy() {
			return false
		}
	}
	if u.healthCheckPolicy != nil && u.healthCheckPolicy.MaxFails > 0 {
		for _, p := range u.peers {
			if atomic.LoadInt32(&p.fails) >= int32(u.healthCheckPolicy.MaxFails) {
				return false
			}
		}
	}
	return true
}

// full returns true if any of the peers cannot
// receive more connections at this time.
func (u *Upstream) full() bool {
	if u.MaxConnections == 0 {
		return false
	}
	for _, p := range u.peers {
		if p.getNumConns() >= u.MaxConnections {
			return true
		}
	}
	return false
}

// totalConns returns the total number of active connections
// to this upstream (across all peers).
func (u *Upstream) totalConns() int {
	var totalConns int
	for _, p := range u.peers {
		totalConns += p.getNumConns()
	}
	return totalConns
}

// peer holds the state for a singular proxy backend;
// must not be copied, because peers are singular
// (even if there is more than 1 instance of a config,
// that does not duplicate the actual backend).
type peer struct {
	numConns  int32
	unhealthy int32
	fails     int32
	address   caddy.NetworkAddress
}

// getNumConns returns the number of active connections with the peer.
func (p *peer) getNumConns() int {
	return int(atomic.LoadInt32(&p.numConns))
}

// healthy returns true if the peer is not unhealthy.
func (p *peer) healthy() bool {
	return atomic.LoadInt32(&p.unhealthy) == 0
}

// countConn mutates the active connection count by
// delta. It returns an error if the adjustment fails.
func (p *peer) countConn(delta int) error {
	result := atomic.AddInt32(&p.numConns, int32(delta))
	if result < 0 {
		return fmt.Errorf("count below 0: %d", result)
	}
	return nil
}

// countFail mutates the recent failures count by
// delta. It returns an error if the adjustment fails.
func (p *peer) countFail(delta int) error {
	result := atomic.AddInt32(&p.fails, int32(delta))
	if result < 0 {
		return fmt.Errorf("count below 0: %d", result)
	}
	return nil
}

// setHealthy sets the upstream has healthy or unhealthy
// and returns true if the new value is different.
func (p *peer) setHealthy(healthy bool) (bool, error) {
	var unhealthy, compare int32 = 1, 0
	if healthy {
		unhealthy, compare = 0, 1
	}
	swapped := atomic.CompareAndSwapInt32(&p.unhealthy, compare, unhealthy)
	return swapped, nil
}


<|start_filename|>modules/l4tee/tee.go<|end_filename|>
// Copyright 2020 <NAME>
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package l4tee

import (
	"encoding/json"
	"io"
	"net"

	"github.com/caddyserver/caddy/v2"
	"github.com/mholt/caddy-l4/layer4"
	"go.uber.org/zap"
)

func init() {
	caddy.RegisterModule(Handler{})
}

// Handler is a layer4 handler that replicates a connection so
// that a branch of handlers can concurrently handle it. Reads
// happen in lock-step with all concurrent branches so as to
// avoid buffering: if one of the branches (including the main
// handler chain) stops reading from the connection, it will
// block all branches.
type Handler struct {
	// Handlers is the list of handlers that constitute this
	// concurrent branch. Any handlers that do connection
	// matching (which involves recording and rewinding the
	// stream) are unsafe to tee, so do all connection
	// matching before teeing.
	HandlersRaw []json.RawMessage `json:"branch,omitempty" caddy:"namespace=layer4.handlers inline_key=handler"`

	compiledChain layer4.Handler
	logger        *zap.Logger
}

// CaddyModule returns the Caddy module information.
func (Handler) CaddyModule() caddy.ModuleInfo {
	return caddy.ModuleInfo{
		ID:  "layer4.handlers.tee",
		New: func() caddy.Module { return new(Handler) },
	}
}

// Provision sets up the handler.
func (t *Handler) Provision(ctx caddy.Context) error {
	t.logger = ctx.Logger(t)

	// set up the handler chain
	mods, err := ctx.LoadModule(t, "HandlersRaw")
	if err != nil {
		return err
	}
	var handlers layer4.Handlers
	for _, mod := range mods.([]interface{}) {
		handlers = append(handlers, mod.(layer4.NextHandler))
	}
	t.compiledChain = handlers.Compile()

	return nil
}

// Handle handles the connection.
func (t Handler) Handle(cx *layer4.Connection, next layer4.Handler) error {
	// what is read by the next handler will also be
	// read by the branch handlers; this is done by
	// writing conn's reads into a pipe, and having
	// the branch read from the pipe
	pr, pw := io.Pipe()

	// this is the conn we pass to the next handler;
	// anything read by it will be teed into the pipe
	// (it also needs a pointer to the pipe so it can
	// close the pipe when the connection closes,
	// otherwise we'll leak the goroutine, yikes!)
	nextc := *cx
	nextc.Conn = nextConn{
		Conn:   cx,
		Reader: io.TeeReader(cx, pw),
		pipe:   pw,
	}

	// this is the conn we pass to the branch
	branchc := *cx
	branchc.Conn = teeConn{
		Conn:   cx,
		Reader: pr,
	}

	// run the branch concurrently
	go func() {
		err := t.compiledChain.Handle(&branchc)
		if err != nil {
			t.logger.Error("handling connection in branch", zap.Error(err))
		}
	}()

	return next.Handle(&nextc)
}

// teeConn is a connection wrapper that reads
// from a different reader.
type teeConn struct {
	net.Conn
	io.Reader
}

func (tc teeConn) Read(p []byte) (int, error) {
	return tc.Reader.Read(p)
}

// nextConn is a connection wrapper that reads from
// a different reader, and when the reader returns
// EOF, the associated pipe is closed.
type nextConn struct {
	net.Conn
	io.Reader
	pipe *io.PipeWriter
}

func (nc nextConn) Read(p []byte) (n int, err error) {
	n, err = nc.Reader.Read(p)
	if err == io.EOF {
		nc.pipe.Close()
	}
	return
}

// Interface guard
var _ layer4.NextHandler = (*Handler)(nil)


<|start_filename|>modules/l4echo/echo.go<|end_filename|>
// Copyright 2020 <NAME>
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package l4echo

import (
	"io"

	"github.com/caddyserver/caddy/v2"
	"github.com/mholt/caddy-l4/layer4"
)

func init() {
	caddy.RegisterModule(Handler{})
}

// Handler is a simple handler that writes what it reads.
type Handler struct{}

// CaddyModule returns the Caddy module information.
func (Handler) CaddyModule() caddy.ModuleInfo {
	return caddy.ModuleInfo{
		ID:  "layer4.handlers.echo",
		New: func() caddy.Module { return new(Handler) },
	}
}

// Handle handles the connection.
func (Handler) Handle(cx *layer4.Connection, _ layer4.Handler) error {
	_, err := io.Copy(cx, cx)
	return err
}

// Interface guard
var _ layer4.NextHandler = (*Handler)(nil)


<|start_filename|>modules/l4proxy/healthchecks.go<|end_filename|>
// Copyright 2020 <NAME>
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package l4proxy

import (
	"fmt"
	"log"
	"net"
	"runtime/debug"
	"time"

	"github.com/caddyserver/caddy/v2"
	"go.uber.org/zap"
)

// HealthChecks configures active and passive health checks.
type HealthChecks struct {
	// Active health checks run in the background on a timer. To
	// minimally enable active health checks, set either path or
	// port (or both).
	Active *ActiveHealthChecks `json:"active,omitempty"`

	// Passive health checks monitor proxied connections for errors or timeouts.
	// To minimally enable passive health checks, specify at least an empty
	// config object.
	Passive *PassiveHealthChecks `json:"passive,omitempty"`
}

// ActiveHealthChecks holds configuration related to active health
// checks (that is, health checks which occur independently in a
// background goroutine).
type ActiveHealthChecks struct {
	// The port to use (if different from the upstream's dial
	// address) for health checks.
	Port int `json:"port,omitempty"`

	// How frequently to perform active health checks (default 30s).
	Interval caddy.Duration `json:"interval,omitempty"`

	// How long to wait for a connection to be established with
	// peer before considering it unhealthy (default 5s).
	Timeout caddy.Duration `json:"timeout,omitempty"`

	logger *zap.Logger
}

// PassiveHealthChecks holds configuration related to passive
// health checks (that is, health checks which occur during
// the normal flow of connection proxying).
type PassiveHealthChecks struct {
	// How long to remember a failed connection to a backend. A
	// duration > 0 enables passive health checking. Default 0.
	FailDuration caddy.Duration `json:"fail_duration,omitempty"`

	// The number of failed connections within the FailDuration window to
	// consider a backend as "down". Must be >= 1; default is 1. Requires
	// that FailDuration be > 0.
	MaxFails int `json:"max_fails,omitempty"`

	// Limits the number of simultaneous connections to a backend by
	// marking the backend as "down" if it has this many or more
	// concurrent connections.
	UnhealthyConnectionCount int `json:"unhealthy_connnection_count,omitempty"`

	logger *zap.Logger
}

// activeHealthChecker runs active health checks on a
// regular basis and blocks until
// h.HealthChecks.Active.stopChan is closed.
func (h *Handler) activeHealthChecker() {
	defer func() {
		if err := recover(); err != nil {
			log.Printf("[PANIC] active health checks: %v\n%s", err, debug.Stack())
		}
	}()
	ticker := time.NewTicker(time.Duration(h.HealthChecks.Active.Interval))
	h.doActiveHealthCheckForAllHosts()
	for {
		select {
		case <-ticker.C:
			h.doActiveHealthCheckForAllHosts()
		case <-h.ctx.Done():
			ticker.Stop()
			return
		}
	}
}

// doActiveHealthCheckForAllHosts immediately performs a
// health checks for all upstream hosts configured by h.
func (h *Handler) doActiveHealthCheckForAllHosts() {
	for _, upstream := range h.Upstreams {
		go func(upstream *Upstream) {
			defer func() {
				if err := recover(); err != nil {
					log.Printf("[PANIC] active health check: %v\n%s", err, debug.Stack())
				}
			}()

			for _, p := range upstream.peers {
				err := h.doActiveHealthCheck(p)
				if err != nil {
					h.HealthChecks.Active.logger.Error("active health check failed",
						zap.String("peer", p.address.String()),
						zap.Error(err))
				}
			}
		}(upstream)
	}
}

// doActiveHealthCheck performs a health check to host which
// can be reached at address hostAddr. The health status of
// the host will be updated according to whether it passes
// the health check. An error is returned only if the health
// check fails to occur or if marking the host's health status
// fails.
func (h *Handler) doActiveHealthCheck(p *peer) error {
	addr := p.address

	// adjust the port, if configured to be different
	if h.HealthChecks.Active.Port > 0 {
		addr.StartPort = uint(h.HealthChecks.Active.Port)
		addr.EndPort = addr.StartPort
	}

	hostPort := addr.JoinHostPort(0)
	timeout := time.Duration(h.HealthChecks.Active.Timeout)

	conn, err := net.DialTimeout(addr.Network, hostPort, timeout)
	if err != nil {
		h.HealthChecks.Active.logger.Info("host is down",
			zap.String("address", addr.String()),
			zap.Duration("timeout", timeout),
			zap.Error(err))
		_, err2 := p.setHealthy(false)
		if err2 != nil {
			return fmt.Errorf("marking unhealthy: %v (original error: %v)", err2, err)
		}
		return nil
	}
	conn.Close()

	// connection succeeded, so mark as healthy
	swapped, err := p.setHealthy(true)
	if swapped {
		h.HealthChecks.Active.logger.Info("host is up", zap.String("address", addr.String()))
	}
	if err != nil {
		return fmt.Errorf("marking healthy: %v", err)
	}

	return nil
}


<|start_filename|>layer4/handlers.go<|end_filename|>
// Copyright 2020 <NAME>
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package layer4

// Handlers is a list of connection handlers.
type Handlers []NextHandler

// Compile assembles the list of handlers into a
// single handler chain.
func (h Handlers) Compile() Handler {
	var midware []Middleware
	for _, midhandler := range h {
		midware = append(midware, wrapHandler(midhandler))
	}
	var next Handler = nopHandler{}
	for i := len(midware) - 1; i >= 0; i-- {
		next = midware[i](next)
	}
	return next
}

// NextHandler is a type that can handle connections
// as part of a middleware chain.
type NextHandler interface {
	Handle(*Connection, Handler) error
}

// Handler is a type that can handle connections.
type Handler interface {
	Handle(*Connection) error
}

// Middleware is a function that wraps a handler.
type Middleware func(Handler) Handler

func wrapHandler(h NextHandler) Middleware {
	return func(next Handler) Handler {
		// TODO: copy next?
		return HandlerFunc(func(cx *Connection) error {
			return h.Handle(cx, next) // TODO: refer to copy here?
		})
	}
}

// HandlerFunc can turn a function into a Handler type.
type HandlerFunc func(*Connection) error

// Handle handles a connection; it implements the Handler interface.
func (h HandlerFunc) Handle(cx *Connection) error { return h(cx) }

// nopHandler is a connection handler that does nothing with the
// connection, not even reading from it; it simply returns. It is
// the default end of all handler chains.
//
// A nopHandler is distinct from a "discard" handler that reads
// the connection and drains it into a black hole: while such a
// handler would ensure that any concurrent branches handling the
// connection don't get blocked, it could also burn through data
// transfer unnecessarily. So as a slight security feature, we
// don't drain a client's unused connection, and instead opt to
// return and close the connection.
type nopHandler struct{}

func (nopHandler) Handle(_ *Connection) error { return nil }


<|start_filename|>modules/l4tls/parsehello.go<|end_filename|>
// Copyright 2020 <NAME>
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package l4tls

import (
	"crypto/tls"
	"strings"

	"golang.org/x/crypto/cryptobyte"
)

// Most of this file is borrowed from the Go standard library, ca. May 2020.
// It was written by the Go Authors and has this copyright:
//
//    Copyright 2009 The Go Authors. All rights reserved.
//    Use of this source code is governed by a BSD-style
//    license that can be found in the LICENSE file.
//
// This code has been modified since then.

func parseRawClientHello(data []byte) (info ClientHelloInfo) {
	defer func() {
		if len(info.SupportedVersions) == 0 {
			info.SupportedVersions = supportedVersionsFromMax(info.Version)
		}
	}()

	s := cryptobyte.String(data)

	if !s.Skip(4) || // message type and uint24 length field
		!s.ReadUint16(&info.Version) || !s.ReadBytes(&info.Random, 32) ||
		!readUint8LengthPrefixed(&s, &info.SessionID) {
		return
	}

	var cipherSuites cryptobyte.String
	if !s.ReadUint16LengthPrefixed(&cipherSuites) {
		return
	}
	for !cipherSuites.Empty() {
		var suite uint16
		if !cipherSuites.ReadUint16(&suite) {
			return
		}
		if suite == scsvRenegotiation {
			info.SecureRenegotiationSupported = true
		}
		info.CipherSuites = append(info.CipherSuites, suite)
	}

	if !readUint8LengthPrefixed(&s, &info.CompressionMethods) {
		return
	}

	if s.Empty() {
		// ClientHello is optionally followed by extension data
		return
	}

	var extensions cryptobyte.String
	if !s.ReadUint16LengthPrefixed(&extensions) || !s.Empty() {
		return
	}

	for !extensions.Empty() {
		var extension uint16
		var extData cryptobyte.String
		if !extensions.ReadUint16(&extension) ||
			!extensions.ReadUint16LengthPrefixed(&extData) {
			return
		}

		// record that client advertised support for this extension
		info.Extensions = append(info.Extensions, extension)

		switch extension {
		case extensionServerName:
			// RFC 6066, Section 3
			var nameList cryptobyte.String
			if !extData.ReadUint16LengthPrefixed(&nameList) || nameList.Empty() {
				return
			}
			for !nameList.Empty() {
				var nameType uint8
				var serverName cryptobyte.String
				if !nameList.ReadUint8(&nameType) ||
					!nameList.ReadUint16LengthPrefixed(&serverName) ||
					serverName.Empty() {
					return
				}
				if nameType != 0 {
					continue
				}
				if len(info.ServerName) != 0 {
					// Multiple names of the same name_type are prohibited.
					return
				}
				info.ServerName = string(serverName)
				// An SNI value may not include a trailing dot.
				if strings.HasSuffix(info.ServerName, ".") {
					return
				}
			}
		case extensionStatusRequest:
			// RFC 4366, Section 3.6
			var statusType uint8
			var ignored cryptobyte.String
			if !extData.ReadUint8(&statusType) ||
				!extData.ReadUint16LengthPrefixed(&ignored) ||
				!extData.ReadUint16LengthPrefixed(&ignored) {
				return
			}
			info.OCSPStapling = statusType == statusTypeOCSP
		case extensionSupportedCurves:
			// RFC 4492, sections 5.1.1 and RFC 8446, Section 4.2.7
			var curves cryptobyte.String
			if !extData.ReadUint16LengthPrefixed(&curves) || curves.Empty() {
				return
			}
			for !curves.Empty() {
				var curve uint16
				if !curves.ReadUint16(&curve) {
					return
				}
				info.SupportedCurves = append(info.SupportedCurves, tls.CurveID(curve))
			}
		case extensionSupportedPoints:
			// RFC 4492, Section 5.1.2
			if !readUint8LengthPrefixed(&extData, &info.SupportedPoints) ||
				len(info.SupportedPoints) == 0 {
				return
			}
		case extensionSessionTicket:
			// RFC 5077, Section 3.2
			info.TicketSupported = true
			extData.ReadBytes(&info.SessionTicket, len(extData))
		case extensionSignatureAlgorithms:
			// RFC 5246, Section 7.4.1.4.1
			var sigAndAlgs cryptobyte.String
			if !extData.ReadUint16LengthPrefixed(&sigAndAlgs) || sigAndAlgs.Empty() {
				return
			}
			for !sigAndAlgs.Empty() {
				var sigAndAlg uint16
				if !sigAndAlgs.ReadUint16(&sigAndAlg) {
					return
				}
				info.SignatureSchemes = append(
					info.SignatureSchemes, tls.SignatureScheme(sigAndAlg))
			}
		case extensionSignatureAlgorithmsCert:
			// RFC 8446, Section 4.2.3
			var sigAndAlgs cryptobyte.String
			if !extData.ReadUint16LengthPrefixed(&sigAndAlgs) || sigAndAlgs.Empty() {
				return
			}
			for !sigAndAlgs.Empty() {
				var sigAndAlg uint16
				if !sigAndAlgs.ReadUint16(&sigAndAlg) {
					return
				}
				info.SupportedSchemesCert = append(
					info.SupportedSchemesCert, tls.SignatureScheme(sigAndAlg))
			}
		case extensionRenegotiationInfo:
			// RFC 5746, Section 3.2
			if !readUint8LengthPrefixed(&extData, &info.SecureRenegotiation) {
				return
			}
			info.SecureRenegotiationSupported = true
		case extensionALPN:
			// RFC 7301, Section 3.1
			var protoList cryptobyte.String
			if !extData.ReadUint16LengthPrefixed(&protoList) || protoList.Empty() {
				return
			}
			for !protoList.Empty() {
				var proto cryptobyte.String
				if !protoList.ReadUint8LengthPrefixed(&proto) || proto.Empty() {
					return
				}
				info.SupportedProtos = append(info.SupportedProtos, string(proto))
			}
		case extensionSCT:
			// RFC 6962, Section 3.3.1
			info.SCTs = true
		case extensionSupportedVersions:
			// RFC 8446, Section 4.2.1
			var versList cryptobyte.String
			if !extData.ReadUint8LengthPrefixed(&versList) || versList.Empty() {
				return
			}
			for !versList.Empty() {
				var vers uint16
				if !versList.ReadUint16(&vers) {
					return
				}
				info.SupportedVersions = append(info.SupportedVersions, vers)
			}
		case extensionCookie:
			// RFC 8446, Section 4.2.2
			if !readUint16LengthPrefixed(&extData, &info.Cookie) ||
				len(info.Cookie) == 0 {
				return
			}
		case extensionKeyShare:
			// RFC 8446, Section 4.2.8
			var clientShares cryptobyte.String
			if !extData.ReadUint16LengthPrefixed(&clientShares) {
				return
			}
			for !clientShares.Empty() {
				var ks KeyShare
				if !clientShares.ReadUint16((*uint16)(&ks.Group)) ||
					!readUint16LengthPrefixed(&clientShares, &ks.Data) ||
					len(ks.Data) == 0 {
					return
				}
				info.KeyShares = append(info.KeyShares, ks)
			}
		case extensionEarlyData:
			// RFC 8446, Section 4.2.10
			info.EarlyData = true
		case extensionPSKModes:
			// RFC 8446, Section 4.2.9
			if !readUint8LengthPrefixed(&extData, &info.PSKModes) {
				return
			}
		case extensionPreSharedKey:
			// RFC 8446, Section 4.2.11
			if !extensions.Empty() {
				return // pre_shared_key must be the last extension
			}
			var identities cryptobyte.String
			if !extData.ReadUint16LengthPrefixed(&identities) || identities.Empty() {
				return
			}
			for !identities.Empty() {
				var psk PSKIdentity
				if !readUint16LengthPrefixed(&identities, &psk.label) ||
					!identities.ReadUint32(&psk.obfuscatedTicketAge) ||
					len(psk.label) == 0 {
					return
				}
				info.PSKIdentities = append(info.PSKIdentities, psk)
			}
			var binders cryptobyte.String
			if !extData.ReadUint16LengthPrefixed(&binders) || binders.Empty() {
				return
			}
			for !binders.Empty() {
				var binder []byte
				if !readUint8LengthPrefixed(&binders, &binder) ||
					len(binder) == 0 {
					return
				}
				info.PSKBinders = append(info.PSKBinders, binder)
			}
		default:
			// Ignore unknown extensions.
			continue
		}

		if !extData.Empty() {
			return
		}
	}

	return
}

// allKnownVersions is all the TLS versions this package knows.
var allKnownVersions = []uint16{
	tls.VersionTLS13,
	tls.VersionTLS12,
	tls.VersionTLS11,
	tls.VersionTLS10,
}

// supportedVersionsFromMax returns a list of supported versions derived from a
// legacy maximum version value. Note that only versions supported by this
// library are returned. Any newer peer will use allKnownVersions anyway.
func supportedVersionsFromMax(maxVersion uint16) []uint16 {
	versions := make([]uint16, 0, len(allKnownVersions))
	for _, v := range allKnownVersions {
		if v > maxVersion {
			continue
		}
		versions = append(versions, v)
	}
	return versions
}

// readUint8LengthPrefixed acts like s.ReadUint8LengthPrefixed, but targets a
// []byte instead of a cryptobyte.String.
func readUint8LengthPrefixed(s *cryptobyte.String, out *[]byte) bool {
	return s.ReadUint8LengthPrefixed((*cryptobyte.String)(out))
}

// readUint16LengthPrefixed acts like s.ReadUint16LengthPrefixed, but targets a
// []byte instead of a cryptobyte.String.
func readUint16LengthPrefixed(s *cryptobyte.String, out *[]byte) bool {
	return s.ReadUint16LengthPrefixed((*cryptobyte.String)(out))
}

// TLS extension numbers
const (
	extensionServerName              uint16 = 0
	extensionStatusRequest           uint16 = 5
	extensionSupportedCurves         uint16 = 10 // supported_groups in TLS 1.3, see RFC 8446, Section 4.2.7
	extensionSupportedPoints         uint16 = 11
	extensionSignatureAlgorithms     uint16 = 13
	extensionALPN                    uint16 = 16
	extensionSCT                     uint16 = 18
	extensionSessionTicket           uint16 = 35
	extensionPreSharedKey            uint16 = 41
	extensionEarlyData               uint16 = 42
	extensionSupportedVersions       uint16 = 43
	extensionCookie                  uint16 = 44
	extensionPSKModes                uint16 = 45
	extensionCertificateAuthorities  uint16 = 47
	extensionSignatureAlgorithmsCert uint16 = 50
	extensionKeyShare                uint16 = 51
	extensionRenegotiationInfo       uint16 = 0xff01
)

// TLS signaling cipher suite values
const (
	scsvRenegotiation uint16 = 0x00ff
)

// TLS CertificateStatusType (RFC 3546)
const (
	statusTypeOCSP uint8 = 1
)

// KeyShare is a TLS 1.3 Key Share. See RFC 8446, Section 4.2.8.
type KeyShare struct {
	Group tls.CurveID
	Data  []byte
}

// PSKIdentity is a TLS 1.3 PSK Identity.
// Can be a Session Ticket, or a reference to a saved
// session. See RFC 8446, Section 4.2.11.
type PSKIdentity struct {
	label               []byte
	obfuscatedTicketAge uint32
}
