anubis/test/cmd/relayd/main.go
Aurelia a420db8b8a
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>
2025-04-25 11:59:55 +00:00

125 lines
2.7 KiB
Go

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,
),
)
}