Skip to content

Commit aa3ff81

Browse files
committed
update (rkn пидоры)
1 parent 67d76a0 commit aa3ff81

10 files changed

Lines changed: 268 additions & 156 deletions

File tree

internal/config/config.go

Lines changed: 32 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -23,36 +23,36 @@ type Config struct {
2323
QuicCertPinSHA256 string `json:"quicCertPinSHA256,omitempty"`
2424
QuicCaCert string `json:"quicCaCert,omitempty"`
2525

26-
QuicTraceLog bool `json:"quicTraceLog,omitempty"`
27-
DualTransport *bool `json:"dualTransport,omitempty"`
28-
Routes string `json:"routes,omitempty"`
29-
Exclude string `json:"exclude,omitempty"`
30-
TunCIDR6 string `json:"tunCIDR6,omitempty"`
31-
Protection *ProtectionOptions `json:"protection,omitempty"`
26+
QuicTraceLog bool `json:"quicTraceLog,omitempty"`
27+
DualTransport *bool `json:"dualTransport,omitempty"`
28+
Routes string `json:"routes,omitempty"`
29+
Exclude string `json:"exclude,omitempty"`
30+
TunCIDR6 string `json:"tunCIDR6,omitempty"`
31+
Protection *ProtectionOptions `json:"protection,omitempty"`
3232
}
3333

3434
type ProtectionOptions struct {
35-
Obfuscation string `json:"obfuscation,omitempty"`
36-
PreambleProfile string `json:"preambleProfile,omitempty"`
37-
PreambleRotate bool `json:"preambleRotate,omitempty"`
38-
ProbeObfsProfileID byte `json:"-"`
39-
JunkCount int `json:"junkCount,omitempty"`
40-
JunkMin int `json:"junkMin,omitempty"`
41-
JunkMax int `json:"junkMax,omitempty"`
42-
PadS1 int `json:"padS1,omitempty"`
43-
PadS2 int `json:"padS2,omitempty"`
44-
PadS3 int `json:"padS3,omitempty"`
45-
PadS4 int `json:"padS4,omitempty"`
46-
PreCheck bool `json:"preCheck,omitempty"`
47-
MagicSplit string `json:"magicSplit,omitempty"`
48-
JunkStyle string `json:"junkStyle,omitempty"`
49-
FlushPolicy string `json:"flushPolicy,omitempty"`
50-
ObfSeed string `json:"obfSeed,omitempty"`
51-
CapsVersion int `json:"capsVersion,omitempty"`
52-
TransportMask int `json:"transportMask,omitempty"`
53-
FeatureBits int `json:"featureBits,omitempty"`
54-
ClientNonce string `json:"clientNonce,omitempty"`
55-
ClientTsSec int64 `json:"clientTsSec,omitempty"`
35+
Obfuscation string `json:"obfuscation,omitempty"`
36+
PreambleProfile string `json:"preambleProfile,omitempty"`
37+
PreambleRotate bool `json:"preambleRotate,omitempty"`
38+
ProbeObfsProfileID byte `json:"-"`
39+
JunkCount int `json:"junkCount,omitempty"`
40+
JunkMin int `json:"junkMin,omitempty"`
41+
JunkMax int `json:"junkMax,omitempty"`
42+
PadS1 int `json:"padS1,omitempty"`
43+
PadS2 int `json:"padS2,omitempty"`
44+
PadS3 int `json:"padS3,omitempty"`
45+
PadS4 int `json:"padS4,omitempty"`
46+
PreCheck bool `json:"preCheck,omitempty"`
47+
MagicSplit string `json:"magicSplit,omitempty"`
48+
JunkStyle string `json:"junkStyle,omitempty"`
49+
FlushPolicy string `json:"flushPolicy,omitempty"`
50+
ObfSeed string `json:"obfSeed,omitempty"`
51+
CapsVersion int `json:"capsVersion,omitempty"`
52+
TransportMask int `json:"transportMask,omitempty"`
53+
FeatureBits int `json:"featureBits,omitempty"`
54+
ClientNonce string `json:"clientNonce,omitempty"`
55+
ClientTsSec int64 `json:"clientTsSec,omitempty"`
5656
}
5757

