Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
185 changes: 116 additions & 69 deletions cmd/anubis/main.go

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,7 @@ require (
github.com/natefinch/atomic v1.0.1 // indirect
github.com/opencontainers/go-digest v1.0.0 // indirect
github.com/opencontainers/image-spec v1.1.1 // indirect
github.com/pires/go-proxyproto v0.8.1 // indirect
github.com/pjbgf/sha1cd v0.4.0 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -328,6 +328,8 @@ github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8
github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
github.com/opencontainers/image-spec v1.1.1 h1:y0fUlFfIZhPF1W537XOLg0/fcx6zcHCJwooC2xJA040=
github.com/opencontainers/image-spec v1.1.1/go.mod h1:qpqAh3Dmcf36wStyyWU+kCeDgrGnAve2nCC8+7h8Q0M=
github.com/pires/go-proxyproto v0.8.1 h1:9KEixbdJfhrbtjpz/ZwCdWDD2Xem0NZ38qMYaASJgp0=
github.com/pires/go-proxyproto v0.8.1/go.mod h1:ZKAAyp3cgy5Y5Mo4n9AlScrkCZwUy0g3Jf+slqQVcuU=
github.com/pjbgf/sha1cd v0.4.0 h1:NXzbL1RvjTUi6kgYZCX3fPwwl27Q1LJndxtUDVfJGRY=
github.com/pjbgf/sha1cd v0.4.0/go.mod h1:zQWigSxVmsHEZow5qaLtPYxpcKMMQpa09ixqBxuCS6A=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
Expand Down
58 changes: 58 additions & 0 deletions internal/headers.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,64 @@
})
}

// ProxyProtocol sets the X-Real-Ip header to the request's real IP set from Proxy Protocol Headers also it sets the request context with proxyProtocolInfo to send Proxy Protocol Heaaders

Check failure on line 65 in internal/headers.go

View workflow job for this annotation

GitHub Actions / Check Spelling

`Heaaders` is not a recognized word. (unrecognized-spelling)
func ProxyProtocol(useProxyProtocol bool, sendProxyProtocol string, next http.Handler) http.Handler {
if !useProxyProtocol {
slog.Debug("skipping middleware, useProxyProtocol is empty")
return next
}

return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if !ProxyProtocolUsed(r.Context()) {
next.ServeHTTP(w, r)
return
}

hdr, ok := ProxyProtocolHeader(r.Context())

Check failure on line 78 in internal/headers.go

View workflow job for this annotation

GitHub Actions / Check Spelling

`hdr` is not a recognized word. (unrecognized-spelling)
if !ok || hdr.SourceAddr == nil {

Check warning on line 79 in internal/headers.go

View workflow job for this annotation

GitHub Actions / Check Spelling

`hdr` is not a recognized word. (unrecognized-spelling)
next.ServeHTTP(w, r)
return
}

host, _, err := net.SplitHostPort(hdr.SourceAddr.String())

Check warning on line 84 in internal/headers.go

View workflow job for this annotation

GitHub Actions / Check Spelling

`hdr` is not a recognized word. (unrecognized-spelling)
if err == nil {
r.Header.Set("X-Real-Ip", host)
if addr, err := netip.ParseAddrPort(host); err == nil {
r = r.WithContext(
context.WithValue(r.Context(), proxyProtocolInfoKey{}, ProxyProtocolInfo{
AddrPort: addr,
}),
)

}
}
// stolen from caddyserver :)

Check failure on line 96 in internal/headers.go

View workflow job for this annotation

GitHub Actions / Check Spelling

`caddyserver` is not a recognized word. (unrecognized-spelling)
if sendProxyProtocol != "" {
// this will not work correctly because when we dont get the infromation via the proxy protocol headers but instead trough x-real-ip we never have a port for the address and always will set it to 0

Check failure on line 98 in internal/headers.go

View workflow job for this annotation

GitHub Actions / Check Spelling

`infromation` is not a recognized word. (unrecognized-spelling)
address := r.Header.Get("X-Real-Ip")
addrPort, err := netip.ParseAddrPort(address)
//this check would only make sense if there would be a port
if err != nil {
// OK; probably didn't have a port
addr, err := netip.ParseAddr(address)
if err != nil {
// Doesn't seem like a valid ip address at all
} else {
// Ok, only the port was missing
addrPort = netip.AddrPortFrom(addr, 0)
}
}
r = r.WithContext(
context.WithValue(r.Context(), proxyProtocolInfoKey{}, ProxyProtocolInfo{
AddrPort: addrPort,
}),
)
}

next.ServeHTTP(w, r)
})
}

