想实现一个简单的 proxy,仅作为玩具使用, 当然其实现成的 lib 有很多, 但是目标很明确,学习一下基本原理
有的, 有一个 python 版本的, 在 github 上发现的 python proxy code
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
有的, 发现 local to server 的时候, read 出现了 error, err: ECONNRESET (54) 然后 接下来就 EOF 了, 所以就退出了, 但是拿到这个 error 的时候, curl 就已经结束了, 所以拿到 EOF 也是正常行为, 主要在于不知道为啥会 curl 会断掉
这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。
V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。
V2EX is a community of developers, designers and creative people.