derp/derphttp,ipn/localapi,net/captivedetection: add cache resistance to captive portal detection
Some checks are pending
checklocks / checklocks (push) Waiting to run
CodeQL / Analyze (go) (push) Waiting to run
Dockerfile build / deploy (push) Waiting to run
CI / race-root-integration (1/4) (push) Waiting to run
CI / race-root-integration (2/4) (push) Waiting to run
CI / race-root-integration (3/4) (push) Waiting to run
CI / race-root-integration (4/4) (push) Waiting to run
CI / test (-coverprofile=/tmp/coverage.out, amd64) (push) Waiting to run
CI / test (-race, amd64, 1/3) (push) Waiting to run
CI / test (-race, amd64, 2/3) (push) Waiting to run
CI / test (-race, amd64, 3/3) (push) Waiting to run
CI / test (386) (push) Waiting to run
CI / windows (push) Waiting to run
CI / privileged (push) Waiting to run
CI / vm (push) Waiting to run
CI / race-build (push) Waiting to run
CI / cross (386, linux) (push) Waiting to run
CI / cross (amd64, darwin) (push) Waiting to run
CI / cross (amd64, freebsd) (push) Waiting to run
CI / cross (amd64, openbsd) (push) Waiting to run
CI / cross (amd64, windows) (push) Waiting to run
CI / cross (arm, 5, linux) (push) Waiting to run
CI / cross (arm, 7, linux) (push) Waiting to run
CI / cross (arm64, darwin) (push) Waiting to run
CI / cross (arm64, linux) (push) Waiting to run
CI / cross (arm64, windows) (push) Waiting to run
CI / cross (loong64, linux) (push) Waiting to run
CI / ios (push) Waiting to run
CI / crossmin (amd64, illumos) (push) Waiting to run
CI / crossmin (amd64, plan9) (push) Waiting to run
CI / crossmin (amd64, solaris) (push) Waiting to run
CI / crossmin (ppc64, aix) (push) Waiting to run
CI / android (push) Waiting to run
CI / wasm (push) Waiting to run
CI / tailscale_go (push) Waiting to run
CI / fuzz (push) Waiting to run
CI / depaware (push) Waiting to run
CI / go_generate (push) Waiting to run
CI / go_mod_tidy (push) Waiting to run
CI / licenses (push) Waiting to run
CI / staticcheck (386, windows) (push) Waiting to run
CI / staticcheck (amd64, darwin) (push) Waiting to run
CI / staticcheck (amd64, linux) (push) Waiting to run
CI / staticcheck (amd64, windows) (push) Waiting to run
CI / notify_slack (push) Blocked by required conditions
CI / check_mergeability (push) Blocked by required conditions
Some checks are pending
checklocks / checklocks (push) Waiting to run
CodeQL / Analyze (go) (push) Waiting to run
Dockerfile build / deploy (push) Waiting to run
CI / race-root-integration (1/4) (push) Waiting to run
CI / race-root-integration (2/4) (push) Waiting to run
CI / race-root-integration (3/4) (push) Waiting to run
CI / race-root-integration (4/4) (push) Waiting to run
CI / test (-coverprofile=/tmp/coverage.out, amd64) (push) Waiting to run
CI / test (-race, amd64, 1/3) (push) Waiting to run
CI / test (-race, amd64, 2/3) (push) Waiting to run
CI / test (-race, amd64, 3/3) (push) Waiting to run
CI / test (386) (push) Waiting to run
CI / windows (push) Waiting to run
CI / privileged (push) Waiting to run
CI / vm (push) Waiting to run
CI / race-build (push) Waiting to run
CI / cross (386, linux) (push) Waiting to run
CI / cross (amd64, darwin) (push) Waiting to run
CI / cross (amd64, freebsd) (push) Waiting to run
CI / cross (amd64, openbsd) (push) Waiting to run
CI / cross (amd64, windows) (push) Waiting to run
CI / cross (arm, 5, linux) (push) Waiting to run
CI / cross (arm, 7, linux) (push) Waiting to run
CI / cross (arm64, darwin) (push) Waiting to run
CI / cross (arm64, linux) (push) Waiting to run
CI / cross (arm64, windows) (push) Waiting to run
CI / cross (loong64, linux) (push) Waiting to run
CI / ios (push) Waiting to run
CI / crossmin (amd64, illumos) (push) Waiting to run
CI / crossmin (amd64, plan9) (push) Waiting to run
CI / crossmin (amd64, solaris) (push) Waiting to run
CI / crossmin (ppc64, aix) (push) Waiting to run
CI / android (push) Waiting to run
CI / wasm (push) Waiting to run
CI / tailscale_go (push) Waiting to run
CI / fuzz (push) Waiting to run
CI / depaware (push) Waiting to run
CI / go_generate (push) Waiting to run
CI / go_mod_tidy (push) Waiting to run
CI / licenses (push) Waiting to run
CI / staticcheck (386, windows) (push) Waiting to run
CI / staticcheck (amd64, darwin) (push) Waiting to run
CI / staticcheck (amd64, linux) (push) Waiting to run
CI / staticcheck (amd64, windows) (push) Waiting to run
CI / notify_slack (push) Blocked by required conditions
CI / check_mergeability (push) Blocked by required conditions
Observed on some airlines (British Airways, WestJet), Squid is configured to cache and transform these results, which is disruptive. The server and client should both actively request that this is not done by setting Cache-Control headers. Send a timestamp parameter to further work against caches that do not respect the cache-control headers. Updates #14856 Signed-off-by: James Tucker <james@tailscale.com>
This commit is contained in:

