介绍
goproxy - An HTTP proxy library for Go
可参考文档:goproxy
简单来说,就是GO实现的http代理,可以从中间操作经过的数据包;劫持到的数据包就是一个net/http
的实例
安装
我直接用go get
搞不下来了,不知道是不是GO1.18的问题,所以这里我直接git clone
下来,放到对应的src目录即可
mkdir $GOPATH/src/github.com/elazarl
cd elazarl
git clone https://github.com/elazarl/goproxy
快速入门
直接用readme中的例子,其中DoFunc
是对数据包进行二次处理。
package main
import (
"github.com/elazarl/goproxy"
"log"
"net/http"
)
func main() {
proxy := goproxy.NewProxyHttpServer()
proxy.Verbose = true
proxy.OnRequest().DoFunc(
func(r *http.Request,ctx *goproxy.ProxyCtx)(*http.Request,*http.Response) {
// 添加Header头
r.Header.Set("X-GoProxy","yxorPoG-X")
return r,nil
})
log.Fatal(http.ListenAndServe(":8080", proxy))
}
跑起来,本地监听80端口,然后用curl发起请求
curl -x http://127.0.0.1:8080 http://127.0.0.1
查看收到的数据包,是我想要的效果,大功告成。
常见用法
各种例子:examples
上面用了一个proxy.OnRequest()
,其他的直接从文档里面复制过来了
There are 3 kinds of useful handlers to manipulate the behavior, as follows:
// handler called after receiving HTTP CONNECT from the client, and before proxy establish connection
// with destination host
httpsHandlers []HttpsHandler
// handler called before proxy send HTTP request to destination host
reqHandlers []ReqHandler
// handler called after proxy receives HTTP Response from destination host, and before proxy forward
// the Response to the client.
respHandlers []RespHandler
Depending on what you want to manipulate, the ways to add handlers to each handler list are:
// Add handlers to httpsHandlers
proxy.OnRequest(Some ReqConditions).HandleConnect(YourHandlerFunc())
// Add handlers to reqHandlers
proxy.OnRequest(Some ReqConditions).Do(YourReqHandlerFunc())
// Add handlers to respHandlers
proxy.OnResponse(Some RespConditions).Do(YourRespHandlerFunc())
For example:
// This rejects the HTTPS request to *.reddit.com during HTTP CONNECT phase
proxy.OnRequest(goproxy.ReqHostMatches(regexp.MustCompile("reddit.*:443$"))).HandleConnect(goproxy.AlwaysReject)
// This will NOT reject the HTTPS request with URL ending with gif, due to the fact that proxy
// only got the URL.Hostname and URL.Port during the HTTP CONNECT phase if the scheme is HTTPS, which is
// quiet common these days.
proxy.OnRequest(goproxy.UrlMatches(regexp.MustCompile(`.*gif$`))).HandleConnect(goproxy.AlwaysReject)
// The correct way to manipulate the HTTP request using URL.Path as condition is:
proxy.OnRequest(goproxy.UrlMatches(regexp.MustCompile(`.*gif$`))).Do(YourReqHandlerFunc())
代理HTTPS
要获取到https流量,都需要在客户端安装信任 CA 证书
生成自签名证书
使用goproxy
自带的生成脚本,路径为github.com/elazarl/goproxy/certs
,可以自己修改openssl.cnf
的配置
sh openssl-gen.sh
会在当前目录生成ca.pem
和ca.key.pem
,macos直接双击安装ca.pem
到钥匙串并完全信任,windows后缀名改为.crt
双击安装并分类到系统根证书
设置代理证书
设置证书代码参考:github.com/elazarl/goproxy/examples/goproxy-customca/cert.go
package main
import (
"crypto/tls"
"crypto/x509"
"github.com/elazarl/goproxy"
"io/ioutil"
"log"
"net/http"
"os"
)
/*
设置代理证书,caCert和caKey就是刚才生成的pem文件内容
*/
func setCA(caCert, caKey []byte) error {
goproxyCa, err := tls.X509KeyPair(caCert, caKey)
if err != nil {
return err
}
if goproxyCa.Leaf, err = x509.ParseCertificate(goproxyCa.Certificate[0]); err != nil {
return err
}
goproxy.GoproxyCa = goproxyCa
goproxy.OkConnect = &goproxy.ConnectAction{Action: goproxy.ConnectAccept, TLSConfig: goproxy.TLSConfigFromCA(&goproxyCa)}
goproxy.MitmConnect = &goproxy.ConnectAction{Action: goproxy.ConnectMitm, TLSConfig: goproxy.TLSConfigFromCA(&goproxyCa)}
goproxy.HTTPMitmConnect = &goproxy.ConnectAction{Action: goproxy.ConnectHTTPMitm, TLSConfig: goproxy.TLSConfigFromCA(&goproxyCa)}
goproxy.RejectConnect = &goproxy.ConnectAction{Action: goproxy.ConnectReject, TLSConfig: goproxy.TLSConfigFromCA(&goproxyCa)}
return nil
}
func main() {
pwd, _ := os.Getwd()
caCert, _ := ioutil.ReadFile(pwd + "/ca.pem") // 设置为你刚才生成的 ca.pem 路径
caKey, _ := ioutil.ReadFile(pwd + "/ca.key.pem") // 设置为你刚才生成的 ca.key.pem 路径
setCA(caCert, caKey)
proxy := goproxy.NewProxyHttpServer()
proxy.Verbose = true
proxy.OnRequest().HandleConnect(goproxy.AlwaysMitm)
proxy.OnRequest().DoFunc(
func(r *http.Request,ctx *goproxy.ProxyCtx)(*http.Request,*http.Response) {
// 添加Header头
r.Header.Set("X-GoProxy","yxorPoG-X")
return r,nil
})
proxy.OnResponse().DoFunc(
func(resp *http.Response, ctx *goproxy.ProxyCtx) *http.Response {
// 返回包状态码修改
resp.StatusCode = 404
return resp
})
log.Fatal(http.ListenAndServe(":8080", proxy))
}
启动后curl试试,发现已经OK了
curl -x http://127.0.0.1:8080 https://blog.gm7.org/