-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathaliyun_live_test.go
More file actions
106 lines (95 loc) · 4.23 KB
/
Copy pathaliyun_live_test.go
File metadata and controls
106 lines (95 loc) · 4.23 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
package domainfront
import (
"context"
"io"
"net/http"
"os"
"strings"
"testing"
"time"
utls "github.com/refraction-networking/utls"
"github.com/stretchr/testify/require"
)
// TestAliyunProviderLive exercises aliyun-provider.yaml against the real Aliyun
// CDN. It proves the security-critical path end to end: the config's GlobalSign
// root verifies the live Alibaba *.tbcdn.cn chain, the generated SNI is accepted
// by the edge, and the edge routes a *cross-organization* Host (Bilibili's
// s1.hdslb.com) over a TLS session that presents Alibaba's certificate — i.e.
// domain fronting works through this library's own dial + verify code.
//
// Skipped by default (it talks to the public internet). Run with:
//
// DOMAINFRONT_LIVE=1 go test -run TestAliyunProviderLive -v
func TestAliyunProviderLive(t *testing.T) {
if os.Getenv("DOMAINFRONT_LIVE") == "" {
t.Skip("live network test; set DOMAINFRONT_LIVE=1 to run")
}
raw, err := os.ReadFile("aliyun-provider.yaml")
require.NoError(t, err)
cfg, err := ParseConfigYAML(raw)
require.NoError(t, err)
// The GlobalSign root parses into a usable pool.
pool, err := cfg.CertPool()
require.NoError(t, err)
// Expand with a country code so FrontingSNIs drives the wire SNI
// (config.go only emits SNI when countryCode != "").
require.Contains(t, cfg.Providers, "aliyun", "aliyun-provider.yaml must define the 'aliyun' provider")
p := ExpandedProvider(cfg.Providers["aliyun"], "cn")
require.NotEmpty(t, p.Masquerades)
const crossOrgHost = "s1.hdslb.com" // Bilibili — unrelated to Alibaba
// Phase 1: prove the security-critical path through the library's own
// dialFront — the config's GlobalSign root verifies the live Alibaba
// *.tbcdn.cn chain under the production Chrome_131 ClientHello, for every
// masquerade, using the SNI that FrontingSNIs generated.
// For each masquerade: dial with the production Chrome_131 ClientHello
// (which Aliyun answers with HTTP/2 over ALPN), then drive the library's
// real doRequest — proving the h2 transport path fronts a cross-org Host
// (Bilibili) over a TLS session bearing Alibaba's certificate.
var dialed int
var frontedOK, frontedOverH2 bool
for _, m := range p.Masquerades {
require.NotEmpty(t, m.SNI, "expanded masquerade should carry an SNI")
f := newFront(m, "aliyun")
ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second)
res := dialFront(ctx, f, pool, utls.HelloChrome_131, NetDialer{})
if res.err != nil {
cancel()
t.Logf("dial %s (SNI %s) failed: %v", m.IpAddress, m.SNI, res.err)
continue
}
dialed++
proto := negotiatedProtocol(res.conn)
t.Logf("TLS+verify OK: ip=%s sni=%s alpn=%s (cert chained to config's GlobalSign root)", m.IpAddress, m.SNI, proto)
req, err := http.NewRequestWithContext(ctx, http.MethodGet, "https://"+crossOrgHost+"/", nil)
require.NoError(t, err)
resp, rerr := (&roundTripper{}).doRequest(req, res.conn, crossOrgHost, nil)
if rerr != nil {
if cerr := res.conn.Close(); cerr != nil {
t.Logf("close conn for %s failed: %v", m.IpAddress, cerr)
}
cancel()
t.Logf("fronted GET via %s failed: %v", m.IpAddress, rerr)
continue
}
body, readErr := io.ReadAll(io.LimitReader(resp.Body, 256))
if cerr := resp.Body.Close(); cerr != nil { // h2Body close tears down the conn
t.Logf("close response body for %s failed: %v", m.IpAddress, cerr)
}
cancel()
t.Logf("fronted %s via %s (SNI %s, %s): HTTP %d, proto=HTTP/%d, body=%q (readErr=%v)",
crossOrgHost, m.IpAddress, m.SNI, proto, resp.StatusCode, resp.ProtoMajor, strings.TrimSpace(string(body)), readErr)
// Require a clean body read so a truncated/failed response can't be
// miscounted as a successful front.
if resp.StatusCode == http.StatusOK && readErr == nil {
frontedOK = true
// Only count it as proving the h2 path when ALPN actually
// negotiated h2 and the response came back as HTTP/2.
if proto == "h2" && resp.ProtoMajor == 2 {
frontedOverH2 = true
}
}
}
require.NotZero(t, dialed, "no Aliyun edge IP completed TLS + GlobalSign verification")
require.True(t, frontedOK, "no edge served the cross-org Host (%s) — fronting did not route", crossOrgHost)
require.True(t, frontedOverH2, "no edge fronted %s over HTTP/2 — the h2 path was not exercised", crossOrgHost)
}