mirror of
https://github.com/TecharoHQ/anubis.git
synced 2025-08-03 17:59:24 -04:00

* 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>
125 lines
2.7 KiB
Go
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,
|
|
),
|
|
)
|
|
}
|