Skip to content

Commit e4e7614

Browse files
TLS ECH: Update ECH configuration parsing logic to be more robust (#6441)
#6441 (comment) --------- Co-authored-by: 风扇滑翔翼 <Fangliding.fshxy@outlook.com>
1 parent 987290b commit e4e7614

3 files changed

Lines changed: 17 additions & 18 deletions

File tree

transport/internet/tls/config.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -450,7 +450,7 @@ func (c *Config) GetTLSConfig(opts ...Option) *tls.Config {
450450
for _, s := range tls.CipherSuites() {
451451
id[s.Name] = s.ID
452452
}
453-
for _, n := range strings.Split(c.CipherSuites, ":") {
453+
for n := range strings.SplitSeq(c.CipherSuites, ":") {
454454
if id[n] != 0 {
455455
config.CipherSuites = append(config.CipherSuites, id[n])
456456
}

transport/internet/tls/ech.go

Lines changed: 14 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -55,19 +55,16 @@ func ApplyECH(c *Config, config *tls.Config) error {
5555
}
5656
config.EncryptedClientHelloConfigList = ECHConfig
5757
}()
58-
// direct base64 config
58+
// query config from dns
5959
if strings.Contains(c.EchConfigList, "://") {
60-
// query config from dns
61-
parts := strings.Split(c.EchConfigList, "+")
60+
// parse ECH DNS server in format of "example.com+https://1.1.1.1/dns-query"
61+
parts := strings.SplitN(c.EchConfigList, "+", 2)
6262
if len(parts) == 2 {
63-
// parse ECH DNS server in format of "example.com+https://1.1.1.1/dns-query"
6463
nameToQuery = parts[0]
6564
DNSServer = parts[1]
66-
} else if len(parts) == 1 {
65+
} else {
6766
// normal format
6867
DNSServer = parts[0]
69-
} else {
70-
return errors.New("Invalid ECH DNS server format: ", c.EchConfigList)
7168
}
7269
if nameToQuery == "" {
7370
return errors.New("Using DNS for ECH Config needs serverName or use Server format example.com+https://1.1.1.1/dns-query")
@@ -77,6 +74,7 @@ func ApplyECH(c *Config, config *tls.Config) error {
7774
return errors.New("Failed to query ECH DNS record for domain: ", nameToQuery, " at server: ", DNSServer).Base(err)
7875
}
7976
} else {
77+
// direct base64 config
8078
ECHConfig, err = base64.StdEncoding.DecodeString(c.EchConfigList)
8179
if err != nil {
8280
return errors.New("Failed to unmarshal ECHConfigList: ", err)
@@ -157,7 +155,7 @@ func QueryRecord(domain string, server string, sockopt *internet.SocketConfig) (
157155
// If expire is zero value, it means we are in initial state, wait for the query to finish
158156
// otherwise return old value immediately and update in a goroutine
159157
// but if the cache is too old, wait for update
160-
if configRecord.expire == (time.Time{}) || configRecord.expire.Add(time.Hour*4).Before(time.Now()) {
158+
if configRecord.expire.IsZero() || configRecord.expire.Add(time.Hour*4).Before(time.Now()) {
161159
return echConfigCache.Update(domain, server, false, sockopt)
162160
} else {
163161
// If someone already acquired the lock, it means it is updating, do not start another update goroutine
@@ -256,14 +254,17 @@ func dnsQuery(server string, domain string, sockopt *internet.SocketConfig) ([]b
256254
}
257255
dnsResolve = respBody
258256
} else if strings.HasPrefix(server, "udp://") { // for classic udp dns server
259-
udpServerAddr := server[len("udp://"):]
257+
udpServerURL, err := url.Parse(server)
258+
if err != nil {
259+
return nil, 0, errors.New("failed to parse udp dns server ", server, " for ECH: ", err)
260+
}
260261
// default port 53 if not specified
261-
if !strings.Contains(udpServerAddr, ":") {
262-
udpServerAddr = udpServerAddr + ":53"
262+
if udpServerURL.Port() == "" {
263+
udpServerURL.Host = udpServerURL.Host + ":53"
263264
}
264-
dest, err := net.ParseDestination("udp" + ":" + udpServerAddr)
265+
dest, err := net.ParseDestination("udp" + ":" + udpServerURL.Host)
265266
if err != nil {
266-
return nil, 0, errors.New("failed to parse udp dns server ", udpServerAddr, " for ECH: ", err)
267+
return nil, 0, errors.New("failed to parse udp dns server ", udpServerURL.Host, " for ECH: ", err)
267268
}
268269
dnsTimeoutCtx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
269270
defer cancel()

transport/internet/tls/ech_test.go

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,7 @@ func TestECHDial(t *testing.T) {
1919
// test concurrent Dial(to test cache problem)
2020
wg := sync.WaitGroup{}
2121
for range 10 {
22-
wg.Add(1)
23-
go func() {
22+
wg.Go(func() {
2423
TLSConfig := config.GetTLSConfig()
2524
TLSConfig.NextProtos = []string{"http/1.1"}
2625
client := &http.Client{
@@ -36,8 +35,7 @@ func TestECHDial(t *testing.T) {
3635
if !strings.Contains(string(body), "sni=encrypted") {
3736
t.Error("ECH Dial success but SNI is not encrypted")
3837
}
39-
wg.Done()
40-
}()
38+
})
4139
}
4240
wg.Wait()
4341
// check cache

0 commit comments

Comments
 (0)