- 问题由来
想实现一个简单的 proxy,仅作为玩具使用, 当然其实现成的 lib 有很多, 但是目标很明确,学习一下基本原理
- 是否有其他的代码参考
有的, 有一个 python 版本的, 在 github 上发现的 python proxy code
- 是否有 GO 代码
package main
import (
"errors"
"fmt"
"github.com/valyala/fasthttp"
"io"
"log"
"net"
"sync"
)
func main() {
if err := fasthttp.ListenAndServe(":1234", requestHandler); err != nil {
log.Fatalf("Error in ListenAndServe: %s", err)
}
}
func processSocket(conn1, conn2 net.Conn, wg *sync.WaitGroup, s string) {
defer func() {
fmt.Println("END", s)
wg.Done()
}()
fmt.Println(s)
var buf []byte
buf = make([]byte, 4096)
i, err := conn1.Read(buf)
buf = buf[:i]
if err != nil {
return
}
for {
fmt.Println(s, string(buf))
conn2.Write(buf)
buf = buf[:]
buf = make([]byte, 2<<10<<10) // 10m
i, err := conn1.Read(buf)
buf = buf[:i]
if err != nil {
if len(buf) > 0 {
conn2.Write(buf)
}
fmt.Println(s, err)
if errors.Is(err, io.EOF) {
break
}
}
}
}
func haddleHTTPS(ctx *fasthttp.RequestCtx) {
h := string(ctx.Request.Host()) // host:port eg. www.baidu.com:443
curConn := ctx.Conn()
curConn.Write([]byte("HTTP/1.1 200 OK\r\nContent-Length: 6\r\n\r\nfoo"))
fmt.Println("haddle:", h)
remotConn, err := net.Dial("tcp", h)
if err != nil {
}
var wg sync.WaitGroup
wg.Add(2)
go processSocket(curConn, remotConn, &wg, "from local to remote")
go processSocket(remotConn, curConn, &wg, "from remote to local")
wg.Wait()
}
func haddleHTTP(ctx *fasthttp.RequestCtx) {
req := fasthttp.AcquireRequest()
req.SetRequestURIBytes(ctx.Request.RequestURI())
//req.Header.SetMethodBytes(ctx.Method())
req.Header = ctx.Request.Header
req.SetBody(ctx.Request.Body())
client := &fasthttp.Client{}
resp := fasthttp.AcquireResponse()
client.Do(req, resp)
body := resp.Body()
fmt.Println(body)
ctx.Write(body)
}
func requestHandler(ctx *fasthttp.RequestCtx) {
method := string(ctx.Method())
if method == "CONNECT" {
// https
haddleHTTPS(ctx)
return
}
// http
haddleHTTP(ctx)
return
}
- 代码是否可以正常工作
不行, http 是没有问题的, https 存在问题
- 问题日志 /描述
➜ ~ curl https://www.baidu.com -vvv
* Uses proxy env variable https_proxy == 'http://127.0.0.1:1234'
* Trying 127.0.0.1...
* TCP_NODELAY set
* Connected to 127.0.0.1 (127.0.0.1) port 1234 (#0)
* allocate connect buffer!
* Establish HTTP proxy tunnel to www.baidu.com:443
> CONNECT www.baidu.com:443 HTTP/1.1
> Host: www.baidu.com:443
> User-Agent: curl/7.64.1
> Proxy-Connection: Keep-Alive
>
< HTTP/1.1 200 OK
< Content-Length: 6
* Ignoring Content-Length in CONNECT 200 response
<
* Proxy replied 200 to CONNECT request
* CONNECT phase completed!
* ALPN, offering h2
* ALPN, offering http/1.1
* successfully set certificate verify locations:
* CAfile: /etc/ssl/cert.pem
CApath: none
* TLSv1.2 (OUT), TLS handshake, Client hello (1):
* CONNECT phase completed!
* CONNECT phase completed!
* error:1400410B:SSL routines:CONNECT_CR_SRVR_HELLO:wrong version number
* Closing connection 0
curl: (35) error:1400410B:SSL routines:CONNECT_CR_SRVR_HELLO:wrong version number
- 是否自行 debug
有的, 发现 local to server 的时候, read 出现了 error, err: ECONNRESET (54) 然后 接下来就 EOF 了, 所以就退出了, 但是拿到这个 error 的时候, curl 就已经结束了, 所以拿到 EOF 也是正常行为, 主要在于不知道为啥会 curl 会断掉
- 主题目标
- 想知道为什么 curl 会断掉
- 有没有什么解决办法[在上述代码中修改]
- 或者有其他代码编写方式