committed by
James Tucker

parent
17ca2b7721
commit
10fe10ea10
@ -5,14 +5,21 @@ package captivedetection
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"net/url"
|
||||
"runtime"
|
||||
"strconv"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"tailscale.com/derp/derphttp"
|
||||
"tailscale.com/net/netmon"
|
||||
"tailscale.com/syncs"
|
||||
"tailscale.com/tstest/nettest"
|
||||
"tailscale.com/util/must"
|
||||
)
|
||||
|
||||
func TestAvailableEndpointsAlwaysAtLeastTwo(t *testing.T) {
|
||||
@ -81,3 +88,67 @@ func TestEndpointsAreUpAndReturnExpectedResponse(t *testing.T) {
|
||||
t.Errorf("no good endpoints found")
|
||||
}
|
||||
}
|
||||
|
||||
func TestCaptivePortalRequest(t *testing.T) {
|
||||
d := NewDetector(t.Logf)
|
||||
now := time.Now()
|
||||
d.clock = func() time.Time { return now }
|
||||
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
s := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method != "GET" {
|
||||
t.Errorf("expected GET, got %q", r.Method)
|
||||
}
|
||||
if r.URL.Path != "/generate_204" {
|
||||
t.Errorf("expected /generate_204, got %q", r.URL.Path)
|
||||
}
|
||||
q := r.URL.Query()
|
||||
if got, want := q.Get("t"), strconv.Itoa(int(now.Unix())); got != want {
|
||||
t.Errorf("timestamp param; got %v, want %v", got, want)
|
||||
}
|
||||
w.Header().Set("X-Tailscale-Response", "response "+r.Header.Get("X-Tailscale-Challenge"))
|
||||
|
||||
w.WriteHeader(http.StatusNoContent)
|
||||
}))
|
||||
defer s.Close()
|
||||
|
||||
e := Endpoint{
|
||||
URL: must.Get(url.Parse(s.URL + "/generate_204")),
|
||||
StatusCode: 204,
|
||||
ExpectedContent: "",
|
||||
SupportsTailscaleChallenge: true,
|
||||
}
|
||||
|
||||
found, err := d.verifyCaptivePortalEndpoint(ctx, e, 0)
|
||||
if err != nil {
|
||||
t.Fatalf("verifyCaptivePortalEndpoint = %v, %v", found, err)
|
||||
}
|
||||
if found {
|
||||
t.Errorf("verifyCaptivePortalEndpoint = %v, want false", found)
|
||||
}
|
||||
}
|
||||
|
||||
func TestAgainstDERPHandler(t *testing.T) {
|
||||
d := NewDetector(t.Logf)
|
||||
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
s := httptest.NewServer(http.HandlerFunc(derphttp.ServeNoContent))
|
||||
defer s.Close()
|
||||
e := Endpoint{
|
||||
URL: must.Get(url.Parse(s.URL + "/generate_204")),
|
||||
StatusCode: 204,
|
||||
ExpectedContent: "",
|
||||
SupportsTailscaleChallenge: true,
|
||||
}
|
||||
found, err := d.verifyCaptivePortalEndpoint(ctx, e, 0)
|
||||
if err != nil {
|
||||
t.Fatalf("verifyCaptivePortalEndpoint = %v, %v", found, err)
|
||||
}
|
||||
if found {
|
||||
t.Errorf("verifyCaptivePortalEndpoint = %v, want false", found)
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user