aboutsummaryrefslogtreecommitdiff
path: root/test/cmd
diff options
context:
space:
mode:
authorAurelia <git@acuteaura.net>2025-04-25 13:59:55 +0200
committerGitHub <noreply@github.com>2025-04-25 11:59:55 +0000
commita420db8b8a3597b56bcc6dc7d1fc5f5d7d932448 (patch)
treea8962aafc94ffd192a23a912c01b73f574dcce6b /test/cmd
parent5a4f68d384895b09c45d0c6ebb09b069603c363b (diff)
downloadanubis-a420db8b8a3597b56bcc6dc7d1fc5f5d7d932448.tar.xz
anubis-a420db8b8a3597b56bcc6dc7d1fc5f5d7d932448.zip
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>
Diffstat (limited to 'test/cmd')
-rw-r--r--test/cmd/relayd/main.go124
-rw-r--r--test/cmd/unixhttpd/main.go75
2 files changed, 199 insertions, 0 deletions
diff --git a/test/cmd/relayd/main.go b/test/cmd/relayd/main.go
new file mode 100644
index 0000000..26700d7
--- /dev/null
+++ b/test/cmd/relayd/main.go
@@ -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,
+ ),
+ )
+}
diff --git a/test/cmd/unixhttpd/main.go b/test/cmd/unixhttpd/main.go
new file mode 100644
index 0000000..a57c202
--- /dev/null
+++ b/test/cmd/unixhttpd/main.go
@@ -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))
+}