当前有很多代理工具,例如fiddler(免费),charles(收费)等,他们功能都非常强大,为什么我还要自己做自己的代理工具呢?
我也不晓得,就是有些功能自定义可能使用方便一些吧大概
- 首先go环境的搭建,就不在赘述,我使用vscode+go的一些组件,安装方法参考:https://blog.csdn.net/AdolphKevin/article/details/105480530
- 首先初始化mod
go mod init mitm
#会生成一个go.mod的文件
- 使用github上现成的编写自己的自定义
package proxy
import (
"bytes"
"crypto/tls"
"github.com/ouqiang/goproxy"
"io/ioutil"
"log"
"mitm/util"
"mitm/watcher"
"net/http"
"net/url"
"os"
"strings"
"sync"
// "time"
)
// Cache 实现证书缓存接口
type Cache struct {
m sync.Map
}
//Set 234
func (c *Cache) Set(host string, cert *tls.Certificate) {
c.m.Store(host, cert)
}
//Get 123
func (c *Cache) Get(host string) *tls.Certificate {
v, ok := c.m.Load(host)
if !ok {
return nil
}
return v.(*tls.Certificate)
}
//Conf 123
type Conf struct {
NotConnectLIst []string
ReqHeaderMap map[string]string
ReqHostMap map[string]string
ResShowBodyList []string
ParentProxy string
ParentProxyShowList []string
ResInfoMap map[string]string //暂时不做
}
// ReadFile 123
func (c *Conf) ReadFile() {
list := util.ReadFile("mitm.conf")
// log.Println(list)
c1 := &Conf{NotConnectLIst: make([]string, 0, 0), ReqHeaderMap: make(map[string]string), ReqHostMap: make(map[string]string), ResShowBodyList: make([]string, 0, 0), ResInfoMap: make(map[string]string), ParentProxy: "", ParentProxyShowList: make([]string, 0, 0)}
for _, line := range list {
if !strings.HasPrefix(line, "#") && len(strings.TrimSpace(line)) > 0 {
lineInner := strings.Split(line, "=")
switch lineInner[0] {
case "NotConnect":
context := strings.Replace(line, "NotConnect=", "", 1)
c1.NotConnectLIst = append(c1.NotConnectLIst, context)
case "ReqHeader":
c1.ReqHeaderMap[lineInner[1]] = lineInner[2]
case "ReqHost":
c1.ReqHostMap[lineInner[1]] = lineInner[2]
case "ResBody":
c1.ResShowBodyList = append(c1.ResShowBodyList, strings.Replace(line, "ResBody=", "", 1))
case "Proxy":
c1.ParentProxy = strings.Replace(line, "Proxy=", "", 1)
case "ProxyShow":
c1.ParentProxyShowList = append(c1.ParentProxyShowList, strings.Replace(line, "ProxyShow=", "", 1))
}
}
}
c.compare(c1)
// c.ParentProxy = c1.ParentProxy
// log.Println(c)
// log.Println(c1)
c.NotConnectLIst = c1.NotConnectLIst
c.ReqHeaderMap = c1.ReqHeaderMap
c.ReqHostMap = c1.ReqHostMap
c.ResShowBodyList = c1.ResShowBodyList
c.ParentProxy = c1.ParentProxy
c.ParentProxyShowList = c1.ParentProxyShowList
}
func (c *Conf) compare(c1 *Conf) {
// log.Println(c1)
// log.Println(c)
if c.ParentProxy != c1.ParentProxy {
log.Println("修改代理地址:" + ",从" + c.ParentProxy + "修改成" + c1.ParentProxy)
}
for _, con := range c.NotConnectLIst {
isC := false
for _, con1 := range c1.NotConnectLIst {
if con == con1 {
isC = true
}
}
if !isC {
log.Println("拒绝连接移除:" + con)
}
}
for _, con := range c1.NotConnectLIst {
isC := false
for _, con1 := range c.NotConnectLIst {
if con == con1 {
isC = true
}
}
if !isC {
log.Println("拒绝连接添加:" + con)
}
}
for _, con := range c.ParentProxyShowList {
isC := false
for _, con1 := range c1.ParentProxyShowList {
if con == con1 {
isC = true
}
}
if !isC {
log.Println("代理可见移除:" + con)
}
}
for _, con := range c1.ParentProxyShowList {
isC := false
for _, con1 := range c.ParentProxyShowList {
if con == con1 {
isC = true
}
}
if !isC {
log.Println("代理可见添加:" + con)
}
}
for _, con := range c.ResShowBodyList {
isC := false
for _, con1 := range c1.ResShowBodyList {
if con == con1 {
isC = true
}
}
if !isC {
log.Println("相应结果移除:" + con)
}
}
for _, con := range c1.ResShowBodyList {
isC := false
for _, con1 := range c.ResShowBodyList {
if con == con1 {
isC = true
}
}
if !isC {
log.Println("相应结果添加:" + con)
}
}
for k, v := range c.ReqHeaderMap {
v1, ok := c1.ReqHeaderMap[k]
if !ok {
log.Println("移除:" + k + v)
} else {
if v != v1 {
log.Println("修改:" + k + "值,从" + v + "修改成" + v1)
}
}
}
for k, v := range c1.ReqHeaderMap {
_, ok := c.ReqHeaderMap[k]
if !ok {
log.Println("添加:" + k + v)
}
}
for k, v := range c.ReqHostMap {
v1, ok := c1.ReqHostMap[k]
if !ok {
log.Println("移除:" + k + v)
} else {
if v != v1 {
log.Println("修改:" + k + "值,从" + v + "修改成" + v1)
}
}
}
for k, v := range c1.ReqHostMap {
_, ok := c.ReqHostMap[k]
if !ok {
log.Println("添加:" + k + v)
}
}
}
func match(source string, filter string) bool {
tmp := strings.TrimSpace(filter)
if len(tmp) > 0 && tmp != "all" && tmp != "ALL" {
sign := tmp[:1]
switch sign {
case "!":
return source != tmp[1:]
case "^":
return !strings.Contains(source, tmp[1:])
case "~":
return strings.Contains(source, tmp[1:])
default:
return source == tmp[1:]
}
} else {
return true
}
}
// CheckFile 123
func (c *Conf) CheckFile() {
if util.IsExist("mitm.conf") {
c.ReadFile()
} else {
f, err := os.Create("mitm.conf")
defer f.Close()
if err != nil {
// 创建文件失败处理
panic(err)
} else {
confsource := `#!V0.0.1
#对于mitm的配置文件,使用键值对的模式
#匹配规则
#!xxx 不等于xxx
#^xxx 不含有xxx
#~xxx 含有xxx
#xxx 等于xxx
#'#'开头注释一行
#可配置的规则如下:
#
#拒绝连接部分,格式:NotConnect=匹配url
#NotConnect=~www.google.com
#添加/修改请求头,默认添加fromroute: mitm,格式:ReqHeader=匹配url/all=key: value
#ReqHeader=all=xxx: yyy
#ReqHeader=~www.baidu.c=xxx1: yyy1
#修改请求方法,格式:ReqMethod=匹配url/all=method,未完成!
#ReqMethod=~www.baidu.c=post
#修改请求url,格式:ReqURL=匹配url/all=method,未完成!
#ReqURL=~www.baidu.c=URL
#修改请求内容,格式:ReqBody=匹配url/all=Body,未完成!
#ReqBody=~www.baidu.c={"aa":1}
#修改请求域名,格式:ReqHost=匹配url/all=Host
#ReqHost=~www.baidu.c=xxx
#显示相应结果,格式:ResBody=xxx
#ResBody=~www.baidu.c
#配置二级代理路径,唯一性不可多配制,多配置读取最后配置
#Proxy=10.xx.xx.xx:xxxx
#配置二级代理可见url,格式:ProxyShow=xxx
#ProxyShow=~www.baidu.c
#配置二级代理不可见url,格式:ProxyNotShow=xxx,未完成!
#ProxyNotShow=~www.baidu.c
`
_, err = f.Write([]byte(confsource))
if err != nil {
// 写入失败处理
panic(err)
}
c.ReadFile()
}
}
}
var conf *Conf
// EventHandler 2134
type EventHandler struct{}
// Connect qwe
func (e *EventHandler) Connect(ctx *goproxy.Context, rw http.ResponseWriter) {
// 禁止访问某个域名
for _, con := range conf.NotConnectLIst {
if match(ctx.Req.URL.String(), con) {
rw.WriteHeader(http.StatusForbidden)
ctx.Abort()
return
}
}
}
//Auth 234
func (e *EventHandler) Auth(ctx *goproxy.Context, rw http.ResponseWriter) {
// 身份验证
}
// BeforeRequest 234
func (e *EventHandler) BeforeRequest(ctx *goproxy.Context) {
for k, v := range conf.ReqHeaderMap {
if match(ctx.Req.URL.String(), k) {
v1 := strings.Split(v, ": ")
ctx.Req.Header.Set(v1[0], v1[1])
}
}
for k, v := range conf.ReqHostMap {
if match(ctx.Req.URL.String(), k) {
ctx.Req.Host = v
ctx.Req.URL.Host = v
}
}
ctx.Req.Header.Set("fromroute", "mitm")
}
// BeforeResponse 2131
func (e *EventHandler) BeforeResponse(ctx *goproxy.Context, resp *http.Response, err error) {
if err != nil {
log.Println("Perr:", err)
return
}
// 修改response
for _, con := range conf.ResShowBodyList {
if match(ctx.Req.URL.String(), con) {
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
// 错误处理
log.Println(err)
return
}
var str string = string(body[:])
log.Println(str)
resp.Body = ioutil.NopCloser(bytes.NewReader(body))
}
}
}
// ParentProxy 设置上级代理
func (e *EventHandler) ParentProxy(req *http.Request) (*url.URL, error) {
// return req.URL, nil
// log.Println(conf)
res := true
for _, con := range conf.ParentProxyShowList {
if !match(req.URL.String(), con) {
res = false
break
}
}
if res {
if conf.ParentProxy != "" {
if strings.HasPrefix(conf.ParentProxy, "http://") {
return url.Parse(conf.ParentProxy)
}
return url.Parse("http://" + conf.ParentProxy)
}
}
return nil, nil
}
// Finish 13
func (e *EventHandler) Finish(ctx *goproxy.Context) {
// fmt.Printf("请求结束 URL:%s\n", ctx.Req.URL)
}
// ErrorLog 记录错误日志
func (e *EventHandler) ErrorLog(err error) {
// log.Println("err:", err)
}
// GetProxy 代理的处理
func GetProxy() *goproxy.Proxy {
conf = &Conf{NotConnectLIst: make([]string, 0, 0), ReqHeaderMap: make(map[string]string), ReqHostMap: make(map[string]string), ResShowBodyList: make([]string, 0, 0), ResInfoMap: make(map[string]string), ParentProxy: "", ParentProxyShowList: make([]string, 0, 0)}
conf.CheckFile()
go watcher.WatchFile("mitm.conf", conf.ReadFile)
return goproxy.New(goproxy.WithDelegate(&EventHandler{}), goproxy.WithDecryptHTTPS(&Cache{}))
}
- 由于本人技术低,使用fsnotify发现浪费大部分功能,就傻傻轮询文件
package watcher
import (
"log"
"mitm/util"
"os"
"time"
)
var mtime int64
// WatchFile 3424
func WatchFile(file string, f1 func()) {
if !util.IsExist(file) {
log.Fatal("no" + file)
return
}
mtime = time.Now().Unix()
for {
mt := GetFileModTime(file)
if mt > mtime {
mtime = mt
f1()
} else {
time.Sleep(time.Second * time.Duration(3))
}
}
}
//GetFileModTime 123
func GetFileModTime(path string) int64 {
fi, err := os.Stat(path)
if err != nil {
log.Println("stat error")
return time.Now().Unix()
}
return fi.ModTime().Unix()
}
- https需要的证书
package cert
import (
"bufio"
// "fmt"
"log"
"mitm/util"
"os"
)
//AddCRT 添加证书
func AddCRT() {
if !util.IsExist("./mitmproxy.crt") {
datasource := `-----BEGIN CERTIFICATE-----
MIIFdDCCA1ygAwIBAgIBATANBgkqhkiG9w0BAQsFADBZMQ4wDAYDVQQGEwVDaGlu
YTEPMA0GA1UECBMGRnVKaWFuMQ8wDQYDVQQHEwZYaWFtZW4xDTALBgNVBAoTBE1h
cnMxFjAUBgNVBAMTDWdvLW1pdG0tcHJveHkwIBcNMTgwMzE4MDkwMDQ0WhgPMjA2
ODAzMTgwOTAwNDRaMFkxDjAMBgNVBAYTBUNoaW5hMQ8wDQYDVQQIEwZGdUppYW4x
DzANBgNVBAcTBlhpYW1lbjENMAsGA1UEChMETWFyczEWMBQGA1UEAxMNZ28tbWl0
bS1wcm94eTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBANiuppEbanTv
iCs47AFIAy+AVXDhaInal4fGmN+kG1txO4YPygKGrdjokCZtkL6ZK61izFg6BLX+
p65j8wnAPZPZr3Zu5vlcDM7baO9ddxtnXm/fACPEuMIvgmG7zxE9CeX3LY7tsq10
hg8uKMnYGTy5Ce0hkuYn8Od0yHseGFWCmaCAHIcshbvQFxPGn42X/zWrEHDEgWtG
fOlamBBTSbNza11H8udLkXlr+N+vv/P/eKjpeIf/xzPCdiUOxdD+NHCeeSgho3Sm
P0T6ia4L7MVW0XUg7CseVVh+9TddO6QefmM1+AsWU/ektD+cUMtlWoDXE8idlpoZ
cMVJfq/6Sa9nG280fCPjd4wFLqbR67BHQkoPjQ1vmRgs4xvD04m796dRPpTDepb/
xvTTMcwgAC5tur/E5SHpr8hx9X6xGPfUUMiKyBQlSgLH4V02SjAmScxqt5AWZcT/
syLHg7BhjxwBGoCwcE8zWHCJarQ0t28Z7ptyL3DXPaJ7Vd2CvLJrekvtnm9B28aU
9KOC9JL3DKzFaRrhTYb0VNLfoLV8kRJCzZI6HAwiKcAAEIXi8on6YwqLvEIxo5AL
0gTeIf/nJU2W4OY640fIdwEvcaH4Wj2bKMRaTWvQGM1TJe4hoCN/c3mVopotCb44
IGC5R0XmVImVxZmdyCXJAfY1jYrWHA2ZAgMBAAGjRTBDMA4GA1UdDwEB/wQEAwIB
BjASBgNVHRMBAf8ECDAGAQH/AgEAMB0GA1UdDgQWBBSfjEyzebvckLQu+eZjlmJF
W0/ZmjANBgkqhkiG9w0BAQsFAAOCAgEAXHGvSFwtcqX6lD9rmLTPeViTIan5hG5T
sEWsPp/kI6j579OavwCr7mk4nUjsKFaOEzN78C4k6s4gDWWePoJhlsXB4KefriW4
gWevzwgRTrIlaw3EDb+fCle0HcsCI/wwxDD8eafUxEyqBGrhLJFiUIxvOcD+yP2Q
mX3Z89Pd38Qvkb9zneJdXo2wHMq0MGKlTPdE04rg1OsuPNnSwRhtem9/E4eCtumF
JoQEQtp440wpvrbZljR18Ahd+xNh6dyaD0prnrUEGsUkC1hMb3nUWmw6dZEA5rCv
8aW5ZMm9Jr7pW7yzrm8J4II1bY5v6i7+qvOFDAf1nEnVshcSCiHu6xzgtwoGtsP8
mSOquiWwiceJL6q8xh6nOD3SYm2mZwA1n7Nl3mRJE/RgbwJNkveMrmZ6CKUm3N/x
eqd5yhTLsD7sf3+d4B7i6fAZ+csccWaDuquVI9cXi2OoMKgIFeeVwJ1FCeLY0Nah
nPlNUA0h7xKeDIHtlGsSOng6uiEVVVXGS+j9V6h+Z55AsuOAoHYOBDoXfr0Y4Bww
irCRNyFcDrKoyILOOUiPxoEcclrwUBTB78JxVA8xKTbAh0aZQRZOZOz49qF4gA1d
1riiUHJIG2sD+54UEdFoR5nhZ4/RLGqQ/Kmch5VnPp7De4OzSMd/KkQDWEjR+AA1
CDPlL4gNB6s=
-----END CERTIFICATE-----
`
f, err := os.Create("./mitmproxy.crt")
defer f.Close()
if err != nil {
// 创建文件失败处理
panic(err)
} else {
_, err = f.Write([]byte(datasource))
if err != nil {
// 写入失败处理
panic(err)
}
}
log.Println("已创建https证书,请安装至根目录:mitmproxy.crt\n回车关闭~")
reader := bufio.NewReader(os.Stdin)
reader.ReadString('\n')
os.Exit(1)
}
}
- 最后执行的main
package main
import (
// "github.com/fsnotify/fsnotify"
"log"
"mitm/cert"
"mitm/proxy"
"net/http"
"time"
)
func main() {
// log.Println("代理地址:http://当前机器ip:8088")
cert.AddCRT()
log.Println("代理地址:http://当前机器ip:8088")
server := &http.Server{
Addr: ":8088",
Handler: proxy.GetProxy(),
ReadTimeout: 1 * time.Minute,
WriteTimeout: 1 * time.Minute,
}
// log.Println("代理地址:http://当前机器ip:8088")
err := server.ListenAndServe()
if err != nil {
panic(err)
}
// log.Println("代理地址:http://当前机器ip:8088")
}
- 其他
问我这些还不够,还有一个util呢?只是实现了读取文件和判断文件在不在的方法
package util
import (
"bufio"
"log"
"os"
"strings"
)
// IsExist 判断文件是否存在
func IsExist(fileAddr string) bool {
// 读取文件信息,判断文件是否存在
_, err := os.Stat(fileAddr)
if err != nil {
// log.Println(err)
if os.IsExist(err) { // 根据错误类型进行判断
return true
}
return false
}
return true
}
//ReadFile 123
func ReadFile(file string) []string {
files, err := os.Open(file)
if err != nil {
log.Fatal(err)
}
defer files.Close()
scanner := bufio.NewScanner(files)
list := make([]string, 0, 0)
for scanner.Scan() {
lineText := strings.TrimSpace(scanner.Text())
if lineText != "" {
list = append(list, lineText)
}
}
return list
}