edge: forgery matrix across unix, tcp and multi proxies, with Connection nomination and unknown suffixes (Astra plan R1-18)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
1 file changed,
+66
−0
internal/edge/geoipheaders_test.go+66 −0
diff --git a/internal/edge/geoipheaders_test.go b/internal/edge/geoipheaders_test.go| index bdf5d59a6..7833229ba 100644 |
| --- a/internal/edge/geoipheaders_test.go |
| +++ b/internal/edge/geoipheaders_test.go |
| @@ -9,6 +9,8 @@ import ( |
| "net/http" |
| "net/http/httptest" |
| "net/http/httputil" |
| + "path/filepath" |
| + "strings" |
| "sync/atomic" |
| "testing" |
| "time" |
| @@ -352,3 +354,67 @@ func TestUpgradeRequestCarriesGeo(t *testing.T) { |
| t.Fatalf("upgrade = %d, backend saw country %q, want 101 and GB", resp.StatusCode, resp.Header.Get("X-Seen-Country")) |
| } |
| } |
| + |
| +// Plan review R1-18 / spec §8.4: forgery, Connection nomination and an |
| +// unknown X-Carlos-Geo-* suffix, through every proxy type a local route can |
| +// use (unix, tcp, multi). Backhaul is covered by |
| +// TestBackhaulDeliversTheSendersAnswer and the tunnel by Task 10's e2e. |
| +func TestForgeryMatrixAcrossLocalProxyTypes(t *testing.T) { |
| + echo := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { |
| + got := map[string]string{} |
| + for k := range r.Header { |
| + if strings.HasPrefix(strings.ToLower(k), "x-carlos-geo-") || strings.EqualFold(k, geoip.HeaderHop) { |
| + got[k] = r.Header.Get(k) |
| + } |
| + } |
| + w.Header().Set("Content-Type", "application/json") |
| + json.NewEncoder(w).Encode(got) |
| + }) |
| + tcp := httptest.NewServer(echo) |
| + t.Cleanup(tcp.Close) |
| + routes := map[string]registry.Route{ |
| + "tcp": {Host: "tcp.test", Kind: "service", Addr: tcp.Listener.Addr().String(), Status: "ready"}, |
| + "multi": {Host: "multi.test", Kind: "service", Addrs: tcp.Listener.Addr().String(), Health: healthJSON(t, frozenHealth()), Status: "ready"}, |
| + } |
| + sock := filepath.Join(t.TempDir(), "g.sock") |
| + if ln, err := net.Listen("unix", sock); err == nil { |
| + us := &httptest.Server{Listener: ln, Config: &http.Server{Handler: echo}} |
| + us.Start() |
| + t.Cleanup(us.Close) |
| + routes["unix"] = registry.Route{Host: "unix.test", Kind: "instance", Socket: sock, Status: "ready"} |
| + } else { |
| + t.Logf("unix listener unavailable here (%v); unix leg skipped", err) |
| + } |
| + reg := openReg(t) |
| + for _, rt := range routes { |
| + if err := reg.Upsert(rt); err != nil { |
| + t.Fatal(err) |
| + } |
| + } |
| + e, err := New(reg, nil) |
| + if err != nil { |
| + t.Fatal(err) |
| + } |
| + t.Cleanup(e.probers.Stop) |
| + spyGeo(e, "GB") |
| + for name, rt := range routes { |
| + r := geoReq(rt.Host, "81.2.69.142") |
| + r.Header.Set(geoip.HeaderCountry, "KP") |
| + r.Header.Set("X-Carlos-Geo-City", "Atlantis") |
| + r.Header.Set(geoip.HeaderHop, "hit;src=forged") |
| + r.Header.Set("Connection", "X-Carlos-Geo-Country, X-Carlos-Geo-Source") |
| + code, h := serveGeo(t, e, r) |
| + if code != 200 { |
| + t.Errorf("%s: status %d", name, code) |
| + continue |
| + } |
| + if h[geoip.HeaderCountry] != "GB" || h[geoip.HeaderSource] != "TestDB-GB" { |
| + t.Errorf("%s: app saw %v, want the edge's GB answer", name, h) |
| + } |
| + for _, bad := range []string{"X-Carlos-Geo-City", geoip.HeaderHop} { |
| + if _, ok := h[bad]; ok { |
| + t.Errorf("%s: %s reached the app", name, bad) |
| + } |
| + } |
| + } |
| +} |