A host under the site domain that no site or custom host claims used to fall through to the relay, so signed requests could verify against a URL the relay does not own. Such hosts are now not found.
- commit
- 249961ba1458a279852cbf968c8ab9148fce11bc
- parent
- df69f8bd82b528fcc7f762b99ecf39f06fc0f2ea
- author
- Dami <dami.etoile@gmail.com>
| M | internal/ | 26 | ++++++++++++++++++++++ |
| A | internal/ | 35 | ++++++++++++++++++++++++++++++ |
@@ -32,6 +32,13 @@ func (t *Tenant) ServeHTTP(w http.ResponseWriter, r *http.Request) {
3232 t.healthHTTP(w, r)3333 return3434 }35+ if t.unclaimedSiteHost(r.Host) {36+ // A host under the site domain that no site claims must not fall37+ // through to the relay: signed requests would otherwise verify38+ // against a URL the relay does not own.39+ http.NotFound(w, r)40+ return41+ }3542 if strings.EqualFold(r.Header.Get("Upgrade"), "websocket") {3643 t.router.HandleHTTP(w, r)3744 return@@ -553,3 +560,22 @@ func containsString(values []string, wanted string) bool {
553560 }554561 return false555562 }563+564+// unclaimedSiteHost reports whether host is a subdomain of the site domain565+// that neither a hosted site nor a custom host claims.566+func (t *Tenant) unclaimedSiteHost(host string) bool {567+ host = strings.ToLower(strings.Split(host, ":")[0])568+ domain := strings.ToLower(t.siteDomain())569+ if domain == "" || host == domain || !strings.HasSuffix(host, "."+domain) {570+ return false571+ }572+ if t.sites != nil && t.sites.MatchesHost(host) {573+ return false574+ }575+ for _, custom := range t.Policy().CustomHosts {576+ if strings.EqualFold(custom.Host, host) {577+ return false578+ }579+ }580+ return true581+}@@ -0,0 +1,35 @@
1+package daemon2+3+import (4+ "context"5+ "net/http"6+ "net/http/httptest"7+ "strings"8+ "testing"9+)10+11+func TestUnclaimedSubdomainsOfTheSiteDomainAreNotFound(t *testing.T) {12+ ctx := context.Background()13+ app, err := New(ctx, Config{DataDir: t.TempDir(), DefaultTenant: "main", PublicURL: "https://relay.test"})14+ if err != nil {15+ t.Fatal(err)16+ }17+ defer app.Close(ctx)18+ meta, err := app.Create(ctx, CreateOptions{Name: "main", Owner: strings.Repeat("a", 64), Template: "default"})19+ if err != nil {20+ t.Fatal(err)21+ }22+ tenant, err := app.tenant(ctx, meta, "https://relay.test")23+ if err != nil {24+ t.Fatal(err)25+ }26+ for host, want := range map[string]int{"relay.test": http.StatusOK, "bauhaus.relay.test": http.StatusNotFound, "tiny.tailnet.example": http.StatusOK, "127.0.0.1:7447": http.StatusOK} {27+ req := httptest.NewRequest(http.MethodGet, "http://"+host+"/", nil)28+ req.Host = host29+ res := httptest.NewRecorder()30+ tenant.ServeHTTP(res, req)31+ if res.Code != want {32+ t.Errorf("host %s: status %d, want %d", host, res.Code, want)33+ }34+ }35+}