5858
func Dir() (string, error) {
@@ -287,6 +287,11 @@ func MergeProbeObfsIntoProtection(p *ProtectionOptions, caps *protocol.ServerHel
287287
}
288288
if caps != nil {
289289
base.ProbeObfsProfileID = caps.ObfsProfileID
290+
poly := (caps.FeatureBits & protocol.FeaturePolyHandshake) != 0
291+
if poly && caps.ObfsProfileID > 0 && strings.TrimSpace(strings.ToLower(base.PreambleProfile)) == "" {
292+
base.PreambleProfile = protocol.PreambleRotate
293+
base.PreambleRotate = true
294+
}
290295
}
291296
return &base
292297
}

internal/config/config_test.go

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -155,13 +155,28 @@ func TestLoadProtectionNotExist(t *testing.T) {
155155

156156
func TestMergeProbeObfsIntoProtection(t *testing.T) {
157157
p := &ProtectionOptions{JunkCount: 3}
158-
caps := &protocol.ServerHelloCaps{ObfsProfileID: 9}
158+
caps := &protocol.ServerHelloCaps{
159+
ObfsProfileID: 9,
160+
FeatureBits: protocol.FeaturePolyHandshake,
161+
}
159162
out := MergeProbeObfsIntoProtection(p, caps)
160-
if out.JunkCount != 3 || out.ProbeObfsProfileID != 9 {
163+
if out.JunkCount != 3 || out.ProbeObfsProfileID != 9 || out.PreambleProfile != protocol.PreambleRotate || !out.PreambleRotate {
161164
t.Fatalf("got %+v", out)
162165
}
163166
out2 := MergeProbeObfsIntoProtection(nil, caps)
164-
if out2.ProbeObfsProfileID != 9 {
167+
if out2.ProbeObfsProfileID != 9 || out2.PreambleProfile != protocol.PreambleRotate || !out2.PreambleRotate {
165168
t.Fatalf("got %+v", out2)
166169
}
167170
}
171+
172+
func TestMergeProbeObfsDoesNotForceRotateWithoutFeature(t *testing.T) {
173+
p := &ProtectionOptions{}
174+
caps := &protocol.ServerHelloCaps{ObfsProfileID: 4}
175+
out := MergeProbeObfsIntoProtection(p, caps)
176+
if out.ProbeObfsProfileID != 4 {
177+
t.Fatalf("got %+v", out)
178+
}
179+
if out.PreambleProfile != "" || out.PreambleRotate {
180+
t.Fatalf("rotate must stay off without poly feature: %+v", out)
181+
}
182+
}

internal/protocol/protocol.go

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -39,21 +39,22 @@ const (
3939
addrV6 = 6
4040
maxPad = 32
4141

42-
CapsVersion = 1
43-
TransportTCP = 1
44-
TransportQUIC = 1 << 1
45-
FeatureIPv6 = 1
42+
CapsVersion = 1
43+
TransportTCP = 1
44+
TransportQUIC = 1 << 1
45+
FeatureIPv6 = 1
46+
FeaturePolyHandshake = 1 << 1
4647
)
4748

4849
type ServerHelloCaps struct {
49-
Version byte
50-
LegacyIPv6 bool
51-
TransportMask byte
52-
FeatureBits uint16
53-
QuicPort uint16
54-
TCPPortHint uint16
55-
ObfsProfileID byte
56-
Nonce []byte
50+
Version byte
51+
LegacyIPv6 bool
52+
TransportMask byte
53+
FeatureBits uint16
54+
QuicPort uint16
55+
TCPPortHint uint16
56+
ObfsProfileID byte
57+
Nonce []byte
5758
QuicLeafPinSHA256 []byte
5859
}
5960

internal/tunnel/quic_client.go

Lines changed: 73 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,11 @@ import (
1515
"syscall"
1616
"time"
1717

18-
quic "github.com/quic-go/quic-go"
1918
"dev.c0redev.volter/internal/clientlog"
2019
"dev.c0redev.volter/internal/config"
2120
"dev.c0redev.volter/internal/protocol"
2221
"dev.c0redev.volter/internal/sockprotect"
22+
quic "github.com/quic-go/quic-go"
2323
)
2424

2525
type QUICConn = quic.Conn
@@ -147,20 +147,6 @@ func dialQUICConn(addr, serverName string, skipVerify bool, certPinSHA256 string
147147
return nil, nil, fmt.Errorf("quic: bad udp port %q", portStr)
148148
}
149149

150-
resolveCtx, cancelRes := context.WithTimeout(context.Background(), 12*time.Second)
151-
ips, err := LookupHostIPsPreferV4(resolveCtx, dialHost)
152-
cancelRes()
153-
if err != nil {
154-
return nil, nil, fmt.Errorf("quic: resolve %q: %w", dialHost, err)
155-
}
156-
if quicTraceOn() {
157-
ipStrs := make([]string, 0, len(ips))
158-
for _, ip := range ips {
159-
ipStrs = append(ipStrs, ip.String())
160-
}
161-
clientlog.Trace("quic dial addr=%q sni=%q ips=%v", addr, sniHost, ipStrs)
162-
}
163-
164150
qconf := &quic.Config{
165151
EnableDatagrams: false,
166152
MaxIdleTimeout: 15 * time.Minute,
@@ -177,65 +163,88 @@ func dialQUICConn(addr, serverName string, skipVerify bool, certPinSHA256 string
177163
}
178164

179165
var lastErr error
180-
for _, ip := range ips {
181-
dialCtx, cancelDial := context.WithTimeout(context.Background(), 50*time.Second)
182-
if v4 := ip.To4(); v4 != nil {
183-
remote := &net.UDPAddr{IP: v4, Port: port}
166+
backoff := 250 * time.Millisecond
167+
for round := 0; round < 4; round++ {
168+
resolveCtx, cancelRes := context.WithTimeout(context.Background(), 12*time.Second)
169+
ips, err := LookupHostIPsPreferV4(resolveCtx, dialHost)
170+
cancelRes()
171+
if err != nil {
172+
lastErr = fmt.Errorf("quic: resolve %q: %w", dialHost, err)
173+
} else {
184174
if quicTraceOn() {
185-
clientlog.Trace("quic dial try Dial udp4 -> %s", remote.String())
175+
ipStrs := make([]string, 0, len(ips))
176+
for _, ip := range ips {
177+
ipStrs = append(ipStrs, ip.String())
178+
}
179+
clientlog.Trace("quic dial round=%d addr=%q sni=%q ips=%v", round+1, addr, sniHost, ipStrs)
186180
}
187-
pc, lerr := listenUDPForQUIC("udp4", &net.UDPAddr{IP: net.IPv4zero, Port: 0})
188-
if lerr != nil {
189-
cancelDial()
181+
for _, ip := range ips {
182+
dialCtx, cancelDial := context.WithTimeout(context.Background(), 50*time.Second)
183+
if v4 := ip.To4(); v4 != nil {
184+
remote := &net.UDPAddr{IP: v4, Port: port}
185+
if quicTraceOn() {
186+
clientlog.Trace("quic dial try Dial udp4 -> %s", remote.String())
187+
}
188+
pc, lerr := listenUDPForQUIC("udp4", &net.UDPAddr{IP: net.IPv4zero, Port: 0})
189+
if lerr != nil {
190+
cancelDial()
191+
if quicTraceOn() {
192+
clientlog.Trace("quic ListenUDP udp4: %v", lerr)
193+
}
194+
lastErr = lerr
195+
continue
196+
}
197+
conn, derr := quic.Dial(dialCtx, pc, remote, tlsCfg, qconf)
198+
cancelDial()
199+
if derr == nil {
200+
if quicTraceOn() {
201+
clientlog.Trace("quic dial ok local=%s remote=%s", conn.LocalAddr(), conn.RemoteAddr())
202+
}
203+
closePC := func() { _ = pc.Close() }
204+
return conn, closePC, nil
205+
}
206+
_ = pc.Close()
207+
if quicTraceOn() {
208+
clientlog.Trace("quic dial fail Dial %s: %v", remote.String(), derr)
209+
}
210+
lastErr = derr
211+
continue
212+
}
213+
pc, lerr := listenUDPForQUIC("udp6", &net.UDPAddr{IP: net.IPv6zero, Port: 0})
214+
if lerr != nil {
215+
cancelDial()
216+
if quicTraceOn() {
217+
clientlog.Trace("quic dial ListenUDP udp6: %v", lerr)
218+
}
219+
lastErr = lerr
220+
continue
221+
}
222+
udpAddr := &net.UDPAddr{IP: ip, Port: port}
190223
if quicTraceOn() {
191-
clientlog.Trace("quic ListenUDP udp4: %v", lerr)
224+
clientlog.Trace("quic dial try Dial udp6 local=%s -> %s", pc.LocalAddr(), udpAddr)
192225
}
193-
lastErr = lerr
194-
continue
195-
}
196-
conn, derr := quic.Dial(dialCtx, pc, remote, tlsCfg, qconf)
197-
cancelDial()
198-
if derr == nil {
226+
conn, derr := quic.Dial(dialCtx, pc, udpAddr, tlsCfg, qconf)
227+
cancelDial()
228+
if derr == nil {
229+
if quicTraceOn() {
230+
clientlog.Trace("quic dial ok local=%s remote=%s", conn.LocalAddr(), conn.RemoteAddr())
231+
}
232+
closePC := func() { _ = pc.Close() }
233+
return conn, closePC, nil
234+
}
235+
_ = pc.Close()
199236
if quicTraceOn() {
200-
clientlog.Trace("quic dial ok local=%s remote=%s", conn.LocalAddr(), conn.RemoteAddr())
237+
clientlog.Trace("quic dial fail Dial %s: %v", udpAddr, derr)
201238
}
202-
closePC := func() { _ = pc.Close() }
203-
return conn, closePC, nil
204-
}
205-
_ = pc.Close()
206-
if quicTraceOn() {
207-
clientlog.Trace("quic dial fail Dial %s: %v", remote.String(), derr)
208-
}
209-
lastErr = derr
210-
continue
211-
}
212-
pc, lerr := listenUDPForQUIC("udp6", &net.UDPAddr{IP: net.IPv6zero, Port: 0})
213-
if lerr != nil {
214-
cancelDial()
215-
if quicTraceOn() {
216-
clientlog.Trace("quic dial ListenUDP udp6: %v", lerr)
239+
lastErr = derr
217240
}
218-
lastErr = lerr
219-
continue
220-
}
221-
udpAddr := &net.UDPAddr{IP: ip, Port: port}
222-
if quicTraceOn() {
223-
clientlog.Trace("quic dial try Dial udp6 local=%s -> %s", pc.LocalAddr(), udpAddr)
224241
}
225-
conn, derr := quic.Dial(dialCtx, pc, udpAddr, tlsCfg, qconf)
226-
cancelDial()
227-
if derr == nil {
228-
if quicTraceOn() {
229-
clientlog.Trace("quic dial ok local=%s remote=%s", conn.LocalAddr(), conn.RemoteAddr())
242+
if round < 3 {
243+
time.Sleep(backoff)
244+
if backoff < 2*time.Second {
245+
backoff *= 2
230246
}
231-
closePC := func() { _ = pc.Close() }
232-
return conn, closePC, nil
233-
}
234-
_ = pc.Close()
235-
if quicTraceOn() {
236-
clientlog.Trace("quic dial fail Dial %s: %v", udpAddr, derr)
237247
}
238-
lastErr = derr
239248
}
240249
return nil, nil, wrapQUICDialTLS(lastErr, addr, skipVerify, hasPin, rootCAs != nil)
241250
}

0 commit comments

Comments
 (0)