From d132001d326016706580221e51b952d3310667dd Mon Sep 17 00:00:00 2001 From: sheepbao <331541471@qq.com> Date: Mon, 3 Apr 2017 00:24:48 +0800 Subject: [PATCH] =?UTF-8?q?=E9=87=8D=E6=9E=84=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- build.sh | 2 + gomitmproxy.go | 84 --------------------- readme.md | 4 +- goproxy.png => src/doc/goproxy.png | Bin proxy.png => src/doc/proxy.png | Bin src/main/main.go | 41 ++++++++++ tcolor.go => src/vendor/color/tcolor.go | 2 +- config.go => src/vendor/config/config.go | 14 +--- cache.go => src/vendor/mitm/cache.go | 2 +- dump.go => src/vendor/mitm/dump.go | 32 ++++---- genKey.go => src/vendor/mitm/genKey.go | 9 ++- src/vendor/mitm/gomitmproxy.go | 48 ++++++++++++ listener.go => src/vendor/mitm/listener.go | 2 +- mitm.go => src/vendor/mitm/mitm.go | 69 ++++++++++------- src/vendor/mylog/my_log.go | 30 ++++++++ src/vendor/mylog/my_log_test.go | 17 +++++ src/vendor/mylog/test.log | 1 + 17 files changed, 211 insertions(+), 146 deletions(-) create mode 100755 build.sh delete mode 100644 gomitmproxy.go rename goproxy.png => src/doc/goproxy.png (100%) rename proxy.png => src/doc/proxy.png (100%) create mode 100644 src/main/main.go rename tcolor.go => src/vendor/color/tcolor.go (99%) rename config.go => src/vendor/config/config.go (87%) rename cache.go => src/vendor/mitm/cache.go (98%) rename dump.go => src/vendor/mitm/dump.go (57%) rename genKey.go => src/vendor/mitm/genKey.go (98%) create mode 100644 src/vendor/mitm/gomitmproxy.go rename listener.go => src/vendor/mitm/listener.go (96%) rename mitm.go => src/vendor/mitm/mitm.go (84%) create mode 100644 src/vendor/mylog/my_log.go create mode 100644 src/vendor/mylog/my_log_test.go create mode 100644 src/vendor/mylog/test.log diff --git a/build.sh b/build.sh new file mode 100755 index 0000000..522ae1b --- /dev/null +++ b/build.sh @@ -0,0 +1,2 @@ +export GOPATH=`pwd` +go build -o bin/gomitmproxy src/main/*.go \ No newline at end of file diff --git a/gomitmproxy.go b/gomitmproxy.go deleted file mode 100644 index c358b15..0000000 --- a/gomitmproxy.go +++ /dev/null @@ -1,84 +0,0 @@ -// This example shows a proxy server that uses go-mitm to man-in-the-middle -// HTTPS connections opened with CONNECT requests - -package main - -import ( - "flag" - "log" - "net/http" - "os" - "sync" - "time" -) - -const ( - Version = "1.1" -) - -var ( - wg sync.WaitGroup -) - -var logFile *os.File -var logger *log.Logger - -func main() { - var conf Cfg - - conf.Port = flag.String("port", "8080", "Listen port") - conf.Raddr = flag.String("raddr", "", "Remote addr") - conf.Log = flag.String("log", "./error.log", "log file path") - conf.Monitor = flag.Bool("m", false, "monitor mode") - conf.Tls = flag.Bool("tls", false, "tls connect") - flag.Parse() - - var err error - logFile, err = os.Create(*conf.Log) - if err != nil { - log.Fatalln("fail to create log file!") - } - - logger = log.New(logFile, "[gomitmproxy]", log.LstdFlags|log.Llongfile) - - wg.Add(1) - gomitmproxy(&conf) - wg.Wait() -} - -func gomitmproxy(conf *Cfg) { - tlsConfig := NewTlsConfig("gomitmproxy-ca-pk.pem", "gomitmproxy-ca-cert.pem", "", "") - - handler, err := InitConfig(conf, tlsConfig) - if err != nil { - logger.Fatalf("InitConfig error: %s", err) - } - - server := &http.Server{ - Addr: ":" + *conf.Port, - Handler: handler, - ReadTimeout: 1 * time.Hour, - WriteTimeout: 1 * time.Hour, - } - - go func() { - log.Printf("proxy listening port:%s", *conf.Port) - - if *conf.Tls { - log.Println("ListenAndServeTLS") - err = server.ListenAndServeTLS("gomitmproxy-ca-cert.pem", "gomitmproxy-ca-pk.pem") - } else { - log.Println("ListenAndServe") - err = server.ListenAndServe() - } - if err != nil { - logger.Fatalf("Unable to start HTTP proxy: %s", err) - } - - wg.Done() - - log.Printf("gomitmproxy stop!!!!") - }() - - return -} diff --git a/readme.md b/readme.md index c809f05..464fea6 100644 --- a/readme.md +++ b/readme.md @@ -40,7 +40,7 @@ gomitmproxy gomitmproxy -m ``` -![fetch http](https://raw.githubusercontent.com/sheepbao/gomitmproxy/develop/goproxy.png) +![fetch http](https://raw.githubusercontent.com/sheepbao/gomitmproxy/develop/doc/goproxy.png) 加 -m 参数,表示抓取http请求和响应 @@ -59,7 +59,7 @@ gomitmproxy -m ``` 然后浏览器设置代理,ip为localhost,端口为8080,即可实现科学上网 -![proxy](https://raw.githubusercontent.com/sheepbao/gomitmproxy/master/proxy.png) +![proxy](https://raw.githubusercontent.com/sheepbao/gomitmproxy/develop/doc/proxy.png) ## 最后 diff --git a/goproxy.png b/src/doc/goproxy.png similarity index 100% rename from goproxy.png rename to src/doc/goproxy.png diff --git a/proxy.png b/src/doc/proxy.png similarity index 100% rename from proxy.png rename to src/doc/proxy.png diff --git a/src/main/main.go b/src/main/main.go new file mode 100644 index 0000000..3a3ab49 --- /dev/null +++ b/src/main/main.go @@ -0,0 +1,41 @@ +package main + +import ( + "config" + "flag" + "io" + "mitm" + "mylog" + "os" + "sync" +) + +func main() { + var log io.WriteCloser + var err error + // cofig + conf := new(config.Cfg) + conf.Port = flag.String("port", "8080", "Listen port") + conf.Raddr = flag.String("raddr", "", "Remote addr") + conf.Log = flag.String("logFile", "", "log file path") + conf.Monitor = flag.Bool("m", false, "monitor mode") + conf.Tls = flag.Bool("tls", false, "tls connect") + flag.Parse() + + // init log + if *conf.Log != "" { + log, err = os.Create(*conf.Log) + if err != nil { + mylog.Fatalln("fail to create log file!") + } + } else { + log = os.Stderr + } + mylog.SetLog(log) + + // start mitm proxy + wg := new(sync.WaitGroup) + wg.Add(1) + mitm.Gomitmproxy(conf, wg) + wg.Wait() +} diff --git a/tcolor.go b/src/vendor/color/tcolor.go similarity index 99% rename from tcolor.go rename to src/vendor/color/tcolor.go index 5a6672c..5d92142 100644 --- a/tcolor.go +++ b/src/vendor/color/tcolor.go @@ -1,4 +1,4 @@ -package main +package color import ( "fmt" diff --git a/config.go b/src/vendor/config/config.go similarity index 87% rename from config.go rename to src/vendor/config/config.go index 6198be5..945ed42 100644 --- a/config.go +++ b/src/vendor/config/config.go @@ -1,16 +1,6 @@ -package main +package config -import ( - "crypto/tls" - "time" -) - -const ( - ONE_DAY = 24 * time.Hour - TWO_WEEKS = ONE_DAY * 14 - ONE_MONTH = 1 - ONE_YEAR = 1 -) +import "crypto/tls" type Cfg struct { Port *string diff --git a/cache.go b/src/vendor/mitm/cache.go similarity index 98% rename from cache.go rename to src/vendor/mitm/cache.go index 0a1c08e..d2c8022 100644 --- a/cache.go +++ b/src/vendor/mitm/cache.go @@ -1,6 +1,6 @@ // package cache implements a really primitive cache that associates expiring // values with string keys. This cache never clears itself out. -package main +package mitm import ( "sync" diff --git a/dump.go b/src/vendor/mitm/dump.go similarity index 57% rename from dump.go rename to src/vendor/mitm/dump.go index 5629329..e19536f 100644 --- a/dump.go +++ b/src/vendor/mitm/dump.go @@ -1,13 +1,15 @@ -package main +package mitm import ( "bufio" "bytes" + "color" "compress/flate" "compress/gzip" "fmt" "io/ioutil" "math" + "mylog" "net/http" "strconv" ) @@ -19,35 +21,35 @@ func httpDump(req *http.Request, resp *http.Response) { respStatusHeader := int(math.Floor(float64(respStatus / 100))) switch respStatusHeader { case 2: - respStatusStr = Green("<--" + strconv.Itoa(respStatus)) + respStatusStr = color.Green("<--" + strconv.Itoa(respStatus)) case 3: - respStatusStr = Yellow("<--" + strconv.Itoa(respStatus)) + respStatusStr = color.Yellow("<--" + strconv.Itoa(respStatus)) case 4: - respStatusStr = Magenta("<--" + strconv.Itoa(respStatus)) + respStatusStr = color.Magenta("<--" + strconv.Itoa(respStatus)) case 5: - respStatusStr = Red("<--" + strconv.Itoa(respStatus)) + respStatusStr = color.Red("<--" + strconv.Itoa(respStatus)) } - fmt.Println(Green("Request:")) - fmt.Printf("%s %s %s\n", Blue(req.Method), req.RequestURI, respStatusStr) + fmt.Println(color.Green("Request:")) + fmt.Printf("%s %s %s\n", color.Blue(req.Method), req.RequestURI, respStatusStr) for headerName, headerContext := range req.Header { - fmt.Printf("%s: %s\n", Blue(headerName), headerContext) + fmt.Printf("%s: %s\n", color.Blue(headerName), headerContext) } if req.Method == "POST" { - fmt.Println(Green("URLEncoded form")) + fmt.Println(color.Green("URLEncoded form")) for k, v := range req.Form { - fmt.Printf("%s: %s\n", Blue(k), v) + fmt.Printf("%s: %s\n", color.Blue(k), v) } } - fmt.Println(Green("Response:")) + fmt.Println(color.Green("Response:")) for headerName, headerContext := range resp.Header { - fmt.Printf("%s: %s\n", Blue(headerName), headerContext) + fmt.Printf("%s: %s\n", color.Blue(headerName), headerContext) } respBody, err := ioutil.ReadAll(resp.Body) if err != nil { - logger.Println("func httpDump read resp body err:", err) + mylog.Println("func httpDump read resp body err:", err) } else { acceptEncode := resp.Header["Content-Encoding"] var respBodyBin bytes.Buffer @@ -59,7 +61,7 @@ func httpDump(req *http.Request, resp *http.Response) { case "gzip": r, err := gzip.NewReader(&respBodyBin) if err != nil { - logger.Println("gzip reader err:", err) + mylog.Println("gzip reader err:", err) } else { defer r.Close() respBody, _ = ioutil.ReadAll(r) @@ -75,5 +77,5 @@ func httpDump(req *http.Request, resp *http.Response) { fmt.Printf("%s\n", string(respBody)) } - fmt.Printf("%s%s%s\n", Black("####################"), Cyan("END"), Black("####################")) + fmt.Printf("%s%s%s\n", color.Black("####################"), color.Cyan("END"), color.Black("####################")) } diff --git a/genKey.go b/src/vendor/mitm/genKey.go similarity index 98% rename from genKey.go rename to src/vendor/mitm/genKey.go index 0a54766..d83e076 100644 --- a/genKey.go +++ b/src/vendor/mitm/genKey.go @@ -1,5 +1,5 @@ // Package keyman provides convenience APIs around Go's built-in crypto APIs. -package main +package mitm import ( "crypto/rand" @@ -10,6 +10,7 @@ import ( "fmt" "io/ioutil" "math/big" + "mylog" "net" "os" "time" @@ -85,7 +86,7 @@ func (key *PrivateKey) WriteToFile(filename string) (err error) { return fmt.Errorf("Unable to PEM encode private key: %s", err) } if err := keyOut.Close(); err != nil { - logger.Printf("Unable to close file: %v", err) + mylog.Printf("Unable to close file: %v", err) } return } @@ -236,7 +237,7 @@ func (cert *Certificate) WriteToFile(filename string) (err error) { } defer func() { if err := certOut.Close(); err != nil { - logger.Printf("Unable to close file: %v", err) + mylog.Printf("Unable to close file: %v", err) } }() return pem.Encode(certOut, cert.pemBlock()) @@ -264,7 +265,7 @@ func (cert *Certificate) WriteToDERFile(filename string) (err error) { } defer func() { if err := certOut.Close(); err != nil { - logger.Printf("Unable to close file: %v", err) + mylog.Printf("Unable to close file: %v", err) } }() _, err = certOut.Write(cert.derBytes) diff --git a/src/vendor/mitm/gomitmproxy.go b/src/vendor/mitm/gomitmproxy.go new file mode 100644 index 0000000..a050d02 --- /dev/null +++ b/src/vendor/mitm/gomitmproxy.go @@ -0,0 +1,48 @@ +// This example shows a proxy server that uses go-mitm to man-in-the-middle +// HTTPS connections opened with CONNECT requests + +package mitm + +import ( + "config" + "mylog" + "net/http" + "sync" + "time" +) + +func Gomitmproxy(conf *config.Cfg, wg *sync.WaitGroup) { + tlsConfig := config.NewTlsConfig("gomitmproxy-ca-pk.pem", "gomitmproxy-ca-cert.pem", "", "") + + handler, err := InitConfig(conf, tlsConfig) + if err != nil { + mylog.Fatalf("InitConfig error: %s", err) + } + + server := &http.Server{ + Addr: ":" + *conf.Port, + Handler: handler, + ReadTimeout: 1 * time.Hour, + WriteTimeout: 1 * time.Hour, + } + + go func() { + mylog.Printf("Gomitmproxy Listening On: %s", *conf.Port) + if *conf.Tls { + mylog.Println("Listen And Serve HTTP TLS") + err = server.ListenAndServeTLS("gomitmproxy-ca-cert.pem", "gomitmproxy-ca-pk.pem") + } else { + mylog.Println("Listen And Serve HTTP") + err = server.ListenAndServe() + } + if err != nil { + mylog.Fatalf("Unable To Start HTTP proxy: %s", err) + } + + wg.Done() + + mylog.Printf("Gomitmproxy Stop!!!!") + }() + + return +} diff --git a/listener.go b/src/vendor/mitm/listener.go similarity index 96% rename from listener.go rename to src/vendor/mitm/listener.go index cb852d8..c1d14a5 100644 --- a/listener.go +++ b/src/vendor/mitm/listener.go @@ -1,4 +1,4 @@ -package main +package mitm import ( "io" diff --git a/mitm.go b/src/vendor/mitm/mitm.go similarity index 84% rename from mitm.go rename to src/vendor/mitm/mitm.go index edcb998..c82805a 100644 --- a/mitm.go +++ b/src/vendor/mitm/mitm.go @@ -1,12 +1,14 @@ -package main +package mitm import ( "bufio" + "config" "crypto/tls" "errors" "fmt" "io" "log" + "mylog" "net" "net/http" "net/http/httputil" @@ -17,9 +19,17 @@ import ( "time" ) +const ( + Version = "1.1" + ONE_DAY = 24 * time.Hour + TWO_WEEKS = ONE_DAY * 14 + ONE_MONTH = 1 + ONE_YEAR = 1 +) + type HandlerWrapper struct { - MyConfig *Cfg - tlsConfig *TlsConfig + MyConfig *config.Cfg + tlsConfig *config.TlsConfig wrapped http.Handler pk *PrivateKey pkPem []byte @@ -100,11 +110,16 @@ func (hw *HandlerWrapper) FakeCertForName(name string) (cert *tls.Certificate, e func (hw *HandlerWrapper) DumpHTTPAndHTTPs(resp http.ResponseWriter, req *http.Request) { req.Header.Del("Proxy-Connection") req.Header.Set("Connection", "Keep-Alive") + reqTmp := copyHTTPRequest(req) + err := reqTmp.ParseForm() + if err != nil { + mylog.Println("parseForm error:", err) + } // handle connection connIn, _, err := resp.(http.Hijacker).Hijack() if err != nil { - logger.Println("hijack error:", err) + mylog.Println("hijack error:", err) } defer connIn.Close() @@ -120,18 +135,18 @@ func (hw *HandlerWrapper) DumpHTTPAndHTTPs(resp http.ResponseWriter, req *http.R connOut, err := net.DialTimeout("tcp", host, time.Second*30) if err != nil { - logger.Println("dial to", host, "error:", err) + mylog.Println("dial to", host, "error:", err) return } if err = req.Write(connOut); err != nil { - logger.Println("send to server error", err) + mylog.Println("send to server error", err) return } respOut, err = http.ReadResponse(bufio.NewReader(connOut), req) if err != nil && err != io.EOF { - logger.Println("read response error:", err) + mylog.Println("read response error:", err) } } else { @@ -142,17 +157,17 @@ func (hw *HandlerWrapper) DumpHTTPAndHTTPs(resp http.ResponseWriter, req *http.R connOut, err := tls.Dial("tcp", host, hw.tlsConfig.ServerTLSConfig) if err != nil { - logger.Panicln("tls dial to", host, "error:", err) + mylog.Panicln("tls dial to", host, "error:", err) return } if err = req.Write(connOut); err != nil { - logger.Println("send to server error", err) + mylog.Println("send to server error", err) return } respOut, err = http.ReadResponse(bufio.NewReader(connOut), req) if err != nil && err != io.EOF { - logger.Println("read response error:", err) + mylog.Println("read response error:", err) } } @@ -164,26 +179,21 @@ func (hw *HandlerWrapper) DumpHTTPAndHTTPs(resp http.ResponseWriter, req *http.R respDump, err := httputil.DumpResponse(respOut, true) if err != nil { - logger.Println("respDump error:", err) + mylog.Println("respDump error:", err) } _, err = connIn.Write(respDump) if err != nil { - logger.Println("connIn write error:", err) + mylog.Println("connIn write error:", err) } if *hw.MyConfig.Monitor { - go httpDump(req, respOut) + go httpDump(reqTmp, respOut) } - } func (hw *HandlerWrapper) ServeHTTP(resp http.ResponseWriter, req *http.Request) { - err := req.ParseForm() - if err != nil { - logger.Println("parseForm error:", err) - } raddr := *hw.MyConfig.Raddr if len(raddr) != 0 { hw.Forward(resp, req, raddr) @@ -230,7 +240,7 @@ func (hw *HandlerWrapper) InterceptHTTPs(resp http.ResponseWriter, req *http.Req go func() { err = http.Serve(listener, handler) if err != nil && err != io.EOF { - logger.Printf("Error serving mitm'ed connection: %s", err) + mylog.Printf("Error serving mitm'ed connection: %s", err) } }() @@ -241,12 +251,12 @@ func (hw *HandlerWrapper) Forward(resp http.ResponseWriter, req *http.Request, r connIn, _, err := resp.(http.Hijacker).Hijack() connOut, err := net.Dial("tcp", raddr) if err != nil { - logger.Println("dial tcp error", err) + mylog.Println("dial tcp error", err) } err = connectProxyServer(connOut, raddr) if err != nil { - logger.Println("connectProxyServer error:", err) + mylog.Println("connectProxyServer error:", err) } if req.Method == "CONNECT" { @@ -254,24 +264,24 @@ func (hw *HandlerWrapper) Forward(resp http.ResponseWriter, req *http.Request, r "Proxy-Agent: gomitmproxy/" + Version + "\r\n\r\n") _, err := connIn.Write(b) if err != nil { - logger.Println("Write Connect err:", err) + mylog.Println("Write Connect err:", err) return } } else { req.Header.Del("Proxy-Connection") req.Header.Set("Connection", "Keep-Alive") if err = req.Write(connOut); err != nil { - logger.Println("send to server err", err) + mylog.Println("send to server err", err) return } } err = Transport(connIn, connOut) if err != nil { - log.Println("trans error ", err) + mylog.Println("trans error ", err) } } -func InitConfig(conf *Cfg, tlsConfig *TlsConfig) (*HandlerWrapper, error) { +func InitConfig(conf *config.Cfg, tlsConfig *config.TlsConfig) (*HandlerWrapper, error) { hw := &HandlerWrapper{ MyConfig: conf, tlsConfig: tlsConfig, @@ -292,6 +302,14 @@ func copyTlsConfig(template *tls.Config) *tls.Config { return tlsConfig } +func copyHTTPRequest(template *http.Request) *http.Request { + req := &http.Request{} + if template != nil { + *req = *template + } + return req +} + func respBadGateway(resp http.ResponseWriter, msg string) { log.Println(msg) resp.WriteHeader(502) @@ -320,7 +338,6 @@ func MyCopy(src io.Reader, dst io.Writer, ch chan<- error) { } func connectProxyServer(conn net.Conn, addr string) error { - req := &http.Request{ Method: "CONNECT", URL: &url.URL{Host: addr}, diff --git a/src/vendor/mylog/my_log.go b/src/vendor/mylog/my_log.go new file mode 100644 index 0000000..55e6a8c --- /dev/null +++ b/src/vendor/mylog/my_log.go @@ -0,0 +1,30 @@ +package mylog + +import "log" +import "io" + +var logger *log.Logger + +func SetLog(l io.WriteCloser) { + logger = log.New(l, "[gomitmproxy]", log.LstdFlags) +} + +func Fatalf(format string, v ...interface{}) { + logger.Fatalf(format, v) +} + +func Fatalln(v ...interface{}) { + logger.Fatalln(v) +} + +func Printf(format string, v ...interface{}) { + logger.Printf(format, v) +} + +func Println(v ...interface{}) { + logger.Println(v) +} + +func Panicln(v ...interface{}) { + logger.Panicln(v) +} diff --git a/src/vendor/mylog/my_log_test.go b/src/vendor/mylog/my_log_test.go new file mode 100644 index 0000000..e3698d1 --- /dev/null +++ b/src/vendor/mylog/my_log_test.go @@ -0,0 +1,17 @@ +package mylog + +import ( + "log" + "os" + "testing" +) + +func TestMyLog(t *testing.T) { + logFile, err := os.Create("test.log") + if err != nil { + log.Fatalln("fail to create log file!") + } + logger := log.New(logFile, "[gomitmproxy]", log.LstdFlags|log.Llongfile) + SetLog(logger) + Println("log test") +} diff --git a/src/vendor/mylog/test.log b/src/vendor/mylog/test.log new file mode 100644 index 0000000..2a76a76 --- /dev/null +++ b/src/vendor/mylog/test.log @@ -0,0 +1 @@ +[gomitmproxy]2017/04/03 00:00:25 /Users/bao/program/go/gowork/gomitmproxy/src/vendor/mylog/my_log.go:20: [log test]