// RemoteXRealIP sets the X-Real-Ip header to the request's real IP if
// the setting is enabled by the user.
func RemoteXRealIP(useRemoteAddress bool, bindNetwork string, next http.Handler) http.Handler {
Expand Down
108 changes: 108 additions & 0 deletions internal/proxyprotocol.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
package internal

Check failure on line 1 in internal/proxyprotocol.go

View workflow job for this annotation

GitHub Actions / Check Spelling

`proxyprotocol` is not a recognized word. (check-file-path)

import (
"context"
"fmt"
"net"
"net/netip"

"github.com/pires/go-proxyproto"

Check warning on line 9 in internal/proxyprotocol.go

View workflow job for this annotation

GitHub Actions / Check Spelling

`pires` is not a recognized word. (unrecognized-spelling)
)

type proxyProtocolUsedKey struct{}

func ProxyProtocolUsed(ctx context.Context) bool {
v, ok := ctx.Value(proxyProtocolUsedKey{}).(bool)
return ok && v
}

type proxyProtocolHeaderKey struct{}

func ProxyProtocolHeader(ctx context.Context) (*proxyproto.Header, bool) {
h, ok := ctx.Value(proxyProtocolHeaderKey{}).(*proxyproto.Header)
return h, ok
}

type proxyProtocolInfoKey struct{}

func proxyProtocolInfo(ctx context.Context) (ProxyProtocolInfo, bool) {
h, ok := ctx.Value(proxyProtocolInfoKey{}).(ProxyProtocolInfo)
return h, ok
}

type ProxyProtocolInfo struct {
AddrPort netip.AddrPort
}

func ProxyProtoConnContext() func(ctx context.Context, c net.Conn) context.Context {
return func(ctx context.Context, c net.Conn) context.Context {
ppConn, ok := c.(*proxyproto.Conn)
if !ok {
return ctx
}

hdr := ppConn.ProxyHeader()

Check warning on line 44 in internal/proxyprotocol.go

View workflow job for this annotation

GitHub Actions / Check Spelling

`hdr` is not a recognized word. (unrecognized-spelling)
if hdr == nil {

Check warning on line 45 in internal/proxyprotocol.go

View workflow job for this annotation

GitHub Actions / Check Spelling

`hdr` is not a recognized word. (unrecognized-spelling)
return context.WithValue(ctx, proxyProtocolUsedKey{}, false)
}

ctx = context.WithValue(ctx, proxyProtocolUsedKey{}, true)
ctx = context.WithValue(ctx, proxyProtocolHeaderKey{}, hdr)

return ctx
}
}

func SendProxyProtocolDialer(dialer *net.Dialer, proxyProtocolVersion string) func(ctx context.Context, network, addr string) (net.Conn, error) {
return func(ctx context.Context, network, addr string) (net.Conn, error) {
conn, err := dialer.DialContext(ctx, network, addr)
if err != nil {
return nil, fmt.Errorf("dial error: %w", err)
}
// stolen from caddyserver :)

Check warning on line 62 in internal/proxyprotocol.go

View workflow job for this annotation

GitHub Actions / Check Spelling

`caddyserver` is not a recognized word. (unrecognized-spelling)
proxyProtocolInfo, ok := proxyProtocolInfo(ctx)
if !ok {
return nil, fmt.Errorf("failed to get proxy protocol info from context")
}
var proxyv byte
switch proxyProtocolVersion {
case "v1":
proxyv = 1
case "v2":
proxyv = 2
default:
return nil, fmt.Errorf("unexpected proxy protocol version")
}

// The src and dst have to be of the same address family. As we don't know the original
// dst address (it's kind of impossible to know) and this address is generally of very
// little interest, we just set it to all zeros.
var destAddr net.Addr
switch {
case proxyProtocolInfo.AddrPort.Addr().Is4():
destAddr = &net.TCPAddr{
IP: net.IPv4zero,
}
case proxyProtocolInfo.AddrPort.Addr().Is6():
destAddr = &net.TCPAddr{
IP: net.IPv6zero,
}
default:
return nil, fmt.Errorf("unexpected remote addr type in proxy protocol info")
}
sourceAddr := &net.TCPAddr{
IP: proxyProtocolInfo.AddrPort.Addr().AsSlice(),
Port: int(proxyProtocolInfo.AddrPort.Port()),
Zone: proxyProtocolInfo.AddrPort.Addr().Zone(),
}
header := proxyproto.HeaderProxyFromAddrs(proxyv, sourceAddr, destAddr)

_, err = header.WriteTo(conn)

if err != nil {
return nil, err
}

return conn, nil
}
}
52 changes: 27 additions & 25 deletions lib/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,31 +28,33 @@ import (
)

type Options struct {
Next http.Handler
Policy *policy.ParsedConfig
Target string
TargetHost string
TargetSNI string
TargetInsecureSkipVerify bool
CookieDynamicDomain bool
CookieDomain string
CookieExpiration time.Duration
CookiePartitioned bool
BasePrefix string
WebmasterEmail string
RedirectDomains []string
ED25519PrivateKey ed25519.PrivateKey
HS512Secret []byte
StripBasePrefix bool
OpenGraph config.OpenGraph
ServeRobotsTXT bool
CookieSecure bool
CookieSameSite http.SameSite
Logger *slog.Logger
LogLevel string
PublicUrl string
JWTRestrictionHeader string
DifficultyInJWT bool
Next http.Handler
Policy *policy.ParsedConfig
Target string
TargetHost string
TargetSNI string
TargetInsecureSkipVerify bool
CookieDynamicDomain bool
CookieDomain string
CookieExpiration time.Duration
CookiePartitioned bool
BasePrefix string
WebmasterEmail string
RedirectDomains []string
ED25519PrivateKey ed25519.PrivateKey
HS512Secret []byte
StripBasePrefix bool
OpenGraph config.OpenGraph
ServeRobotsTXT bool
CookieSecure bool
CookieSameSite http.SameSite
Logger *slog.Logger
LogLevel string
PublicUrl string
JWTRestrictionHeader string
DifficultyInJWT bool
ProxyProtocolTimeout time.Duration
ProxyProtocolAllowedCIDRs []string
}

func LoadPoliciesOrDefault(ctx context.Context, fname string, defaultDifficulty int, logLevel string) (*policy.ParsedConfig, error) {
Expand Down
Loading