mirror of
https://github.com/TecharoHQ/anubis.git
synced 2025-08-03 01:38:14 -04:00
feat: more elaborate XFF compute (#350)
* feat: more elaborate XFF compute #328 followup now featuring configuration and defaults that shouldn't break most setups. fixes #344 * refactor: obvious condition eval order optimization * feat: add StripLLU implementation * chore: I'm sorry it's 7 AM * test: add test environment for unix socket serving Signed-off-by: Xe Iaso <me@xeiaso.net> * test(unix-socket-xff): comment out the shell script more Signed-off-by: Xe Iaso <me@xeiaso.net> * fix(internal): fix logic bug in XFF computation, add tests Signed-off-by: Xe Iaso <me@xeiaso.net> * fix(internal): prevent panic in local testing Signed-off-by: Xe Iaso <me@xeiaso.net> * fix(internal): shuffle around return values to flow better Signed-off-by: Xe Iaso <me@xeiaso.net> --------- Signed-off-by: Xe Iaso <me@xeiaso.net> Co-authored-by: Xe Iaso <me@xeiaso.net>
This commit is contained in:
parent
5a4f68d384
commit
a420db8b8a
@ -1,15 +1,29 @@
|
||||
package internal
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/netip"
|
||||
"strings"
|
||||
|
||||
"github.com/TecharoHQ/anubis"
|
||||
"github.com/sebest/xff"
|
||||
)
|
||||
|
||||
// TODO: move into config
|
||||
type XFFComputePreferences struct {
|
||||
StripPrivate bool
|
||||
StripLoopback bool
|
||||
StripCGNAT bool
|
||||
StripLLU bool
|
||||
Flatten bool
|
||||
}
|
||||
|
||||
var CGNat = netip.MustParsePrefix("100.64.0.0/10")
|
||||
|
||||
// UnchangingCache sets the Cache-Control header to cache a response for 1 year if
|
||||
// and only if the application is compiled in "release" mode by Docker.
|
||||
func UnchangingCache(next http.Handler) http.Handler {
|
||||
@ -71,40 +85,106 @@ func XForwardedForUpdate(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
defer next.ServeHTTP(w, r)
|
||||
|
||||
remoteIP, _, err := net.SplitHostPort(r.RemoteAddr)
|
||||
pref := XFFComputePreferences{
|
||||
StripPrivate: true,
|
||||
StripLoopback: true,
|
||||
StripCGNAT: true,
|
||||
Flatten: true,
|
||||
StripLLU: true,
|
||||
}
|
||||
|
||||
if parsedRemoteIP := net.ParseIP(remoteIP); parsedRemoteIP != nil && parsedRemoteIP.IsLoopback() {
|
||||
// anubis is likely deployed behind a local reverse proxy
|
||||
// pass header as-is to not break existing applications
|
||||
remoteAddr := r.RemoteAddr
|
||||
origXFFHeader := r.Header.Get("X-Forwarded-For")
|
||||
|
||||
if remoteAddr == "@" {
|
||||
// remote is a unix socket
|
||||
// do not touch chain
|
||||
return
|
||||
}
|
||||
|
||||
xffHeaderString, err := computeXFFHeader(remoteAddr, origXFFHeader, pref)
|
||||
if err != nil {
|
||||
slog.Warn("The default format of request.RemoteAddr should be IP:Port", "remoteAddr", r.RemoteAddr)
|
||||
slog.Debug("computing X-Forwarded-For header failed", "err", err)
|
||||
return
|
||||
}
|
||||
if xff := r.Header.Get("X-Forwarded-For"); xff != "" {
|
||||
forwardedList := strings.Split(",", xff)
|
||||
forwardedList = append(forwardedList, remoteIP)
|
||||
// this behavior is equivalent to
|
||||
// ingress-nginx "compute-full-forwarded-for"
|
||||
// https://kubernetes.github.io/ingress-nginx/user-guide/nginx-configuration/configmap/#compute-full-forwarded-for
|
||||
//
|
||||
// this would be the correct place to strip and/or flatten this list
|
||||
//
|
||||
// strip - iterate backwards and eliminate configured trusted IPs
|
||||
// flatten - only return the last element to avoid spoofing confusion
|
||||
//
|
||||
// many applications handle this in different ways, but
|
||||
// generally they'd be expected to do these two things on
|
||||
// their own end to find the first non-spoofed IP
|
||||
r.Header.Set("X-Forwarded-For", strings.Join(forwardedList, ","))
|
||||
|
||||
if len(xffHeaderString) == 0 {
|
||||
r.Header.Del("X-Forwarded-For")
|
||||
} else {
|
||||
r.Header.Set("X-Forwarded-For", remoteIP)
|
||||
r.Header.Set("X-Forwarded-For", xffHeaderString)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
var (
|
||||
ErrCantSplitHostParse = errors.New("internal: unable to net.SplitHostParse")
|
||||
ErrCantParseRemoteIP = errors.New("internal: unable to parse remote IP")
|
||||
)
|
||||
|
||||
func computeXFFHeader(remoteAddr string, origXFFHeader string, pref XFFComputePreferences) (string, error) {
|
||||
remoteIP, _, err := net.SplitHostPort(remoteAddr)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("%w: %w", ErrCantSplitHostParse, err)
|
||||
}
|
||||
parsedRemoteIP, err := netip.ParseAddr(remoteIP)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("%w: %w", ErrCantParseRemoteIP, err)
|
||||
}
|
||||
|
||||
origForwardedList := make([]string, 0, 4)
|
||||
if origXFFHeader != "" {
|
||||
origForwardedList = strings.Split(origXFFHeader, ",")
|
||||
}
|
||||
origForwardedList = append(origForwardedList, parsedRemoteIP.String())
|
||||
forwardedList := make([]string, 0, len(origForwardedList))
|
||||
// this behavior is equivalent to
|
||||
// ingress-nginx "compute-full-forwarded-for"
|
||||
// https://kubernetes.github.io/ingress-nginx/user-guide/nginx-configuration/configmap/#compute-full-forwarded-for
|
||||
//
|
||||
// this would be the correct place to strip and/or flatten this list
|
||||
//
|
||||
// strip - iterate backwards and eliminate configured trusted IPs
|
||||
// flatten - only return the last element to avoid spoofing confusion
|
||||
//
|
||||
// many applications handle this in different ways, but
|
||||
// generally they'd be expected to do these two things on
|
||||
// their own end to find the first non-spoofed IP
|
||||
for i := len(origForwardedList) - 1; i >= 0; i-- {
|
||||
segmentIP, err := netip.ParseAddr(origForwardedList[i])
|
||||
if err != nil {
|
||||
// can't assess this element, so the remainder of the chain
|
||||
// can't be trusted. not a fatal error, since anyone can
|
||||
// spoof an XFF header
|
||||
slog.Debug("failed to parse XFF segment", "err", err)
|
||||
break
|
||||
}
|
||||
if pref.StripPrivate && segmentIP.IsPrivate() {
|
||||
continue
|
||||
}
|
||||
if pref.StripLoopback && segmentIP.IsLoopback() {
|
||||
continue
|
||||
}
|
||||
if pref.StripLLU && segmentIP.IsLinkLocalUnicast() {
|
||||
continue
|
||||
}
|
||||
if pref.StripCGNAT && CGNat.Contains(segmentIP) {
|
||||
continue
|
||||
}
|
||||
forwardedList = append([]string{segmentIP.String()}, forwardedList...)
|
||||
}
|
||||
var xffHeaderString string
|
||||
if len(forwardedList) == 0 {
|
||||
xffHeaderString = ""
|
||||
return xffHeaderString, nil
|
||||
}
|
||||
if pref.Flatten {
|
||||
xffHeaderString = forwardedList[len(forwardedList)-1]
|
||||
} else {
|
||||
xffHeaderString = strings.Join(forwardedList, ",")
|
||||
}
|
||||
return xffHeaderString, nil
|
||||
}
|
||||
|
||||
// NoStoreCache sets the Cache-Control header to no-store for the response.
|
||||
func NoStoreCache(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
|
166
internal/xff_test.go
Normal file
166
internal/xff_test.go
Normal file
@ -0,0 +1,166 @@
|
||||
package internal
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestXForwardedForUpdateIgnoreUnix(t *testing.T) {
|
||||
var remoteAddr = ""
|
||||
var xff = ""
|
||||
|
||||
h := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
remoteAddr = r.RemoteAddr
|
||||
xff = r.Header.Get("X-Forwarded-For")
|
||||
w.WriteHeader(http.StatusOK)
|
||||
})
|
||||
|
||||
r := httptest.NewRequest(http.MethodGet, "/", nil)
|
||||
|
||||
r.RemoteAddr = "@"
|
||||
|
||||
w := httptest.NewRecorder()
|
||||
|
||||
XForwardedForUpdate(h).ServeHTTP(w, r)
|
||||
|
||||
if r.RemoteAddr != remoteAddr {
|
||||
t.Errorf("wanted remoteAddr to be %s, got: %s", r.RemoteAddr, remoteAddr)
|
||||
}
|
||||
|
||||
if xff != "" {
|
||||
t.Error("handler added X-Forwarded-For when it should not have")
|
||||
}
|
||||
}
|
||||
|
||||
func TestXForwardedForUpdateAddToChain(t *testing.T) {
|
||||
var xff = ""
|
||||
const expected = "1.1.1.1"
|
||||
|
||||
h := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
xff = r.Header.Get("X-Forwarded-For")
|
||||
w.WriteHeader(http.StatusOK)
|
||||
})
|
||||
|
||||
srv := httptest.NewServer(XForwardedForUpdate(h))
|
||||
|
||||
r, err := http.NewRequest(http.MethodGet, srv.URL, nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
r.Header.Set("X-Forwarded-For", "1.1.1.1,10.20.30.40")
|
||||
|
||||
if _, err := srv.Client().Do(r); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if xff != expected {
|
||||
t.Logf("expected: %s", expected)
|
||||
t.Logf("got: %s", xff)
|
||||
t.Error("X-Forwarded-For header was not what was expected")
|
||||
}
|
||||
}
|
||||
|
||||
func TestComputeXFFHeader(t *testing.T) {
|
||||
for _, tt := range []struct {
|
||||
name string
|
||||
remoteAddr string
|
||||
origXFFHeader string
|
||||
pref XFFComputePreferences
|
||||
result string
|
||||
err error
|
||||
}{
|
||||
{
|
||||
name: "StripPrivate",
|
||||
remoteAddr: "127.0.0.1:80",
|
||||
origXFFHeader: "1.1.1.1,10.0.0.1",
|
||||
pref: XFFComputePreferences{
|
||||
StripPrivate: true,
|
||||
},
|
||||
result: "1.1.1.1,127.0.0.1",
|
||||
},
|
||||
{
|
||||
name: "StripLoopback",
|
||||
remoteAddr: "127.0.0.1:80",
|
||||
origXFFHeader: "1.1.1.1,10.0.0.1,127.0.0.1",
|
||||
pref: XFFComputePreferences{
|
||||
StripLoopback: true,
|
||||
},
|
||||
result: "1.1.1.1,10.0.0.1",
|
||||
},
|
||||
{
|
||||
name: "StripCGNAT",
|
||||
remoteAddr: "100.64.0.1:80",
|
||||
origXFFHeader: "1.1.1.1,10.0.0.1,100.64.0.1",
|
||||
pref: XFFComputePreferences{
|
||||
StripCGNAT: true,
|
||||
},
|
||||
result: "1.1.1.1,10.0.0.1",
|
||||
},
|
||||
{
|
||||
name: "StripLinkLocalUnicastIPv4",
|
||||
remoteAddr: "169.254.0.1:80",
|
||||
origXFFHeader: "1.1.1.1,10.0.0.1,169.254.0.1",
|
||||
pref: XFFComputePreferences{
|
||||
StripLLU: true,
|
||||
},
|
||||
result: "1.1.1.1,10.0.0.1",
|
||||
},
|
||||
{
|
||||
name: "StripLinkLocalUnicastIPv6",
|
||||
remoteAddr: "169.254.0.1:80",
|
||||
origXFFHeader: "1.1.1.1,10.0.0.1,fe80::",
|
||||
pref: XFFComputePreferences{
|
||||
StripLLU: true,
|
||||
},
|
||||
result: "1.1.1.1,10.0.0.1",
|
||||
},
|
||||
{
|
||||
name: "Flatten",
|
||||
remoteAddr: "127.0.0.1:80",
|
||||
origXFFHeader: "1.1.1.1,10.0.0.1,fe80::,100.64.0.1,169.254.0.1",
|
||||
pref: XFFComputePreferences{
|
||||
StripPrivate: true,
|
||||
StripLoopback: true,
|
||||
StripCGNAT: true,
|
||||
StripLLU: true,
|
||||
Flatten: true,
|
||||
},
|
||||
result: "1.1.1.1",
|
||||
},
|
||||
{
|
||||
name: "invalid-ip-port",
|
||||
remoteAddr: "fe80::",
|
||||
err: ErrCantSplitHostParse,
|
||||
},
|
||||
{
|
||||
name: "invalid-remote-ip",
|
||||
remoteAddr: "anubis:80",
|
||||
err: ErrCantParseRemoteIP,
|
||||
},
|
||||
{
|
||||
name: "no-xff-dont-panic",
|
||||
remoteAddr: "127.0.0.1:80",
|
||||
pref: XFFComputePreferences{
|
||||
StripPrivate: true,
|
||||
StripLoopback: true,
|
||||
StripCGNAT: true,
|
||||
StripLLU: true,
|
||||
Flatten: true,
|
||||
},
|
||||
},
|
||||
} {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
result, err := computeXFFHeader(tt.remoteAddr, tt.origXFFHeader, tt.pref)
|
||||
if err != nil && !errors.Is(err, tt.err) {
|
||||
t.Errorf("computeXFFHeader got the wrong error, wanted %v but got: %v", tt.err, err)
|
||||
}
|
||||
|
||||
if result != tt.result {
|
||||
t.Errorf("computeXFFHeader returned the wrong result, wanted %q but got: %q", tt.result, result)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
2
test/.gitignore
vendored
Normal file
2
test/.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
*.sock
|
||||
*.pem
|
124
test/cmd/relayd/main.go
Normal file
124
test/cmd/relayd/main.go
Normal file
@ -0,0 +1,124 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"flag"
|
||||
"log"
|
||||
"log/slog"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/http/httputil"
|
||||
"net/url"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/TecharoHQ/anubis/internal"
|
||||
"github.com/facebookgo/flagenv"
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
var (
|
||||
bind = flag.String("bind", ":3004", "port to listen on")
|
||||
certDir = flag.String("cert-dir", "/xe/pki", "where to read mounted certificates from")
|
||||
certFname = flag.String("cert-fname", "cert.pem", "certificate filename")
|
||||
keyFname = flag.String("key-fname", "key.pem", "key filename")
|
||||
proxyTo = flag.String("proxy-to", "http://localhost:5000", "where to reverse proxy to")
|
||||
slogLevel = flag.String("slog-level", "info", "logging level")
|
||||
)
|
||||
|
||||
func main() {
|
||||
flagenv.Parse()
|
||||
flag.Parse()
|
||||
|
||||
internal.InitSlog(*slogLevel)
|
||||
|
||||
slog.Info("starting",
|
||||
"bind", *bind,
|
||||
"cert-dir", *certDir,
|
||||
"cert-fname", *certFname,
|
||||
"key-fname", *keyFname,
|
||||
"proxy-to", *proxyTo,
|
||||
)
|
||||
|
||||
cert := filepath.Join(*certDir, *certFname)
|
||||
key := filepath.Join(*certDir, *keyFname)
|
||||
|
||||
st, err := os.Stat(cert)
|
||||
|
||||
if err != nil {
|
||||
slog.Error("can't stat cert file", "certFname", cert)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
lastModified := st.ModTime()
|
||||
|
||||
go func(lm time.Time) {
|
||||
t := time.NewTicker(time.Hour)
|
||||
defer t.Stop()
|
||||
|
||||
for range t.C {
|
||||
st, err := os.Stat(cert)
|
||||
if err != nil {
|
||||
slog.Error("can't stat file", "fname", cert, "err", err)
|
||||
continue
|
||||
}
|
||||
|
||||
if st.ModTime().After(lm) {
|
||||
slog.Info("new cert detected", "oldTime", lm.Format(time.RFC3339), "newTime", st.ModTime().Format(time.RFC3339))
|
||||
os.Exit(0)
|
||||
}
|
||||
}
|
||||
}(lastModified)
|
||||
|
||||
u, err := url.Parse(*proxyTo)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
h := httputil.NewSingleHostReverseProxy(u)
|
||||
|
||||
if u.Scheme == "unix" {
|
||||
slog.Info("using unix socket proxy")
|
||||
|
||||
h = &httputil.ReverseProxy{
|
||||
Director: func(r *http.Request) {
|
||||
r.URL.Scheme = "http"
|
||||
r.URL.Host = r.Host
|
||||
|
||||
r.Header.Set("X-Forwarded-Proto", "https")
|
||||
r.Header.Set("X-Forwarded-Scheme", "https")
|
||||
r.Header.Set("X-Request-Id", uuid.NewString())
|
||||
r.Header.Set("X-Scheme", "https")
|
||||
|
||||
remoteHost, remotePort, err := net.SplitHostPort(r.Host)
|
||||
if err == nil {
|
||||
r.Header.Set("X-Forwarded-Host", remoteHost)
|
||||
r.Header.Set("X-Forwarded-Port", remotePort)
|
||||
} else {
|
||||
r.Header.Set("X-Forwarded-Host", r.Host)
|
||||
}
|
||||
|
||||
host, _, err := net.SplitHostPort(r.RemoteAddr)
|
||||
if err == nil {
|
||||
r.Header.Set("X-Real-Ip", host)
|
||||
}
|
||||
},
|
||||
Transport: &http.Transport{
|
||||
DialContext: func(_ context.Context, _, _ string) (net.Conn, error) {
|
||||
return net.Dial("unix", strings.TrimPrefix(*proxyTo, "unix://"))
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
log.Fatal(
|
||||
http.ListenAndServeTLS(
|
||||
*bind,
|
||||
cert,
|
||||
key,
|
||||
h,
|
||||
),
|
||||
)
|
||||
}
|
75
test/cmd/unixhttpd/main.go
Normal file
75
test/cmd/unixhttpd/main.go
Normal file
@ -0,0 +1,75 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"log"
|
||||
"log/slog"
|
||||
"net"
|
||||
"net/http"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/TecharoHQ/anubis/internal"
|
||||
"github.com/facebookgo/flagenv"
|
||||
)
|
||||
|
||||
var (
|
||||
dir = flag.String("dir", ".", "directory to serve")
|
||||
slogLevel = flag.String("slog-level", "info", "logging level")
|
||||
socketPath = flag.String("socket-path", "./unixhttpd.sock", "unix socket path to use")
|
||||
)
|
||||
|
||||
func init() {
|
||||
flag.Usage = func() {
|
||||
fmt.Fprintf(os.Stderr, "Usage of %s:\n", filepath.Base(os.Args[0]))
|
||||
fmt.Fprintf(os.Stderr, " %s [--dir=.] [--socket-path=./unixhttpd.sock]\n\n", filepath.Base(os.Args[0]))
|
||||
flag.PrintDefaults()
|
||||
os.Exit(2)
|
||||
}
|
||||
}
|
||||
|
||||
func main() {
|
||||
flagenv.Parse()
|
||||
flag.Parse()
|
||||
|
||||
internal.InitSlog(*slogLevel)
|
||||
|
||||
if *dir == "" && *socketPath == "" {
|
||||
flag.Usage()
|
||||
}
|
||||
|
||||
slog.Info("starting up", "dir", *dir, "socketPath", *socketPath)
|
||||
|
||||
os.Remove(*socketPath)
|
||||
|
||||
mux := http.NewServeMux()
|
||||
|
||||
mux.HandleFunc("/reqmeta", func(w http.ResponseWriter, r *http.Request) {
|
||||
contains := strings.Contains(r.Header.Get("Accept"), "text/html")
|
||||
|
||||
if contains {
|
||||
w.Header().Add("Content-Type", "text/html")
|
||||
fmt.Fprint(w, "<pre id=\"main\"><code>")
|
||||
}
|
||||
|
||||
r.Write(w)
|
||||
|
||||
if contains {
|
||||
fmt.Fprintln(w, "</pre></code>")
|
||||
}
|
||||
})
|
||||
|
||||
mux.Handle("/", http.FileServer(http.Dir(*dir)))
|
||||
|
||||
server := http.Server{
|
||||
Handler: mux,
|
||||
}
|
||||
|
||||
unixListener, err := net.Listen("unix", *socketPath)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
log.Fatal(server.Serve(unixListener))
|
||||
}
|
41
test/go.mod
Normal file
41
test/go.mod
Normal file
@ -0,0 +1,41 @@
|
||||
module github.com/TecharoHQ/anubis/test
|
||||
|
||||
go 1.24.2
|
||||
|
||||
replace github.com/TecharoHQ/anubis => ..
|
||||
|
||||
require (
|
||||
github.com/facebookgo/flagenv v0.0.0-20160425205200-fcd59fca7456
|
||||
github.com/google/uuid v1.6.0
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/TecharoHQ/anubis v1.16.0 // indirect
|
||||
github.com/a-h/templ v0.3.857 // indirect
|
||||
github.com/beorn7/perks v1.0.1 // indirect
|
||||
github.com/cespare/xxhash/v2 v2.3.0 // indirect
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
|
||||
github.com/facebookgo/ensure v0.0.0-20200202191622-63f1cf65ac4c // indirect
|
||||
github.com/facebookgo/stack v0.0.0-20160209184415-751773369052 // indirect
|
||||
github.com/facebookgo/subset v0.0.0-20200203212716-c811ad88dec4 // indirect
|
||||
github.com/golang-jwt/jwt/v5 v5.2.2 // indirect
|
||||
github.com/jsha/minica v1.1.0 // indirect
|
||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
|
||||
github.com/prometheus/client_golang v1.22.0 // indirect
|
||||
github.com/prometheus/client_model v0.6.1 // indirect
|
||||
github.com/prometheus/common v0.62.0 // indirect
|
||||
github.com/prometheus/procfs v0.15.1 // indirect
|
||||
github.com/sebest/xff v0.0.0-20210106013422-671bd2870b3a // indirect
|
||||
github.com/yl2chen/cidranger v1.0.2 // indirect
|
||||
golang.org/x/net v0.39.0 // indirect
|
||||
golang.org/x/sys v0.32.0 // indirect
|
||||
google.golang.org/protobuf v1.36.5 // indirect
|
||||
k8s.io/apimachinery v0.32.3 // indirect
|
||||
sigs.k8s.io/json v0.0.0-20241010143419-9aa6b5e7a4b3 // indirect
|
||||
sigs.k8s.io/yaml v1.4.0 // indirect
|
||||
)
|
||||
|
||||
tool (
|
||||
github.com/TecharoHQ/anubis/cmd/anubis
|
||||
github.com/jsha/minica
|
||||
)
|
55
test/go.sum
Normal file
55
test/go.sum
Normal file
@ -0,0 +1,55 @@
|
||||
github.com/a-h/templ v0.3.857 h1:6EqcJuGZW4OL+2iZ3MD+NnIcG7nGkaQeF2Zq5kf9ZGg=
|
||||
github.com/a-h/templ v0.3.857/go.mod h1:qhrhAkRFubE7khxLZHsBFHfX+gWwVNKbzKeF9GlPV4M=
|
||||
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
|
||||
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
|
||||
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
|
||||
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/facebookgo/ensure v0.0.0-20200202191622-63f1cf65ac4c h1:8ISkoahWXwZR41ois5lSJBSVw4D0OV19Ht/JSTzvSv0=
|
||||
github.com/facebookgo/ensure v0.0.0-20200202191622-63f1cf65ac4c/go.mod h1:Yg+htXGokKKdzcwhuNDwVvN+uBxDGXJ7G/VN1d8fa64=
|
||||
github.com/facebookgo/flagenv v0.0.0-20160425205200-fcd59fca7456 h1:CkmB2l68uhvRlwOTPrwnuitSxi/S3Cg4L5QYOcL9MBc=
|
||||
github.com/facebookgo/flagenv v0.0.0-20160425205200-fcd59fca7456/go.mod h1:zFhibDvPDWmtk4dAQ05sRobtyoffEHygEt3wSNuAzz8=
|
||||
github.com/facebookgo/stack v0.0.0-20160209184415-751773369052 h1:JWuenKqqX8nojtoVVWjGfOF9635RETekkoH6Cc9SX0A=
|
||||
github.com/facebookgo/stack v0.0.0-20160209184415-751773369052/go.mod h1:UbMTZqLaRiH3MsBH8va0n7s1pQYcu3uTb8G4tygF4Zg=
|
||||
github.com/facebookgo/subset v0.0.0-20200203212716-c811ad88dec4 h1:7HZCaLC5+BZpmbhCOZJ293Lz68O7PYrF2EzeiFMwCLk=
|
||||
github.com/facebookgo/subset v0.0.0-20200203212716-c811ad88dec4/go.mod h1:5tD+neXqOorC30/tWg0LCSkrqj/AR6gu8yY8/fpw1q0=
|
||||
github.com/golang-jwt/jwt/v5 v5.2.2 h1:Rl4B7itRWVtYIHFrSNd7vhTiz9UpLdi6gZhZ3wEeDy8=
|
||||
github.com/golang-jwt/jwt/v5 v5.2.2/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk=
|
||||
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
||||
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/jsha/minica v1.1.0 h1:O2ZbzAN75w4RTB+5+HfjIEvY5nxRqDlwj3ZlLVG5JD8=
|
||||
github.com/jsha/minica v1.1.0/go.mod h1:dxC3wNmD+gU1ewXo/R8jB2ihB6wNpyXrG8aUk5Iuf/k=
|
||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
|
||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/prometheus/client_golang v1.22.0 h1:rb93p9lokFEsctTys46VnV1kLCDpVZ0a/Y92Vm0Zc6Q=
|
||||
github.com/prometheus/client_golang v1.22.0/go.mod h1:R7ljNsLXhuQXYZYtw6GAE9AZg8Y7vEW5scdCXrWRXC0=
|
||||
github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E=
|
||||
github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY=
|
||||
github.com/prometheus/common v0.62.0 h1:xasJaQlnWAeyHdUBeGjXmutelfJHWMRr+Fg4QszZ2Io=
|
||||
github.com/prometheus/common v0.62.0/go.mod h1:vyBcEuLSvWos9B1+CyL7JZ2up+uFzXhkqml0W5zIY1I=
|
||||
github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc=
|
||||
github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk=
|
||||
github.com/sebest/xff v0.0.0-20210106013422-671bd2870b3a h1:iLcLb5Fwwz7g/DLK89F+uQBDeAhHhwdzB5fSlVdhGcM=
|
||||
github.com/sebest/xff v0.0.0-20210106013422-671bd2870b3a/go.mod h1:wozgYq9WEBQBaIJe4YZ0qTSFAMxmcwBhQH0fO0R34Z0=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||
github.com/yl2chen/cidranger v1.0.2 h1:lbOWZVCG1tCRX4u24kuM1Tb4nHqWkDxwLdoS+SevawU=
|
||||
github.com/yl2chen/cidranger v1.0.2/go.mod h1:9U1yz7WPYDwf0vpNWFaeRh0bjwz5RVgRy/9UEQfHl0g=
|
||||
golang.org/x/net v0.39.0 h1:ZCu7HMWDxpXpaiKdhzIfaltL9Lp31x/3fCP11bc6/fY=
|
||||
golang.org/x/net v0.39.0/go.mod h1:X7NRbYVEA+ewNkCNyJ513WmMdQ3BineSwVtN2zD/d+E=
|
||||
golang.org/x/sys v0.32.0 h1:s77OFDvIQeibCmezSnk/q6iAfkdiQaJi4VzroCFrN20=
|
||||
golang.org/x/sys v0.32.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
|
||||
google.golang.org/protobuf v1.36.5 h1:tPhr+woSbjfYvY6/GPufUoYizxw1cF/yFoxJ2fmpwlM=
|
||||
google.golang.org/protobuf v1.36.5/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
k8s.io/apimachinery v0.32.3 h1:JmDuDarhDmA/Li7j3aPrwhpNBA94Nvk5zLeOge9HH1U=
|
||||
k8s.io/apimachinery v0.32.3/go.mod h1:GpHVgxoKlTxClKcteaeuF1Ul/lDVb74KpZcxcmLDElE=
|
||||
sigs.k8s.io/json v0.0.0-20241010143419-9aa6b5e7a4b3 h1:/Rv+M11QRah1itp8VhT6HoVx1Ray9eB4DBr+K+/sCJ8=
|
||||
sigs.k8s.io/json v0.0.0-20241010143419-9aa6b5e7a4b3/go.mod h1:18nIHnGi6636UCz6m8i4DhaJ65T6EruyzmoQqI2BVDo=
|
||||
sigs.k8s.io/yaml v1.4.0 h1:Mk1wCc2gy/F0THH0TAp1QYyJNzRm2KCLy3o5ASXVI5E=
|
||||
sigs.k8s.io/yaml v1.4.0/go.mod h1:Ejl7/uTz7PSA4eKMyQCUTnhZYNmLIl+5c2lQPGR2BPY=
|
54
test/unix-socket-xff/start.sh
Executable file
54
test/unix-socket-xff/start.sh
Executable file
@ -0,0 +1,54 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
# Remove lingering .sock files, relayd and unixhttpd will do that too but
|
||||
# measure twice, cut once.
|
||||
rm *.sock ||:
|
||||
|
||||
# If the transient local TLS certificate doesn't exist, mint a new one
|
||||
if [ ! -f ../pki/relayd.local.cetacean.club/cert.pem ]; then
|
||||
# Subshell to contain the directory change
|
||||
(
|
||||
cd ../pki \
|
||||
&& mkdir -p relayd.local.cetacean.club \
|
||||
&& \
|
||||
# Try using https://github.com/FiloSottile/mkcert for better DevEx,
|
||||
# but fall back to using https://github.com/jsha/minica in case
|
||||
# you don't have that installed.
|
||||
(
|
||||
mkcert \
|
||||
--cert-file ./relayd.local.cetacean.club/cert.pem \
|
||||
--key-file ./relayd.local.cetacean.club/key.pem relayd.local.cetacean.club \
|
||||
|| go tool minica -domains relayd.local.cetacean.club
|
||||
)
|
||||
)
|
||||
fi
|
||||
|
||||
# Build static assets
|
||||
(cd ../.. && npm ci && npm run assets)
|
||||
|
||||
# Spawn three jobs:
|
||||
|
||||
# HTTP daemon that listens over a unix socket (implicitly ./unixhttpd.sock)
|
||||
go run ../cmd/unixhttpd &
|
||||
|
||||
# A copy of Anubis, specifically for the current Git checkout
|
||||
go tool anubis \
|
||||
--bind=./anubis.sock \
|
||||
--bind-network=unix \
|
||||
--target=unix://$(pwd)/unixhttpd.sock &
|
||||
|
||||
# A simple TLS terminator that forwards to Anubis, which will forward to
|
||||
# unixhttpd
|
||||
go run ../cmd/relayd \
|
||||
--proxy-to=unix://./anubis.sock \
|
||||
--cert-dir=../pki/relayd.local.cetacean.club &
|
||||
|
||||
# When you press control c, kill all the child processes to clean things up
|
||||
trap 'echo signal received!; kill $(jobs -p); wait' SIGINT SIGTERM
|
||||
|
||||
echo "open https://relayd.local.cetacean.club:3004/reqmeta"
|
||||
|
||||
# Wait for all child processes to exit
|
||||
wait
|
Loading…
x
Reference in New Issue
Block a user