Skip to content

Commit 2050dd8

Browse files
committed
Fix TLS handshake
The fpgo proxy was sending a `Connection: close` header in its CONNECT response and then immediately closing the TCP connection after returning `200 OK`. This prevented the TLS handshake from completing, causing "tls handshake eof" errors. Signed-off-by: Joeky <joeky5888@gmail.com>
1 parent d8a10fc commit 2050dd8

1 file changed

Lines changed: 31 additions & 24 deletions

File tree

main.go

Lines changed: 31 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,9 @@ type LogLevel uint8
2020

2121
const (
2222
DefaultMaxConcurrent = 512
23-
DefaultAddr = ":13002"
24-
DefaultDNS = ""
25-
DefaultTimeout = 60 * time.Second
23+
DefaultAddr = ":13002"
24+
DefaultDNS = ""
25+
DefaultTimeout = 60 * time.Second
2626
DefaultLogLevel = 1
2727

2828
LogLevelDebug LogLevel = 0
@@ -34,20 +34,20 @@ const (
3434
var (
3535
version = "dev"
3636

37-
addrF = flag.String("a", DefaultAddr, `Listen address.`)
37+
addrF = flag.String("a", DefaultAddr, `Listen address.`)
3838
maxConcurrentF = flag.Int("c", DefaultMaxConcurrent, "Max concurrency for fasthttp server")
3939
dnsresolversF = flag.String("n", DefaultDNS, `DNS nameserves, E.g. "8.8.8.8" or "1.1.1.1,8.8.8.8". Default is empty (OS default)`)
4040
timeoutF = flag.Duration("t", DefaultTimeout, `Connection timeout. Examples: 1m or 10s`)
4141
logLevelF = flag.Int("l", DefaultLogLevel, `Log level. Examples: 0 (debug), 1 (info), 2 (warn), 3 (error).`)
42-
usageF = flag.Bool("h", false, "Show usage")
43-
verF = flag.Bool("v", false, "Show version")
42+
usageF = flag.Bool("h", false, "Show usage")
43+
verF = flag.Bool("v", false, "Show version")
4444

45-
addr string
45+
addr string
4646
maxConcurrent int
47-
dns []string
47+
dns []string
4848
timeout time.Duration
4949
logLevel LogLevel
50-
ver string
50+
ver string
5151

5252
defaultResolver = &net.Resolver{
5353
PreferGo: true,
@@ -59,14 +59,14 @@ var (
5959
}
6060

6161
defaultDialer = fasthttp.TCPDialer{
62-
Concurrency: maxConcurrent,
62+
Concurrency: maxConcurrent,
6363
DNSCacheDuration: time.Minute,
6464
}
6565

6666
fastclient = fasthttp.Client{
6767
NoDefaultUserAgentHeader: true,
68-
Dial: defaultDialer.DialDualStack,
69-
MaxConnWaitTimeout: 10 * time.Second,
68+
Dial: defaultDialer.DialDualStack,
69+
MaxConnWaitTimeout: 10 * time.Second,
7070
}
7171
)
7272

@@ -75,7 +75,7 @@ func Logging(level LogLevel, format string, args ...any) {
7575
return
7676
}
7777
if len(args) == 0 {
78-
format += "\n" // append line break if no arg
78+
format += "\n"
7979
}
8080

8181
fmt.Printf("%s %s %s",
@@ -163,7 +163,19 @@ func handleFastHTTP(ctx *fasthttp.RequestCtx) {
163163

164164
func handleFastHTTPS(ctx *fasthttp.RequestCtx) {
165165
Info("Connect to: https://%s\n", ctx.Host())
166+
167+
// Tell fasthttp not to send any automatic response
168+
ctx.HijackSetNoResponse(true)
169+
166170
ctx.Hijack(func(clientConn net.Conn) {
171+
// Manually write the 200 OK response without Connection: close
172+
_, err := clientConn.Write([]byte("HTTP/1.1 200 OK\r\n\r\n"))
173+
if err != nil {
174+
Error("Failed to send CONNECT response: %s", err)
175+
return
176+
}
177+
178+
// Now establish the tunnel to the destination
167179
destConn, err := defaultDialer.DialTimeout(b2s(ctx.Host()), timeout)
168180
if err != nil {
169181
Error("Dial timeout: %s", err)
@@ -178,13 +190,10 @@ func handleFastHTTPS(ctx *fasthttp.RequestCtx) {
178190
})
179191
}
180192

181-
// Unsafe but fast []byte to string convertion without memory copy
182193
func b2s(b []byte) string {
183-
/* #nosec G103 */
184194
return *(*string)(unsafe.Pointer(&b))
185195
}
186196

187-
// wait graceful shutdown
188197
func wait(server *fasthttp.Server) <-chan struct{} {
189198
graceful.NewManager().AddRunningJob(func(ctx context.Context) error {
190199
<-ctx.Done()
@@ -201,7 +210,6 @@ func wait(server *fasthttp.Server) <-chan struct{} {
201210
return graceful.NewManager().Done()
202211
}
203212

204-
// request handler in fasthttp style, i.e. just plain function.
205213
func fastHTTPHandler(ctx *fasthttp.RequestCtx) {
206214
switch strings.ToUpper(b2s(ctx.Method())) {
207215
case fasthttp.MethodConnect:
@@ -213,18 +221,17 @@ func fastHTTPHandler(ctx *fasthttp.RequestCtx) {
213221

214222
func main() {
215223
server := &fasthttp.Server{
216-
Handler: fasthttp.CompressHandler(fastHTTPHandler),
217-
ReadTimeout: timeout,
218-
WriteTimeout: timeout,
219-
MaxConnsPerIP: 1024,
224+
Handler: fasthttp.CompressHandler(fastHTTPHandler),
225+
ReadTimeout: timeout,
226+
WriteTimeout: timeout,
227+
MaxConnsPerIP: 1024,
220228
MaxRequestsPerConn: 1024,
221-
IdleTimeout: 3 * timeout,
229+
IdleTimeout: 3 * timeout,
222230
ReduceMemoryUsage: true,
223231
CloseOnShutdown: true,
224-
Concurrency: maxConcurrent,
232+
Concurrency: maxConcurrent,
225233
}
226234

227-
// Start server
228235
go func() {
229236
Info("Version: %s\n", ver)
230237
Info("Concurrency: %d\n", maxConcurrent)

0 commit comments

Comments
 (0)