From ff5d9838277b1be085cc6f1ea578befbf764435b Mon Sep 17 00:00:00 2001 From: vnxme <46669194+vnxme@users.noreply.github.com> Date: Thu, 8 Aug 2024 15:57:31 +0300 Subject: [PATCH] Fix warnings, possible linter failures and typos (#223) * Fix warnings: unhandled errors * Fix warnings: redundant type conversions * Fix warnings: errors comparison and type conversion * Fix warnings: redundant function arguments * Fix warnings: built-in function name collisions * Fix warnings: typos in comments * Fix warnings: potential nil pointer dereference * Fix warnings: mixed value and pointer receivers * Fix warnings: remove deprecated weekrand.Seed() call * Fix possible linter failures: imports order * Fix README: caddyfile support * Fix README: sort matchers and handlers by name * Fix warnings: one more typo in comments * Fix warnings: potential nil pointer dereference, optimized --- README.md | 14 ++++---- integration/caddyfile_adapt_test.go | 1 + layer4/app.go | 10 +++--- layer4/connection.go | 2 +- layer4/connection_test.go | 10 +++--- layer4/listener.go | 15 +++++---- layer4/matchers.go | 34 +++++++++---------- layer4/matchers_test.go | 2 +- layer4/routes.go | 2 +- layer4/routes_test.go | 6 ++-- layer4/server.go | 21 ++++++------ modules/l4echo/echo.go | 7 ++-- modules/l4http/httpmatcher.go | 26 ++++++++------- modules/l4http/httpmatcher_test.go | 13 ++++---- modules/l4postgres/matcher.go | 11 ++++--- modules/l4proxy/healthchecks.go | 2 +- modules/l4proxy/loadbalancing.go | 43 ++++++++++++------------- modules/l4proxy/proxy.go | 24 +++++++------- modules/l4proxy/upstream.go | 5 +-- modules/l4proxyprotocol/handler.go | 9 +++--- modules/l4proxyprotocol/handler_test.go | 9 +++--- modules/l4proxyprotocol/matcher.go | 7 ++-- modules/l4proxyprotocol/matcher_test.go | 9 +++--- modules/l4rdp/matcher.go | 1 + modules/l4rdp/matcher_test.go | 3 +- modules/l4socks/socks4_matcher.go | 7 ++-- modules/l4socks/socks4_matcher_test.go | 3 +- modules/l4socks/socks5_handler.go | 9 +++--- modules/l4socks/socks5_handler_test.go | 5 +-- modules/l4socks/socks5_matcher.go | 7 ++-- modules/l4socks/socks5_matcher_test.go | 3 +- modules/l4ssh/matcher.go | 7 ++-- modules/l4subroute/handler.go | 7 ++-- modules/l4tee/tee.go | 17 +++++----- modules/l4throttle/throttle.go | 9 +++--- modules/l4tls/alpn_matcher.go | 10 +++--- modules/l4tls/handler.go | 7 ++-- modules/l4tls/matcher.go | 11 ++++--- modules/l4xmpp/matcher.go | 7 ++-- 39 files changed, 212 insertions(+), 183 deletions(-) diff --git a/README.md b/README.md index 3171451..8c45734 100644 --- a/README.md +++ b/README.md @@ -32,29 +32,29 @@ Current matchers: - **layer4.matchers.clock** - matches connections on the time they are wrapped/matched. - **layer4.matchers.http** - matches connections that start with HTTP requests. In addition, any [`http.matchers` modules](https://caddyserver.com/docs/modules/) can be used for matching on HTTP-specific properties of requests, such as header or path. Note that only the first request of each connection can be used for matching. -- **layer4.matchers.tls** - matches connections that start with TLS handshakes. In addition, any [`tls.handshake_match` modules](https://caddyserver.com/docs/modules/) can be used for matching on TLS-specific properties of the ClientHello, such as ServerName (SNI). -- **layer4.matchers.ssh** - matches connections that look like SSH connections. -- **layer4.matchers.postgres** - matches connections that look like Postgres connections. -- **layer4.matchers.remote_ip** - matches connections based on remote IP (or CIDR range). - **layer4.matchers.local_ip** - matches connections based on local IP (or CIDR range). - **layer4.matchers.not** - matches connections that aren't matched by inner matcher sets. +- **layer4.matchers.postgres** - matches connections that look like Postgres connections. - **layer4.matchers.proxy_protocol** - matches connections that start with [HAPROXY proxy protocol](https://www.haproxy.org/download/1.8/doc/proxy-protocol.txt). - **layer4.matchers.rdp** - matches connections that look like [RDP](https://winprotocoldoc.blob.core.windows.net/productionwindowsarchives/MS-RDPBCGR/%5BMS-RDPBCGR%5D.pdf). - **layer4.matchers.regexp** - matches connections that have the first packet bytes matching a regular expression. +- **layer4.matchers.remote_ip** - matches connections based on remote IP (or CIDR range). - **layer4.matchers.socks4** - matches connections that look like [SOCKSv4](https://www.openssh.com/txt/socks4.protocol). - **layer4.matchers.socks5** - matches connections that look like [SOCKSv5](https://www.rfc-editor.org/rfc/rfc1928.html). +- **layer4.matchers.ssh** - matches connections that look like SSH connections. +- **layer4.matchers.tls** - matches connections that start with TLS handshakes. In addition, any [`tls.handshake_match` modules](https://caddyserver.com/docs/modules/) can be used for matching on TLS-specific properties of the ClientHello, such as ServerName (SNI). - **layer4.matchers.xmpp** - matches connections that look like [XMPP](https://xmpp.org/about/technology-overview/). Current handlers: - **layer4.handlers.echo** - An echo server. - **layer4.handlers.proxy** - Powerful layer 4 proxy, capable of multiple upstreams (with load balancing and health checks) and establishing new TLS connections to backends. Optionally supports sending the [HAProxy proxy protocol](https://www.haproxy.org/download/1.8/doc/proxy-protocol.txt). +- **layer4.handlers.proxy_protocol** - Accepts the [HAPROXY proxy protocol](https://www.haproxy.org/download/1.8/doc/proxy-protocol.txt) on the receiving side. +- **layer4.handlers.socks5** - Handles [SOCKSv5](https://www.rfc-editor.org/rfc/rfc1928.html) proxy protocol connections. - **layer4.handlers.subroute** - Implements recursion logic, i.e. allows to match and handle already matched connections. - **layer4.handlers.tee** - Branches the handling of a connection into a concurrent handler chain. - **layer4.handlers.throttle** - Throttle connections to simulate slowness and latency. - **layer4.handlers.tls** - TLS termination. -- **layer4.handlers.proxy_protocol** - Accepts the [HAPROXY proxy protocol](https://www.haproxy.org/download/1.8/doc/proxy-protocol.txt) on the receiving side. -- **layer4.handlers.socks5** - Handles [SOCKSv5](https://www.rfc-editor.org/rfc/rfc1928.html) proxy protocol connections. Like the `http` app, some handlers are "terminal" meaning that they don't call the next handler in the chain. For example: `echo` and `proxy` are terminal handlers because they consume the client's input. @@ -75,7 +75,7 @@ Alternatively, to hack on the plugin code, you can clone it down, then build and ## Writing config -Since this app does not support Caddyfile (yet?), you will have to use Caddy's native JSON format to configure it. I highly recommend [this caddy-json-schema plugin by @abiosoft](https://github.com/abiosoft/caddy-json-schema) which can give you auto-complete and documentation right in your editor as you write your config! +This app supports Caddyfile, but you may also use Caddy's native JSON format to configure it. I highly recommend [this caddy-json-schema plugin by @abiosoft](https://github.com/abiosoft/caddy-json-schema) which can give you auto-complete and documentation right in your editor as you write your config! See below for some examples to help you get started. diff --git a/integration/caddyfile_adapt_test.go b/integration/caddyfile_adapt_test.go index b138b0c..14537b1 100644 --- a/integration/caddyfile_adapt_test.go +++ b/integration/caddyfile_adapt_test.go @@ -10,6 +10,7 @@ import ( "testing" "github.com/caddyserver/caddy/v2/caddytest" + _ "github.com/mholt/caddy-l4" ) diff --git a/layer4/app.go b/layer4/app.go index 4183044..5a5c55e 100644 --- a/layer4/app.go +++ b/layer4/app.go @@ -23,7 +23,7 @@ import ( ) func init() { - caddy.RegisterModule(App{}) + caddy.RegisterModule(&App{}) } // App is a Caddy app that operates closest to layer 4 of the OSI model. @@ -40,7 +40,7 @@ type App struct { } // CaddyModule returns the Caddy module information. -func (App) CaddyModule() caddy.ModuleInfo { +func (*App) CaddyModule() caddy.ModuleInfo { return caddy.ModuleInfo{ ID: "layer4", New: func() caddy.Module { return new(App) }, @@ -76,11 +76,11 @@ func (a *App) Start() error { case net.Listener: a.listeners = append(a.listeners, ln) lnAddr = caddy.JoinNetworkAddress(ln.Addr().Network(), ln.Addr().String(), "") - go s.serve(ln) + go func() { _ = s.serve(ln) }() case net.PacketConn: a.packetConns = append(a.packetConns, ln) lnAddr = caddy.JoinNetworkAddress(ln.LocalAddr().Network(), ln.LocalAddr().String(), "") - go s.servePacket(ln) + go func() { _ = s.servePacket(ln) }() } s.logger.Debug("listening", zap.String("address", lnAddr)) } @@ -90,7 +90,7 @@ func (a *App) Start() error { } // Stop stops the servers and closes all listeners. -func (a App) Stop() error { +func (a *App) Stop() error { for _, pc := range a.packetConns { err := pc.Close() if err != nil { diff --git a/layer4/connection.go b/layer4/connection.go index faae99f..f193a54 100644 --- a/layer4/connection.go +++ b/layer4/connection.go @@ -214,7 +214,7 @@ func (cx *Connection) GetVar(key string) interface{} { } // MatchingBytes returns all bytes currently available for matching. This is only intended for reading. -// Do not write into the slice. It's a view of the internal buffer and you will likely mess up the connection. +// Do not write into the slice. It's a view of the internal buffer, and you will likely mess up the connection. func (cx *Connection) MatchingBytes() []byte { return cx.buf[cx.offset:] } diff --git a/layer4/connection_test.go b/layer4/connection_test.go index d7626e6..306745f 100644 --- a/layer4/connection_test.go +++ b/layer4/connection_test.go @@ -10,11 +10,11 @@ import ( func TestConnection_FreezeAndUnfreeze(t *testing.T) { in, out := net.Pipe() - defer in.Close() - defer out.Close() + defer func() { _ = in.Close() }() + defer func() { _ = out.Close() }() cx := WrapConnection(out, []byte{}, zap.NewNop()) - defer cx.Close() + defer func() { _ = cx.Close() }() matcherData := []byte("foo") consumeData := []byte("bar") @@ -22,8 +22,8 @@ func TestConnection_FreezeAndUnfreeze(t *testing.T) { buf := make([]byte, len(matcherData)) go func() { - in.Write(matcherData) - in.Write(consumeData) + _, _ = in.Write(matcherData) + _, _ = in.Write(consumeData) }() // prefetch like server handler would diff --git a/layer4/listener.go b/layer4/listener.go index 451e749..70c2733 100644 --- a/layer4/listener.go +++ b/layer4/listener.go @@ -15,7 +15,7 @@ import ( ) func init() { - caddy.RegisterModule(ListenerWrapper{}) + caddy.RegisterModule(&ListenerWrapper{}) } // ListenerWrapper is a Caddy module that wraps App as a listener wrapper, it doesn't support udp. @@ -33,7 +33,7 @@ type ListenerWrapper struct { } // CaddyModule returns the Caddy module information. -func (ListenerWrapper) CaddyModule() caddy.ModuleInfo { +func (*ListenerWrapper) CaddyModule() caddy.ModuleInfo { return caddy.ModuleInfo{ ID: "caddy.listeners.layer4", New: func() caddy.Module { return new(ListenerWrapper) }, @@ -126,7 +126,8 @@ type listener struct { func (l *listener) loop() { for { conn, err := l.Listener.Accept() - if nerr, ok := err.(net.Error); ok && nerr.Temporary() { + var nerr net.Error + if errors.As(err, &nerr) && nerr.Temporary() { l.logger.Error("temporary error accepting connection", zap.Error(err)) continue } @@ -145,7 +146,7 @@ func (l *listener) loop() { close(l.connChan) }() for conn := range l.connChan { - conn.Close() + _ = conn.Close() } } @@ -156,8 +157,8 @@ func (l *listener) handle(conn net.Conn) { var err error defer func() { l.wg.Done() - if err != errHijacked { - conn.Close() + if !errors.Is(err, errHijacked) { + _ = conn.Close() } }() @@ -171,7 +172,7 @@ func (l *listener) handle(conn net.Conn) { start := time.Now() err = l.compiledRoute.Handle(cx) duration := time.Since(start) - if err != nil && err != errHijacked { + if err != nil && !errors.Is(err, errHijacked) { l.logger.Error("handling connection", zap.Error(err)) } diff --git a/layer4/matchers.go b/layer4/matchers.go index 12ea4bb..8409cf1 100644 --- a/layer4/matchers.go +++ b/layer4/matchers.go @@ -27,9 +27,9 @@ import ( ) func init() { - caddy.RegisterModule(MatchRemoteIP{}) - caddy.RegisterModule(MatchLocalIP{}) - caddy.RegisterModule(MatchNot{}) + caddy.RegisterModule(&MatchRemoteIP{}) + caddy.RegisterModule(&MatchLocalIP{}) + caddy.RegisterModule(&MatchNot{}) } // ConnMatcher is a type that can match a connection. @@ -83,14 +83,14 @@ 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 { +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 + matched = len(*mss) == 0 return } @@ -117,7 +117,7 @@ type MatchRemoteIP struct { } // CaddyModule returns the Caddy module information. -func (MatchRemoteIP) CaddyModule() caddy.ModuleInfo { +func (*MatchRemoteIP) CaddyModule() caddy.ModuleInfo { return caddy.ModuleInfo{ ID: "layer4.matchers.remote_ip", New: func() caddy.Module { return new(MatchRemoteIP) }, @@ -134,7 +134,7 @@ func (m *MatchRemoteIP) Provision(_ caddy.Context) (err error) { } // Match returns true if the connection is from one of the designated IP ranges. -func (m MatchRemoteIP) Match(cx *Connection) (bool, error) { +func (m *MatchRemoteIP) Match(cx *Connection) (bool, error) { clientIP, err := m.getRemoteIP(cx) if err != nil { return false, fmt.Errorf("getting remote IP: %v", err) @@ -147,7 +147,7 @@ func (m MatchRemoteIP) Match(cx *Connection) (bool, error) { return false, nil } -func (m MatchRemoteIP) getRemoteIP(cx *Connection) (netip.Addr, error) { +func (m *MatchRemoteIP) getRemoteIP(cx *Connection) (netip.Addr, error) { remote := cx.Conn.RemoteAddr().String() ipStr, _, err := net.SplitHostPort(remote) @@ -164,7 +164,7 @@ func (m MatchRemoteIP) getRemoteIP(cx *Connection) (netip.Addr, error) { // UnmarshalCaddyfile sets up the MatchRemoteIP from Caddyfile tokens. Syntax: // -// ip +// remote_ip func (m *MatchRemoteIP) UnmarshalCaddyfile(d *caddyfile.Dispenser) error { _, wrapper := d.Next(), d.Val() // consume wrapper name @@ -198,7 +198,7 @@ type MatchLocalIP struct { } // CaddyModule returns the Caddy module information. -func (MatchLocalIP) CaddyModule() caddy.ModuleInfo { +func (*MatchLocalIP) CaddyModule() caddy.ModuleInfo { return caddy.ModuleInfo{ ID: "layer4.matchers.local_ip", New: func() caddy.Module { return new(MatchLocalIP) }, @@ -206,7 +206,7 @@ func (MatchLocalIP) CaddyModule() caddy.ModuleInfo { } // Provision parses m's IP ranges, either from IP or CIDR expressions. -func (m *MatchLocalIP) Provision(ctx caddy.Context) error { +func (m *MatchLocalIP) Provision(_ caddy.Context) error { ipnets, err := ParseNetworks(m.Ranges) if err != nil { return err @@ -216,7 +216,7 @@ func (m *MatchLocalIP) Provision(ctx caddy.Context) error { } // Match returns true if the connection is from one of the designated IP ranges. -func (m MatchLocalIP) Match(cx *Connection) (bool, error) { +func (m *MatchLocalIP) Match(cx *Connection) (bool, error) { localIP, err := m.getLocalIP(cx) if err != nil { return false, fmt.Errorf("getting local IP: %v", err) @@ -229,7 +229,7 @@ func (m MatchLocalIP) Match(cx *Connection) (bool, error) { return false, nil } -func (m MatchLocalIP) getLocalIP(cx *Connection) (netip.Addr, error) { +func (m *MatchLocalIP) getLocalIP(cx *Connection) (netip.Addr, error) { remote := cx.Conn.LocalAddr().String() ipStr, _, err := net.SplitHostPort(remote) @@ -300,7 +300,7 @@ type MatchNot struct { } // CaddyModule implements caddy.Module. -func (MatchNot) CaddyModule() caddy.ModuleInfo { +func (*MatchNot) CaddyModule() caddy.ModuleInfo { return caddy.ModuleInfo{ ID: "layer4.matchers.not", New: func() caddy.Module { return new(MatchNot) }, @@ -315,7 +315,7 @@ func (m *MatchNot) UnmarshalJSON(data []byte) error { // MarshalJSON satisfies json.Marshaler by marshaling // m's raw matcher sets. -func (m MatchNot) MarshalJSON() ([]byte, error) { +func (m *MatchNot) MarshalJSON() ([]byte, error) { return json.Marshal(m.MatcherSetsRaw) } @@ -338,7 +338,7 @@ func (m *MatchNot) Provision(ctx caddy.Context) error { // Match returns true if r matches m. Since this matcher negates // the embedded matchers, false is returned if any of its matcher // sets return true. -func (m MatchNot) Match(r *Connection) (bool, error) { +func (m *MatchNot) Match(r *Connection) (bool, error) { for _, ms := range m.MatcherSets { match, err := ms.Match(r) if err != nil { diff --git a/layer4/matchers_test.go b/layer4/matchers_test.go index 3d61cb3..73a192b 100644 --- a/layer4/matchers_test.go +++ b/layer4/matchers_test.go @@ -48,7 +48,7 @@ type provisionableMatcher interface { } func provision(in provisionableMatcher) ConnMatcher { - in.Provision(caddy.Context{}) + _ = in.Provision(caddy.Context{}) return in } func TestNotMatcher(t *testing.T) { diff --git a/layer4/routes.go b/layer4/routes.go index cfa4003..bba6f0d 100644 --- a/layer4/routes.go +++ b/layer4/routes.go @@ -35,7 +35,7 @@ type Route struct { // Matchers define the conditions upon which to execute the handlers. // All matchers within the same set must match, and at least one set // must match; in other words, matchers are AND'ed together within a - // set, but multiple sets are OR'ed together. No matchers matches all. + // set, but multiple sets are OR'ed together. No matchers match all. MatcherSetsRaw []caddy.ModuleMap `json:"match,omitempty" caddy:"namespace=layer4.matchers"` // Handlers define the behavior for handling the stream. They are diff --git a/layer4/routes_test.go b/layer4/routes_test.go index 1db54c7..9024756 100644 --- a/layer4/routes_test.go +++ b/layer4/routes_test.go @@ -33,11 +33,11 @@ func TestMatchingTimeoutWorks(t *testing.T) { })) in, out := net.Pipe() - defer in.Close() - defer out.Close() + defer func() { _ = in.Close() }() + defer func() { _ = out.Close() }() cx := WrapConnection(out, []byte{}, zap.NewNop()) - defer cx.Close() + defer func() { _ = cx.Close() }() err = compiledRoutes.Handle(cx) if err != nil { diff --git a/layer4/server.go b/layer4/server.go index 6c5fd2c..092f501 100644 --- a/layer4/server.go +++ b/layer4/server.go @@ -16,6 +16,7 @@ package layer4 import ( "bytes" + "errors" "fmt" "io" "net" @@ -72,10 +73,11 @@ func (s *Server) Provision(ctx caddy.Context, logger *zap.Logger) error { return nil } -func (s Server) serve(ln net.Listener) error { +func (s *Server) serve(ln net.Listener) error { for { conn, err := ln.Accept() - if nerr, ok := err.(net.Error); ok && nerr.Timeout() { + var nerr net.Error + if errors.As(err, &nerr) && nerr.Timeout() { s.logger.Error("timeout accepting connection", zap.Error(err)) continue } @@ -86,7 +88,7 @@ func (s Server) serve(ln net.Listener) error { } } -func (s Server) servePacket(pc net.PacketConn) error { +func (s *Server) servePacket(pc net.PacketConn) error { // Spawn a goroutine whose only job is to consume packets from the socket // and send to the packets channel. packets := make(chan packet, 10) @@ -95,7 +97,8 @@ func (s Server) servePacket(pc net.PacketConn) error { buf := udpBufPool.Get().([]byte) n, addr, err := pc.ReadFrom(buf) if err != nil { - if netErr, ok := err.(net.Error); ok && netErr.Timeout() { + var netErr net.Error + if errors.As(err, &netErr) && netErr.Timeout() { continue } packets <- packet{err: err} @@ -113,7 +116,7 @@ func (s Server) servePacket(pc net.PacketConn) error { // be removed from this map after being closed. udpConns := make(map[string]*packetConn) // closeCh is used to receive notifications of socket closures from - // packetConn, which allows us to to remove stale connections (whose + // packetConn, which allows us to remove stale connections (whose // proxy handlers have completed) from the udpConns map. closeCh := make(chan string, 10) for { @@ -153,8 +156,8 @@ func (s Server) servePacket(pc net.PacketConn) error { } } -func (s Server) handle(conn net.Conn) { - defer conn.Close() +func (s *Server) handle(conn net.Conn) { + defer func() { _ = conn.Close() }() buf := bufPool.Get().([]byte) buf = buf[:0] @@ -285,7 +288,7 @@ func (pc *packetConn) Read(b []byte) (n int, err error) { return 0, io.EOF } -func (pc packetConn) Write(b []byte) (n int, err error) { +func (pc *packetConn) Write(b []byte) (n int, err error) { return pc.PacketConn.WriteTo(b, pc.addr) } @@ -308,7 +311,7 @@ func (pc *packetConn) Close() error { return nil } -func (pc packetConn) RemoteAddr() net.Addr { return pc.addr } +func (pc *packetConn) RemoteAddr() net.Addr { return pc.addr } var udpBufPool = sync.Pool{ New: func() interface{} { diff --git a/modules/l4echo/echo.go b/modules/l4echo/echo.go index e425d6c..6ab0fab 100644 --- a/modules/l4echo/echo.go +++ b/modules/l4echo/echo.go @@ -19,18 +19,19 @@ import ( "github.com/caddyserver/caddy/v2" "github.com/caddyserver/caddy/v2/caddyconfig/caddyfile" + "github.com/mholt/caddy-l4/layer4" ) func init() { - caddy.RegisterModule(Handler{}) + 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 { +func (*Handler) CaddyModule() caddy.ModuleInfo { return caddy.ModuleInfo{ ID: "layer4.handlers.echo", New: func() caddy.Module { return new(Handler) }, @@ -38,7 +39,7 @@ func (Handler) CaddyModule() caddy.ModuleInfo { } // Handle handles the connection. -func (Handler) Handle(cx *layer4.Connection, _ layer4.Handler) error { +func (*Handler) Handle(cx *layer4.Connection, _ layer4.Handler) error { _, err := io.Copy(cx, cx) return err } diff --git a/modules/l4http/httpmatcher.go b/modules/l4http/httpmatcher.go index ed9ac33..ffbd54c 100644 --- a/modules/l4http/httpmatcher.go +++ b/modules/l4http/httpmatcher.go @@ -26,14 +26,15 @@ import ( "github.com/caddyserver/caddy/v2" "github.com/caddyserver/caddy/v2/caddyconfig/caddyfile" "github.com/caddyserver/caddy/v2/modules/caddyhttp" - "github.com/mholt/caddy-l4/layer4" - "github.com/mholt/caddy-l4/modules/l4tls" "golang.org/x/net/http2" "golang.org/x/net/http2/hpack" + + "github.com/mholt/caddy-l4/layer4" + "github.com/mholt/caddy-l4/modules/l4tls" ) func init() { - caddy.RegisterModule(MatchHTTP{}) + caddy.RegisterModule(&MatchHTTP{}) } // MatchHTTP is able to match HTTP connections. The auto-generated @@ -45,7 +46,7 @@ type MatchHTTP struct { } // CaddyModule returns the Caddy module information. -func (MatchHTTP) CaddyModule() caddy.ModuleInfo { +func (*MatchHTTP) CaddyModule() caddy.ModuleInfo { return caddy.ModuleInfo{ ID: "layer4.matchers.http", New: func() caddy.Module { return new(MatchHTTP) }, @@ -58,7 +59,7 @@ func (m *MatchHTTP) UnmarshalJSON(b []byte) error { } // MarshalJSON satisfies the json.Marshaler interface. -func (m MatchHTTP) MarshalJSON() ([]byte, error) { +func (m *MatchHTTP) MarshalJSON() ([]byte, error) { return json.Marshal(m.MatcherSetsRaw) } @@ -76,7 +77,7 @@ func (m *MatchHTTP) Provision(ctx caddy.Context) error { } // Match returns true if the conn starts with an HTTP request. -func (m MatchHTTP) Match(cx *layer4.Connection) (bool, error) { +func (m *MatchHTTP) Match(cx *layer4.Connection) (bool, error) { // TODO: do we need a more standardized way to amortize matchers? or at least to remember decoded results from previous matchers? req, ok := cx.GetVar("http_request").(*http.Request) if !ok { @@ -123,7 +124,7 @@ func (m MatchHTTP) Match(cx *layer4.Connection) (bool, error) { return m.matcherSets.AnyMatch(req), nil } -func (m MatchHTTP) isHttp(data []byte) bool { +func (m *MatchHTTP) isHttp(data []byte) bool { // try to find the end of a http request line, for example " HTTP/1.1\r\n" i := bytes.IndexByte(data, 0x0a) // find first new line if i < 10 { @@ -141,7 +142,7 @@ func (m MatchHTTP) isHttp(data []byte) bool { } // Parses information from a http2 request with prior knowledge (RFC 7540 Section 3.4) -func (m MatchHTTP) handleHttp2WithPriorKnowledge(reader io.Reader, req *http.Request) error { +func (m *MatchHTTP) handleHttp2WithPriorKnowledge(reader io.Reader, req *http.Request) error { // Does req contain a valid http2 magic? // https://github.com/golang/net/blob/a630d4f3e7a22f21271532b4b88e1693824a838f/http2/h2c/h2c.go#L74 if req.Method != "PRI" || len(req.Header) != 0 || req.URL.Path != "*" || req.Proto != "HTTP/2.0" { @@ -164,18 +165,19 @@ func (m MatchHTTP) handleHttp2WithPriorKnowledge(reader io.Reader, req *http.Req // read the first 10 frames until we get a headers frame (skipping settings, window update & priority frames) var frame http2.Frame - for i := 0; i < 10; i++ { + maxAttempts := 10 + for i := 0; i < maxAttempts; i++ { frame, err = framer.ReadFrame() if err != nil { return err } if frame.Header().Type == http2.FrameHeaders { + maxAttempts = 0 break } } - - if frame.Header().Type != http2.FrameHeaders { - return fmt.Errorf("failed to read a http2 headers frame after 10 attempts") + if maxAttempts != 0 { + return fmt.Errorf("failed to read a http2 headers frame after %d attempts", maxAttempts) } decoder := hpack.NewDecoder(4096, nil) // max table size 4096 from http2.initialHeaderTableSize diff --git a/modules/l4http/httpmatcher_test.go b/modules/l4http/httpmatcher_test.go index 19d1e0a..7028436 100644 --- a/modules/l4http/httpmatcher_test.go +++ b/modules/l4http/httpmatcher_test.go @@ -11,8 +11,9 @@ import ( "github.com/caddyserver/caddy/v2" "github.com/caddyserver/caddy/v2/modules/caddyhttp" - "github.com/mholt/caddy-l4/layer4" "go.uber.org/zap" + + "github.com/mholt/caddy-l4/layer4" ) func assertNoError(t *testing.T, err error) { @@ -24,8 +25,8 @@ func assertNoError(t *testing.T, err error) { func httpMatchTester(t *testing.T, matchers json.RawMessage, data []byte) (bool, error) { in, out := net.Pipe() - defer in.Close() - defer out.Close() + defer func() { _ = in.Close() }() + defer func() { _ = out.Close() }() cx := layer4.WrapConnection(in, make([]byte, 0), zap.NewNop()) go func() { @@ -211,8 +212,8 @@ func TestHttpMatchingByProtocolWithHttps(t *testing.T) { })) in, out := net.Pipe() - defer in.Close() - defer out.Close() + defer func() { _ = in.Close() }() + defer func() { _ = out.Close() }() cx := layer4.WrapConnection(in, []byte{}, zap.NewNop()) go func() { @@ -290,7 +291,7 @@ func TestMatchHTTP_isHttp(t *testing.T) { }, } { t.Run(tc.name, func(t *testing.T) { - matched := MatchHTTP{}.isHttp(tc.data) + matched := (&MatchHTTP{}).isHttp(tc.data) if matched != tc.shouldMatch { t.Fatalf("test %v | matched: %v != shouldMatch: %v", tc.name, matched, tc.shouldMatch) } diff --git a/modules/l4postgres/matcher.go b/modules/l4postgres/matcher.go index d5dfc94..c97d18e 100644 --- a/modules/l4postgres/matcher.go +++ b/modules/l4postgres/matcher.go @@ -30,11 +30,12 @@ import ( "github.com/caddyserver/caddy/v2" "github.com/caddyserver/caddy/v2/caddyconfig/caddyfile" + "github.com/mholt/caddy-l4/layer4" ) func init() { - caddy.RegisterModule(MatchPostgres{}) + caddy.RegisterModule(&MatchPostgres{}) } const ( @@ -59,8 +60,8 @@ func (b *message) ReadUint32() (r uint32) { func (b *message) ReadString() (r string) { end := b.offset - max := uint32(len(b.data)) - for ; end != max && b.data[end] != 0; end++ { + maximum := uint32(len(b.data)) + for ; end != maximum && b.data[end] != 0; end++ { } r = string(b.data[b.offset:end]) b.offset = end + 1 @@ -82,7 +83,7 @@ type startupMessage struct { type MatchPostgres struct{} // CaddyModule returns the Caddy module information. -func (MatchPostgres) CaddyModule() caddy.ModuleInfo { +func (*MatchPostgres) CaddyModule() caddy.ModuleInfo { return caddy.ModuleInfo{ ID: "layer4.matchers.postgres", New: func() caddy.Module { return new(MatchPostgres) }, @@ -90,7 +91,7 @@ func (MatchPostgres) CaddyModule() caddy.ModuleInfo { } // Match returns true if the connection looks like the Postgres protocol. -func (m MatchPostgres) Match(cx *layer4.Connection) (bool, error) { +func (m *MatchPostgres) Match(cx *layer4.Connection) (bool, error) { // Get bytes containing the message length head := make([]byte, initMessageSizeLength) if _, err := io.ReadFull(cx, head); err != nil { diff --git a/modules/l4proxy/healthchecks.go b/modules/l4proxy/healthchecks.go index cfdf118..3f0c2c2 100644 --- a/modules/l4proxy/healthchecks.go +++ b/modules/l4proxy/healthchecks.go @@ -152,7 +152,7 @@ func (h *Handler) doActiveHealthCheck(p *peer) error { } return nil } - conn.Close() + _ = conn.Close() // connection succeeded, so mark as healthy swapped, err := p.setHealthy(true) diff --git a/modules/l4proxy/loadbalancing.go b/modules/l4proxy/loadbalancing.go index f246617..5b80955 100644 --- a/modules/l4proxy/loadbalancing.go +++ b/modules/l4proxy/loadbalancing.go @@ -26,6 +26,7 @@ import ( "github.com/caddyserver/caddy/v2" "github.com/caddyserver/caddy/v2/caddyconfig/caddyfile" + "github.com/mholt/caddy-l4/layer4" ) @@ -76,14 +77,12 @@ type Selector interface { } func init() { - caddy.RegisterModule(RandomSelection{}) - caddy.RegisterModule(RandomChoiceSelection{}) - caddy.RegisterModule(LeastConnSelection{}) - caddy.RegisterModule(RoundRobinSelection{}) - caddy.RegisterModule(FirstSelection{}) - caddy.RegisterModule(IPHashSelection{}) - - weakrand.Seed(time.Now().UTC().UnixNano()) + caddy.RegisterModule(&RandomSelection{}) + caddy.RegisterModule(&RandomChoiceSelection{}) + caddy.RegisterModule(&LeastConnSelection{}) + caddy.RegisterModule(&RoundRobinSelection{}) + caddy.RegisterModule(&FirstSelection{}) + caddy.RegisterModule(&IPHashSelection{}) } // RandomSelection is a policy that selects @@ -91,7 +90,7 @@ func init() { type RandomSelection struct{} // CaddyModule returns the Caddy module information. -func (RandomSelection) CaddyModule() caddy.ModuleInfo { +func (*RandomSelection) CaddyModule() caddy.ModuleInfo { return caddy.ModuleInfo{ ID: "layer4.proxy.selection_policies.random", New: func() caddy.Module { return new(RandomSelection) }, @@ -99,7 +98,7 @@ func (RandomSelection) CaddyModule() caddy.ModuleInfo { } // Select returns an available host, if any. -func (r RandomSelection) Select(pool UpstreamPool, conn *layer4.Connection) *Upstream { +func (r *RandomSelection) Select(pool UpstreamPool, _ *layer4.Connection) *Upstream { // use reservoir sampling because the number of available // hosts isn't known: https://en.wikipedia.org/wiki/Reservoir_sampling var randomHost *Upstream @@ -108,7 +107,7 @@ func (r RandomSelection) Select(pool UpstreamPool, conn *layer4.Connection) *Ups if !upstream.available() { continue } - // (n % 1 == 0) holds for all n, therefore a + // (n % 1 == 0) holds for all n, therefore an // upstream will always be chosen if there is at // least one available count++ @@ -148,7 +147,7 @@ type RandomChoiceSelection struct { } // CaddyModule returns the Caddy module information. -func (RandomChoiceSelection) CaddyModule() caddy.ModuleInfo { +func (*RandomChoiceSelection) CaddyModule() caddy.ModuleInfo { return caddy.ModuleInfo{ ID: "layer4.proxy.selection_policies.random_choose", New: func() caddy.Module { return new(RandomChoiceSelection) }, @@ -156,7 +155,7 @@ func (RandomChoiceSelection) CaddyModule() caddy.ModuleInfo { } // Provision sets up r. -func (r *RandomChoiceSelection) Provision(ctx caddy.Context) error { +func (r *RandomChoiceSelection) Provision(_ caddy.Context) error { if r.Choose == 0 { r.Choose = 2 } @@ -164,7 +163,7 @@ func (r *RandomChoiceSelection) Provision(ctx caddy.Context) error { } // Validate ensures that r's configuration is valid. -func (r RandomChoiceSelection) Validate() error { +func (r *RandomChoiceSelection) Validate() error { if r.Choose < 2 { return fmt.Errorf("choose must be at least 2") } @@ -172,7 +171,7 @@ func (r RandomChoiceSelection) Validate() error { } // Select returns an available host, if any. -func (r RandomChoiceSelection) Select(pool UpstreamPool, _ *layer4.Connection) *Upstream { +func (r *RandomChoiceSelection) Select(pool UpstreamPool, _ *layer4.Connection) *Upstream { k := r.Choose if k > len(pool) { k = len(pool) @@ -224,7 +223,7 @@ func (r *RandomChoiceSelection) UnmarshalCaddyfile(d *caddyfile.Dispenser) error type LeastConnSelection struct{} // CaddyModule returns the Caddy module information. -func (LeastConnSelection) CaddyModule() caddy.ModuleInfo { +func (*LeastConnSelection) CaddyModule() caddy.ModuleInfo { return caddy.ModuleInfo{ ID: "layer4.proxy.selection_policies.least_conn", New: func() caddy.Module { return new(LeastConnSelection) }, @@ -234,7 +233,7 @@ func (LeastConnSelection) CaddyModule() caddy.ModuleInfo { // Select selects the up host with the least number of connections in the // pool. If more than one host has the same least number of connections, // one of the hosts is chosen at random. -func (LeastConnSelection) Select(pool UpstreamPool, _ *layer4.Connection) *Upstream { +func (*LeastConnSelection) Select(pool UpstreamPool, _ *layer4.Connection) *Upstream { var best *Upstream var count int leastConns := -1 @@ -288,7 +287,7 @@ type RoundRobinSelection struct { } // CaddyModule returns the Caddy module information. -func (RoundRobinSelection) CaddyModule() caddy.ModuleInfo { +func (*RoundRobinSelection) CaddyModule() caddy.ModuleInfo { return caddy.ModuleInfo{ ID: "layer4.proxy.selection_policies.round_robin", New: func() caddy.Module { return new(RoundRobinSelection) }, @@ -335,7 +334,7 @@ func (r *RoundRobinSelection) UnmarshalCaddyfile(d *caddyfile.Dispenser) error { type FirstSelection struct{} // CaddyModule returns the Caddy module information. -func (FirstSelection) CaddyModule() caddy.ModuleInfo { +func (*FirstSelection) CaddyModule() caddy.ModuleInfo { return caddy.ModuleInfo{ ID: "layer4.proxy.selection_policies.first", New: func() caddy.Module { return new(FirstSelection) }, @@ -343,7 +342,7 @@ func (FirstSelection) CaddyModule() caddy.ModuleInfo { } // Select returns an available host, if any. -func (FirstSelection) Select(pool UpstreamPool, _ *layer4.Connection) *Upstream { +func (*FirstSelection) Select(pool UpstreamPool, _ *layer4.Connection) *Upstream { for _, host := range pool { if host.available() { return host @@ -376,7 +375,7 @@ func (r *FirstSelection) UnmarshalCaddyfile(d *caddyfile.Dispenser) error { type IPHashSelection struct{} // CaddyModule returns the Caddy module information. -func (IPHashSelection) CaddyModule() caddy.ModuleInfo { +func (*IPHashSelection) CaddyModule() caddy.ModuleInfo { return caddy.ModuleInfo{ ID: "layer4.proxy.selection_policies.ip_hash", New: func() caddy.Module { return new(IPHashSelection) }, @@ -384,7 +383,7 @@ func (IPHashSelection) CaddyModule() caddy.ModuleInfo { } // Select returns an available host, if any. -func (IPHashSelection) Select(pool UpstreamPool, conn *layer4.Connection) *Upstream { +func (*IPHashSelection) Select(pool UpstreamPool, conn *layer4.Connection) *Upstream { remoteAddr := conn.Conn.RemoteAddr().String() clientIP, _, err := net.SplitHostPort(remoteAddr) if err != nil { diff --git a/modules/l4proxy/proxy.go b/modules/l4proxy/proxy.go index 36a1eb5..f1a8e50 100644 --- a/modules/l4proxy/proxy.go +++ b/modules/l4proxy/proxy.go @@ -17,9 +17,7 @@ package l4proxy import ( "crypto/tls" "fmt" - "github.com/caddyserver/caddy/v2/caddyconfig" "io" - "io/ioutil" "log" "net" "runtime/debug" @@ -29,16 +27,18 @@ import ( "time" "github.com/caddyserver/caddy/v2" + "github.com/caddyserver/caddy/v2/caddyconfig" "github.com/caddyserver/caddy/v2/caddyconfig/caddyfile" "github.com/mastercactapus/proxyprotocol" + "go.uber.org/zap" + "github.com/mholt/caddy-l4/layer4" "github.com/mholt/caddy-l4/modules/l4proxyprotocol" "github.com/mholt/caddy-l4/modules/l4tls" - "go.uber.org/zap" ) func init() { - caddy.RegisterModule(Handler{}) + caddy.RegisterModule(&Handler{}) } // Handler is a handler that can proxy connections. @@ -62,7 +62,7 @@ type Handler struct { } // CaddyModule returns the Caddy module information. -func (Handler) CaddyModule() caddy.ModuleInfo { +func (*Handler) CaddyModule() caddy.ModuleInfo { return caddy.ModuleInfo{ ID: "layer4.handlers.proxy", New: func() caddy.Module { return new(Handler) }, @@ -127,7 +127,7 @@ func (h *Handler) Provision(ctx caddy.Context) error { h.LoadBalancing = new(LoadBalancing) } if h.LoadBalancing.SelectionPolicy == nil { - h.LoadBalancing.SelectionPolicy = RandomSelection{} + h.LoadBalancing.SelectionPolicy = &RandomSelection{} } if h.LoadBalancing.TryDuration > 0 && h.LoadBalancing.TryInterval == 0 { // a non-zero try_duration with a zero try_interval @@ -141,7 +141,7 @@ func (h *Handler) Provision(ctx caddy.Context) error { } // Handle handles the downstream connection. -func (h Handler) Handle(down *layer4.Connection, _ layer4.Handler) error { +func (h *Handler) Handle(down *layer4.Connection, _ layer4.Handler) error { repl := down.Context.Value(layer4.ReplacerCtxKey).(*caddy.Replacer) start := time.Now() @@ -178,7 +178,7 @@ func (h Handler) Handle(down *layer4.Connection, _ layer4.Handler) error { // make sure upstream connections all get closed defer func() { for _, conn := range upConns { - conn.Close() + _ = conn.Close() } }() @@ -235,7 +235,7 @@ func (h *Handler) dialPeers(upstream *Upstream, repl *caddy.Replacer, down *laye if err != nil { h.countFailure(p) for _, conn := range upConns { - conn.Close() + _ = conn.Close() } return nil, err } @@ -285,7 +285,7 @@ func (h *Handler) proxy(down *layer4.Connection, upConns []net.Conn) { go func() { // read from downstream until connection is closed; // TODO: this pumps the reader, but writing into discard is a weird way to do it; could be avoided if we used io.Pipe - see _gitignore/oldtee.go.txt - io.Copy(ioutil.Discard, downTee) + _, _ = io.Copy(io.Discard, downTee) downConnClosedCh <- struct{}{} // Shut down the writing side of all upstream connections, in case @@ -301,7 +301,7 @@ func (h *Handler) proxy(down *layer4.Connection, upConns []net.Conn) { if conn, ok := up.(closeWriter); ok { _ = conn.CloseWrite() } else { - up.Close() + _ = up.Close() } } }() @@ -365,7 +365,7 @@ func (h *Handler) Cleanup() error { // remove hosts from our config from the pool for _, upstream := range h.Upstreams { for _, dialAddr := range upstream.Dial { - peers.Delete(dialAddr) + _, _ = peers.Delete(dialAddr) } } return nil diff --git a/modules/l4proxy/upstream.go b/modules/l4proxy/upstream.go index d49eaa9..63dc7cf 100644 --- a/modules/l4proxy/upstream.go +++ b/modules/l4proxy/upstream.go @@ -26,6 +26,7 @@ import ( "github.com/caddyserver/caddy/v2/caddyconfig/caddyfile" "github.com/caddyserver/caddy/v2/modules/caddyhttp/reverseproxy" "github.com/caddyserver/caddy/v2/modules/caddytls" + "github.com/mholt/caddy-l4/layer4" ) @@ -50,7 +51,7 @@ type Upstream struct { healthCheckPolicy *PassiveHealthChecks } -func (u Upstream) String() string { +func (u *Upstream) String() string { return strings.Join(u.Dial, ",") } @@ -85,7 +86,7 @@ func (u *Upstream) provision(ctx caddy.Context, h *Handler) error { // 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 + // but the passive health checker is a default value for upstreams // without MaxConnections), copy the value into this upstream, since the // value in the upstream (MaxConnections) is what is used during // availability checks diff --git a/modules/l4proxyprotocol/handler.go b/modules/l4proxyprotocol/handler.go index ad28be0..aa3242a 100644 --- a/modules/l4proxyprotocol/handler.go +++ b/modules/l4proxyprotocol/handler.go @@ -23,12 +23,13 @@ import ( "github.com/caddyserver/caddy/v2" "github.com/caddyserver/caddy/v2/caddyconfig/caddyfile" "github.com/mastercactapus/proxyprotocol" - "github.com/mholt/caddy-l4/layer4" "go.uber.org/zap" + + "github.com/mholt/caddy-l4/layer4" ) func init() { - caddy.RegisterModule(Handler{}) + caddy.RegisterModule(&Handler{}) } // Handler is a connection handler that accepts the PROXY protocol. @@ -45,7 +46,7 @@ type Handler struct { } // CaddyModule returns the Caddy module information. -func (Handler) CaddyModule() caddy.ModuleInfo { +func (*Handler) CaddyModule() caddy.ModuleInfo { return caddy.ModuleInfo{ ID: "layer4.handlers.proxy_protocol", New: func() caddy.Module { return new(Handler) }, @@ -91,7 +92,7 @@ func (h *Handler) tidyRules() { }) if len(rules) > 0 { - // dedup + // deduplication last := rules[0] nf := rules[1:1] for _, f := range rules[1:] { diff --git a/modules/l4proxyprotocol/handler_test.go b/modules/l4proxyprotocol/handler_test.go index 741592a..3a8997a 100644 --- a/modules/l4proxyprotocol/handler_test.go +++ b/modules/l4proxyprotocol/handler_test.go @@ -8,8 +8,9 @@ import ( "testing" "github.com/caddyserver/caddy/v2" - "github.com/mholt/caddy-l4/layer4" "go.uber.org/zap" + + "github.com/mholt/caddy-l4/layer4" ) func assertString(t *testing.T, expected string, value string) { @@ -28,7 +29,7 @@ func TestProxyProtocolHandleV1(t *testing.T) { go func() { wg.Add(1) defer wg.Done() - defer out.Close() + defer func() { _ = out.Close() }() _, err := out.Write(ProxyV1Example) assertNoError(t, err) }() @@ -66,7 +67,7 @@ func TestProxyProtocolHandleV2(t *testing.T) { go func() { wg.Add(1) defer wg.Done() - defer out.Close() + defer func() { _ = out.Close() }() _, err := out.Write(ProxyV2Example) assertNoError(t, err) }() @@ -104,7 +105,7 @@ func TestProxyProtocolHandleGarbage(t *testing.T) { go func() { wg.Add(1) defer wg.Done() - defer out.Close() + defer func() { _ = out.Close() }() _, err := out.Write([]byte("some garbage")) assertNoError(t, err) }() diff --git a/modules/l4proxyprotocol/matcher.go b/modules/l4proxyprotocol/matcher.go index e40028c..b4a4e15 100644 --- a/modules/l4proxyprotocol/matcher.go +++ b/modules/l4proxyprotocol/matcher.go @@ -20,6 +20,7 @@ import ( "github.com/caddyserver/caddy/v2" "github.com/caddyserver/caddy/v2/caddyconfig/caddyfile" + "github.com/mholt/caddy-l4/layer4" ) @@ -30,13 +31,13 @@ var ( ) func init() { - caddy.RegisterModule(MatchProxyProtocol{}) + caddy.RegisterModule(&MatchProxyProtocol{}) } type MatchProxyProtocol struct{} // CaddyModule returns the Caddy module information. -func (MatchProxyProtocol) CaddyModule() caddy.ModuleInfo { +func (*MatchProxyProtocol) CaddyModule() caddy.ModuleInfo { return caddy.ModuleInfo{ ID: "layer4.matchers.proxy_protocol", New: func() caddy.Module { return new(MatchProxyProtocol) }, @@ -44,7 +45,7 @@ func (MatchProxyProtocol) CaddyModule() caddy.ModuleInfo { } // Match returns true if the connection looks like it is using the Proxy Protocol. -func (m MatchProxyProtocol) Match(cx *layer4.Connection) (bool, error) { +func (m *MatchProxyProtocol) Match(cx *layer4.Connection) (bool, error) { buf := make([]byte, len(headerV2Prefix)) _, err := io.ReadFull(cx, buf) if err != nil { diff --git a/modules/l4proxyprotocol/matcher_test.go b/modules/l4proxyprotocol/matcher_test.go index c34d33c..1e48cfb 100644 --- a/modules/l4proxyprotocol/matcher_test.go +++ b/modules/l4proxyprotocol/matcher_test.go @@ -7,8 +7,9 @@ import ( "sync" "testing" - "github.com/mholt/caddy-l4/layer4" "go.uber.org/zap" + + "github.com/mholt/caddy-l4/layer4" ) var ProxyV1Example = []byte("PROXY TCP4 192.168.0.1 192.168.0.11 56324 443\r\n") @@ -36,7 +37,7 @@ func TestProxyProtocolMatchV1(t *testing.T) { go func() { wg.Add(1) defer wg.Done() - defer out.Close() + defer func() { _ = out.Close() }() _, err := out.Write(ProxyV1Example) assertNoError(t, err) }() @@ -62,7 +63,7 @@ func TestProxyProtocolMatchV2(t *testing.T) { go func() { wg.Add(1) defer wg.Done() - defer out.Close() + defer func() { _ = out.Close() }() _, err := out.Write(ProxyV2Example) assertNoError(t, err) }() @@ -88,7 +89,7 @@ func TestProxyProtocolMatchGarbage(t *testing.T) { go func() { wg.Add(1) defer wg.Done() - defer out.Close() + defer func() { _ = out.Close() }() _, err := out.Write([]byte("Hello World Hello World Hello World Hello World")) assertNoError(t, err) }() diff --git a/modules/l4rdp/matcher.go b/modules/l4rdp/matcher.go index 3be133b..5f99ec1 100644 --- a/modules/l4rdp/matcher.go +++ b/modules/l4rdp/matcher.go @@ -27,6 +27,7 @@ import ( "github.com/caddyserver/caddy/v2" "github.com/caddyserver/caddy/v2/caddyconfig/caddyfile" + "github.com/mholt/caddy-l4/layer4" ) diff --git a/modules/l4rdp/matcher_test.go b/modules/l4rdp/matcher_test.go index 223d5a9..594cdb3 100644 --- a/modules/l4rdp/matcher_test.go +++ b/modules/l4rdp/matcher_test.go @@ -22,8 +22,9 @@ import ( "testing" "github.com/caddyserver/caddy/v2" - "github.com/mholt/caddy-l4/layer4" "go.uber.org/zap" + + "github.com/mholt/caddy-l4/layer4" ) func assertNoError(t *testing.T, err error) { diff --git a/modules/l4socks/socks4_matcher.go b/modules/l4socks/socks4_matcher.go index efbae5e..f869f3c 100644 --- a/modules/l4socks/socks4_matcher.go +++ b/modules/l4socks/socks4_matcher.go @@ -10,17 +10,18 @@ import ( "github.com/caddyserver/caddy/v2" "github.com/caddyserver/caddy/v2/caddyconfig/caddyfile" + "github.com/mholt/caddy-l4/layer4" ) func init() { - caddy.RegisterModule(Socks4Matcher{}) + caddy.RegisterModule(&Socks4Matcher{}) } // Socks4Matcher matches SOCKSv4 connections according to https://www.openssh.com/txt/socks4.protocol. // Since the SOCKSv4 header is very short it could produce a lot of false positives. // To improve the matching use Commands, Ports and Networks to specify to which destinations you expect clients to connect to. -// By default CONNECT & BIND commands are matched with any destination ip and port. +// By default, CONNECT & BIND commands are matched with any destination ip and port. type Socks4Matcher struct { // Only match on these commands. Default: ["CONNECT", "BIND"] Commands []string `json:"commands,omitempty"` @@ -33,7 +34,7 @@ type Socks4Matcher struct { cidrs []netip.Prefix } -func (Socks4Matcher) CaddyModule() caddy.ModuleInfo { +func (*Socks4Matcher) CaddyModule() caddy.ModuleInfo { return caddy.ModuleInfo{ ID: "layer4.matchers.socks4", New: func() caddy.Module { return new(Socks4Matcher) }, diff --git a/modules/l4socks/socks4_matcher_test.go b/modules/l4socks/socks4_matcher_test.go index 6757b70..9adafe1 100644 --- a/modules/l4socks/socks4_matcher_test.go +++ b/modules/l4socks/socks4_matcher_test.go @@ -7,8 +7,9 @@ import ( "testing" "github.com/caddyserver/caddy/v2" - "github.com/mholt/caddy-l4/layer4" "go.uber.org/zap" + + "github.com/mholt/caddy-l4/layer4" ) func assertNoError(t *testing.T, err error) { diff --git a/modules/l4socks/socks5_handler.go b/modules/l4socks/socks5_handler.go index 62c1515..3c9bb9f 100644 --- a/modules/l4socks/socks5_handler.go +++ b/modules/l4socks/socks5_handler.go @@ -7,13 +7,14 @@ import ( "github.com/caddyserver/caddy/v2" "github.com/caddyserver/caddy/v2/caddyconfig/caddyfile" - "github.com/mholt/caddy-l4/layer4" "github.com/things-go/go-socks5" "go.uber.org/zap" + + "github.com/mholt/caddy-l4/layer4" ) func init() { - caddy.RegisterModule(Socks5Handler{}) + caddy.RegisterModule(&Socks5Handler{}) } // Socks5Handler is a connection handler that terminates SOCKSv5 connection. @@ -28,7 +29,7 @@ type Socks5Handler struct { server *socks5.Server } -func (Socks5Handler) CaddyModule() caddy.ModuleInfo { +func (*Socks5Handler) CaddyModule() caddy.ModuleInfo { return caddy.ModuleInfo{ ID: "layer4.handlers.socks5", New: func() caddy.Module { return new(Socks5Handler) }, @@ -40,7 +41,7 @@ func (h *Socks5Handler) Provision(ctx caddy.Context) error { if len(h.Commands) == 0 { rule.EnableConnect = true rule.EnableAssociate = true - // BIND is currently not supported so we dont allow it by default + // BIND is currently not supported, so we don't allow it by default } else { for _, c := range h.Commands { switch strings.ToUpper(c) { diff --git a/modules/l4socks/socks5_handler_test.go b/modules/l4socks/socks5_handler_test.go index a85f02e..601bbf4 100644 --- a/modules/l4socks/socks5_handler_test.go +++ b/modules/l4socks/socks5_handler_test.go @@ -10,8 +10,9 @@ import ( "testing" "github.com/caddyserver/caddy/v2" - "github.com/mholt/caddy-l4/layer4" "go.uber.org/zap" + + "github.com/mholt/caddy-l4/layer4" ) func replay(t *testing.T, handler *Socks5Handler, expectedError string, messages [][]byte) { @@ -62,7 +63,7 @@ func TestSocks5Handler_Defaults(t *testing.T) { // target for the socks handler to connect to (using free random port) listener, err := net.Listen("tcp", "127.0.0.1:0") assertNoError(t, err) - defer listener.Close() + defer func() { _ = listener.Close() }() // transform random listening port into bytes _, portStr, err := net.SplitHostPort(listener.Addr().String()) diff --git a/modules/l4socks/socks5_matcher.go b/modules/l4socks/socks5_matcher.go index 4dc80c7..a96f6ac 100644 --- a/modules/l4socks/socks5_matcher.go +++ b/modules/l4socks/socks5_matcher.go @@ -6,22 +6,23 @@ import ( "github.com/caddyserver/caddy/v2" "github.com/caddyserver/caddy/v2/caddyconfig/caddyfile" + "github.com/mholt/caddy-l4/layer4" ) func init() { - caddy.RegisterModule(Socks5Matcher{}) + caddy.RegisterModule(&Socks5Matcher{}) } // Socks5Matcher matches SOCKSv5 connections according to RFC 1928 (https://www.rfc-editor.org/rfc/rfc1928.html). // Since the SOCKSv5 header is very short it could produce a lot of false positives, // use AuthMethods to exactly specify which METHODS you expect your clients to send. -// By default only the most common methods are matched NO AUTH, GSSAPI & USERNAME/PASSWORD. +// By default, only the most common methods are matched NO AUTH, GSSAPI & USERNAME/PASSWORD. type Socks5Matcher struct { AuthMethods []uint16 `json:"auth_methods,omitempty"` } -func (Socks5Matcher) CaddyModule() caddy.ModuleInfo { +func (*Socks5Matcher) CaddyModule() caddy.ModuleInfo { return caddy.ModuleInfo{ ID: "layer4.matchers.socks5", New: func() caddy.Module { return new(Socks5Matcher) }, diff --git a/modules/l4socks/socks5_matcher_test.go b/modules/l4socks/socks5_matcher_test.go index b1ff95d..f5c5bd2 100644 --- a/modules/l4socks/socks5_matcher_test.go +++ b/modules/l4socks/socks5_matcher_test.go @@ -7,8 +7,9 @@ import ( "testing" "github.com/caddyserver/caddy/v2" - "github.com/mholt/caddy-l4/layer4" "go.uber.org/zap" + + "github.com/mholt/caddy-l4/layer4" ) func TestSocks5Matcher_Match(t *testing.T) { diff --git a/modules/l4ssh/matcher.go b/modules/l4ssh/matcher.go index 7efbbfa..3fb5e17 100644 --- a/modules/l4ssh/matcher.go +++ b/modules/l4ssh/matcher.go @@ -20,18 +20,19 @@ import ( "github.com/caddyserver/caddy/v2" "github.com/caddyserver/caddy/v2/caddyconfig/caddyfile" + "github.com/mholt/caddy-l4/layer4" ) func init() { - caddy.RegisterModule(MatchSSH{}) + caddy.RegisterModule(&MatchSSH{}) } // MatchSSH is able to match SSH connections. type MatchSSH struct{} // CaddyModule returns the Caddy module information. -func (MatchSSH) CaddyModule() caddy.ModuleInfo { +func (*MatchSSH) CaddyModule() caddy.ModuleInfo { return caddy.ModuleInfo{ ID: "layer4.matchers.ssh", New: func() caddy.Module { return new(MatchSSH) }, @@ -39,7 +40,7 @@ func (MatchSSH) CaddyModule() caddy.ModuleInfo { } // Match returns true if the connection looks like SSH. -func (m MatchSSH) Match(cx *layer4.Connection) (bool, error) { +func (m *MatchSSH) Match(cx *layer4.Connection) (bool, error) { p := make([]byte, len(sshPrefix)) n, err := io.ReadFull(cx, p) if err != nil || n < len(sshPrefix) { diff --git a/modules/l4subroute/handler.go b/modules/l4subroute/handler.go index 2c5cb5e..b36c5e2 100644 --- a/modules/l4subroute/handler.go +++ b/modules/l4subroute/handler.go @@ -20,12 +20,13 @@ import ( "github.com/caddyserver/caddy/v2" "github.com/caddyserver/caddy/v2/caddyconfig/caddyfile" - "github.com/mholt/caddy-l4/layer4" "go.uber.org/zap" + + "github.com/mholt/caddy-l4/layer4" ) func init() { - caddy.RegisterModule(Handler{}) + caddy.RegisterModule(&Handler{}) } // Handler implements a handler that compiles and executes routes. @@ -43,7 +44,7 @@ type Handler struct { } // CaddyModule returns the Caddy module information. -func (Handler) CaddyModule() caddy.ModuleInfo { +func (*Handler) CaddyModule() caddy.ModuleInfo { return caddy.ModuleInfo{ ID: "layer4.handlers.subroute", New: func() caddy.Module { return new(Handler) }, diff --git a/modules/l4tee/tee.go b/modules/l4tee/tee.go index 3193630..f0cf766 100644 --- a/modules/l4tee/tee.go +++ b/modules/l4tee/tee.go @@ -21,17 +21,18 @@ import ( "github.com/caddyserver/caddy/v2" "github.com/caddyserver/caddy/v2/caddyconfig/caddyfile" - "github.com/mholt/caddy-l4/layer4" "go.uber.org/zap" + + "github.com/mholt/caddy-l4/layer4" ) func init() { - caddy.RegisterModule(Handler{}) + 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 +// happen in lock-step with all concurrent branches to // avoid buffering: if one of the branches (including the main // handler chain) stops reading from the connection, it will // block all branches. @@ -48,7 +49,7 @@ type Handler struct { } // CaddyModule returns the Caddy module information. -func (Handler) CaddyModule() caddy.ModuleInfo { +func (*Handler) CaddyModule() caddy.ModuleInfo { return caddy.ModuleInfo{ ID: "layer4.handlers.tee", New: func() caddy.Module { return new(Handler) }, @@ -64,7 +65,7 @@ func (t *Handler) Provision(ctx caddy.Context) error { if err != nil { return err } - var handlers layer4.Handlers + handlers := make(layer4.Handlers, 0) for _, mod := range mods.([]interface{}) { handlers = append(handlers, mod.(layer4.NextHandler)) } @@ -74,7 +75,7 @@ func (t *Handler) Provision(ctx caddy.Context) error { } // Handle handles the connection. -func (t Handler) Handle(cx *layer4.Connection, next layer4.Handler) error { +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 @@ -83,7 +84,7 @@ func (t Handler) Handle(cx *layer4.Connection, next layer4.Handler) error { // 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 + // (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 @@ -155,7 +156,7 @@ type nextConn struct { func (nc nextConn) Read(p []byte) (n int, err error) { n, err = nc.Reader.Read(p) if err == io.EOF { - nc.pipe.Close() + _ = nc.pipe.Close() } return } diff --git a/modules/l4throttle/throttle.go b/modules/l4throttle/throttle.go index 712642c..9794c56 100644 --- a/modules/l4throttle/throttle.go +++ b/modules/l4throttle/throttle.go @@ -23,13 +23,14 @@ import ( "github.com/caddyserver/caddy/v2" "github.com/caddyserver/caddy/v2/caddyconfig/caddyfile" - "github.com/mholt/caddy-l4/layer4" "go.uber.org/zap" "golang.org/x/time/rate" + + "github.com/mholt/caddy-l4/layer4" ) func init() { - caddy.RegisterModule(Handler{}) + caddy.RegisterModule(&Handler{}) } // Handler throttles connections using leaky bucket rate limiting. @@ -58,7 +59,7 @@ type Handler struct { } // CaddyModule returns the Caddy module information. -func (Handler) CaddyModule() caddy.ModuleInfo { +func (*Handler) CaddyModule() caddy.ModuleInfo { return caddy.ModuleInfo{ ID: "layer4.handlers.throttle", New: func() caddy.Module { return new(Handler) }, @@ -93,7 +94,7 @@ func (h *Handler) Provision(ctx caddy.Context) error { } // Handle handles the connection. -func (h Handler) Handle(cx *layer4.Connection, next layer4.Handler) error { +func (h *Handler) Handle(cx *layer4.Connection, next layer4.Handler) error { var localLimiter *rate.Limiter if h.ReadBytesPerSecond > 0 || h.ReadBurstSize > 0 { localLimiter = rate.NewLimiter(rate.Limit(h.ReadBytesPerSecond), h.ReadBurstSize) diff --git a/modules/l4tls/alpn_matcher.go b/modules/l4tls/alpn_matcher.go index 0574317..3ae55e5 100644 --- a/modules/l4tls/alpn_matcher.go +++ b/modules/l4tls/alpn_matcher.go @@ -23,24 +23,24 @@ import ( ) func init() { - caddy.RegisterModule(MatchALPN{}) + caddy.RegisterModule(&MatchALPN{}) } type MatchALPN []string // CaddyModule returns the Caddy module information. -func (MatchALPN) CaddyModule() caddy.ModuleInfo { +func (*MatchALPN) CaddyModule() caddy.ModuleInfo { return caddy.ModuleInfo{ ID: "tls.handshake_match.alpn", New: func() caddy.Module { return new(MatchALPN) }, } } -func (m MatchALPN) Match(hello *tls.ClientHelloInfo) bool { +func (m *MatchALPN) Match(hello *tls.ClientHelloInfo) bool { clientProtocols := hello.SupportedProtos - for _, alpn := range m { + for _, alpn := range *m { for _, clientProtocol := range clientProtocols { - if alpn == string(clientProtocol) { + if alpn == clientProtocol { return true } } diff --git a/modules/l4tls/handler.go b/modules/l4tls/handler.go index dd467df..49e8afa 100644 --- a/modules/l4tls/handler.go +++ b/modules/l4tls/handler.go @@ -23,12 +23,13 @@ import ( "github.com/caddyserver/caddy/v2" "github.com/caddyserver/caddy/v2/caddyconfig/caddyfile" "github.com/caddyserver/caddy/v2/modules/caddytls" - "github.com/mholt/caddy-l4/layer4" "go.uber.org/zap" + + "github.com/mholt/caddy-l4/layer4" ) func init() { - caddy.RegisterModule(Handler{}) + caddy.RegisterModule(&Handler{}) } // Handler is a connection handler that terminates TLS. @@ -40,7 +41,7 @@ type Handler struct { } // CaddyModule returns the Caddy module information. -func (Handler) CaddyModule() caddy.ModuleInfo { +func (*Handler) CaddyModule() caddy.ModuleInfo { return caddy.ModuleInfo{ ID: "layer4.handlers.tls", New: func() caddy.Module { return new(Handler) }, diff --git a/modules/l4tls/matcher.go b/modules/l4tls/matcher.go index eaea266..ca12a26 100644 --- a/modules/l4tls/matcher.go +++ b/modules/l4tls/matcher.go @@ -22,12 +22,13 @@ import ( "github.com/caddyserver/caddy/v2" "github.com/caddyserver/caddy/v2/caddyconfig/caddyfile" "github.com/caddyserver/caddy/v2/modules/caddytls" - "github.com/mholt/caddy-l4/layer4" "go.uber.org/zap" + + "github.com/mholt/caddy-l4/layer4" ) func init() { - caddy.RegisterModule(MatchTLS{}) + caddy.RegisterModule(&MatchTLS{}) } // MatchTLS is able to match TLS connections. Its structure @@ -41,7 +42,7 @@ type MatchTLS struct { } // CaddyModule returns the Caddy module information. -func (MatchTLS) CaddyModule() caddy.ModuleInfo { +func (*MatchTLS) CaddyModule() caddy.ModuleInfo { return caddy.ModuleInfo{ ID: "layer4.matchers.tls", New: func() caddy.Module { return new(MatchTLS) }, @@ -54,7 +55,7 @@ func (m *MatchTLS) UnmarshalJSON(b []byte) error { } // MarshalJSON satisfies the json.Marshaler interface. -func (m MatchTLS) MarshalJSON() ([]byte, error) { +func (m *MatchTLS) MarshalJSON() ([]byte, error) { return json.Marshal(m.MatchersRaw) } @@ -72,7 +73,7 @@ func (m *MatchTLS) Provision(ctx caddy.Context) error { } // Match returns true if the connection is a TLS handshake. -func (m MatchTLS) Match(cx *layer4.Connection) (bool, error) { +func (m *MatchTLS) Match(cx *layer4.Connection) (bool, error) { // read the header bytes const recordHeaderLen = 5 hdr := make([]byte, recordHeaderLen) diff --git a/modules/l4xmpp/matcher.go b/modules/l4xmpp/matcher.go index 55ce1b1..e930f24 100644 --- a/modules/l4xmpp/matcher.go +++ b/modules/l4xmpp/matcher.go @@ -20,18 +20,19 @@ import ( "github.com/caddyserver/caddy/v2" "github.com/caddyserver/caddy/v2/caddyconfig/caddyfile" + "github.com/mholt/caddy-l4/layer4" ) func init() { - caddy.RegisterModule(MatchXMPP{}) + caddy.RegisterModule(&MatchXMPP{}) } // MatchXMPP is able to match XMPP connections. type MatchXMPP struct{} // CaddyModule returns the Caddy module information. -func (MatchXMPP) CaddyModule() caddy.ModuleInfo { +func (*MatchXMPP) CaddyModule() caddy.ModuleInfo { return caddy.ModuleInfo{ ID: "layer4.matchers.xmpp", New: func() caddy.Module { return new(MatchXMPP) }, @@ -39,7 +40,7 @@ func (MatchXMPP) CaddyModule() caddy.ModuleInfo { } // Match returns true if the connection looks like XMPP. -func (m MatchXMPP) Match(cx *layer4.Connection) (bool, error) { +func (m *MatchXMPP) Match(cx *layer4.Connection) (bool, error) { p := make([]byte, minXmppLength) n, err := io.ReadFull(cx, p) if err != nil || n < minXmppLength { // needs at least 50 (fix for adium/pidgin)