重构代码

main
sheepbao 8 years ago
parent 1c14528edc
commit d132001d32
  1. 2
      build.sh
  2. 84
      gomitmproxy.go
  3. 4
      readme.md
  4. 0
      src/doc/goproxy.png
  5. 0
      src/doc/proxy.png
  6. 41
      src/main/main.go
  7. 2
      src/vendor/color/tcolor.go
  8. 14
      src/vendor/config/config.go
  9. 2
      src/vendor/mitm/cache.go
  10. 32
      src/vendor/mitm/dump.go
  11. 9
      src/vendor/mitm/genKey.go
  12. 48
      src/vendor/mitm/gomitmproxy.go
  13. 2
      src/vendor/mitm/listener.go
  14. 69
      src/vendor/mitm/mitm.go
  15. 30
      src/vendor/mylog/my_log.go
  16. 17
      src/vendor/mylog/my_log_test.go
  17. 1
      src/vendor/mylog/test.log

@ -0,0 +1,2 @@
export GOPATH=`pwd`
go build -o bin/gomitmproxy src/main/*.go

@ -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
}

@ -40,7 +40,7 @@ gomitmproxy
gomitmproxy -m 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请求和响应 加 -m 参数,表示抓取http请求和响应
@ -59,7 +59,7 @@ gomitmproxy -m
``` ```
然后浏览器设置代理,ip为localhost,端口为8080,即可实现科学上网 然后浏览器设置代理,ip为localhost,端口为8080,即可实现科学上网
![proxy](https://raw.githubusercontent.com/sheepbao/gomitmproxy/master/proxy.png) ![proxy](https://raw.githubusercontent.com/sheepbao/gomitmproxy/develop/doc/proxy.png)
## 最后 ## 最后

Before

Width:  |  Height:  |  Size: 1.5 MiB

After

Width:  |  Height:  |  Size: 1.5 MiB

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 14 KiB

@ -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()
}

@ -1,4 +1,4 @@
package main package color
import ( import (
"fmt" "fmt"

@ -1,16 +1,6 @@
package main package config
import ( import "crypto/tls"
"crypto/tls"
"time"
)
const (
ONE_DAY = 24 * time.Hour
TWO_WEEKS = ONE_DAY * 14
ONE_MONTH = 1
ONE_YEAR = 1
)
type Cfg struct { type Cfg struct {
Port *string Port *string

@ -1,6 +1,6 @@
// package cache implements a really primitive cache that associates expiring // package cache implements a really primitive cache that associates expiring
// values with string keys. This cache never clears itself out. // values with string keys. This cache never clears itself out.
package main package mitm
import ( import (
"sync" "sync"

@ -1,13 +1,15 @@
package main package mitm
import ( import (
"bufio" "bufio"
"bytes" "bytes"
"color"
"compress/flate" "compress/flate"
"compress/gzip" "compress/gzip"
"fmt" "fmt"
"io/ioutil" "io/ioutil"
"math" "math"
"mylog"
"net/http" "net/http"
"strconv" "strconv"
) )
@ -19,35 +21,35 @@ func httpDump(req *http.Request, resp *http.Response) {
respStatusHeader := int(math.Floor(float64(respStatus / 100))) respStatusHeader := int(math.Floor(float64(respStatus / 100)))
switch respStatusHeader { switch respStatusHeader {
case 2: case 2:
respStatusStr = Green("<--" + strconv.Itoa(respStatus)) respStatusStr = color.Green("<--" + strconv.Itoa(respStatus))
case 3: case 3:
respStatusStr = Yellow("<--" + strconv.Itoa(respStatus)) respStatusStr = color.Yellow("<--" + strconv.Itoa(respStatus))
case 4: case 4:
respStatusStr = Magenta("<--" + strconv.Itoa(respStatus)) respStatusStr = color.Magenta("<--" + strconv.Itoa(respStatus))
case 5: case 5:
respStatusStr = Red("<--" + strconv.Itoa(respStatus)) respStatusStr = color.Red("<--" + strconv.Itoa(respStatus))
} }
fmt.Println(Green("Request:")) fmt.Println(color.Green("Request:"))
fmt.Printf("%s %s %s\n", Blue(req.Method), req.RequestURI, respStatusStr) fmt.Printf("%s %s %s\n", color.Blue(req.Method), req.RequestURI, respStatusStr)
for headerName, headerContext := range req.Header { 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" { if req.Method == "POST" {
fmt.Println(Green("URLEncoded form")) fmt.Println(color.Green("URLEncoded form"))
for k, v := range req.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 { 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) respBody, err := ioutil.ReadAll(resp.Body)
if err != nil { if err != nil {
logger.Println("func httpDump read resp body err:", err) mylog.Println("func httpDump read resp body err:", err)
} else { } else {
acceptEncode := resp.Header["Content-Encoding"] acceptEncode := resp.Header["Content-Encoding"]
var respBodyBin bytes.Buffer var respBodyBin bytes.Buffer
@ -59,7 +61,7 @@ func httpDump(req *http.Request, resp *http.Response) {
case "gzip": case "gzip":
r, err := gzip.NewReader(&respBodyBin) r, err := gzip.NewReader(&respBodyBin)
if err != nil { if err != nil {
logger.Println("gzip reader err:", err) mylog.Println("gzip reader err:", err)
} else { } else {
defer r.Close() defer r.Close()
respBody, _ = ioutil.ReadAll(r) 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\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("####################"))
} }

@ -1,5 +1,5 @@
// Package keyman provides convenience APIs around Go's built-in crypto APIs. // Package keyman provides convenience APIs around Go's built-in crypto APIs.
package main package mitm
import ( import (
"crypto/rand" "crypto/rand"
@ -10,6 +10,7 @@ import (
"fmt" "fmt"
"io/ioutil" "io/ioutil"
"math/big" "math/big"
"mylog"
"net" "net"
"os" "os"
"time" "time"
@ -85,7 +86,7 @@ func (key *PrivateKey) WriteToFile(filename string) (err error) {
return fmt.Errorf("Unable to PEM encode private key: %s", err) return fmt.Errorf("Unable to PEM encode private key: %s", err)
} }
if err := keyOut.Close(); err != nil { if err := keyOut.Close(); err != nil {
logger.Printf("Unable to close file: %v", err) mylog.Printf("Unable to close file: %v", err)
} }
return return
} }
@ -236,7 +237,7 @@ func (cert *Certificate) WriteToFile(filename string) (err error) {
} }
defer func() { defer func() {
if err := certOut.Close(); err != nil { 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()) return pem.Encode(certOut, cert.pemBlock())
@ -264,7 +265,7 @@ func (cert *Certificate) WriteToDERFile(filename string) (err error) {
} }
defer func() { defer func() {
if err := certOut.Close(); err != nil { 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) _, err = certOut.Write(cert.derBytes)

@ -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
}

@ -1,4 +1,4 @@
package main package mitm
import ( import (
"io" "io"

@ -1,12 +1,14 @@
package main package mitm
import ( import (
"bufio" "bufio"
"config"
"crypto/tls" "crypto/tls"
"errors" "errors"
"fmt" "fmt"
"io" "io"
"log" "log"
"mylog"
"net" "net"
"net/http" "net/http"
"net/http/httputil" "net/http/httputil"
@ -17,9 +19,17 @@ import (
"time" "time"
) )
const (
Version = "1.1"
ONE_DAY = 24 * time.Hour
TWO_WEEKS = ONE_DAY * 14
ONE_MONTH = 1
ONE_YEAR = 1
)
type HandlerWrapper struct { type HandlerWrapper struct {
MyConfig *Cfg MyConfig *config.Cfg
tlsConfig *TlsConfig tlsConfig *config.TlsConfig
wrapped http.Handler wrapped http.Handler
pk *PrivateKey pk *PrivateKey
pkPem []byte 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) { func (hw *HandlerWrapper) DumpHTTPAndHTTPs(resp http.ResponseWriter, req *http.Request) {
req.Header.Del("Proxy-Connection") req.Header.Del("Proxy-Connection")
req.Header.Set("Connection", "Keep-Alive") req.Header.Set("Connection", "Keep-Alive")
reqTmp := copyHTTPRequest(req)
err := reqTmp.ParseForm()
if err != nil {
mylog.Println("parseForm error:", err)
}
// handle connection // handle connection
connIn, _, err := resp.(http.Hijacker).Hijack() connIn, _, err := resp.(http.Hijacker).Hijack()
if err != nil { if err != nil {
logger.Println("hijack error:", err) mylog.Println("hijack error:", err)
} }
defer connIn.Close() 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) connOut, err := net.DialTimeout("tcp", host, time.Second*30)
if err != nil { if err != nil {
logger.Println("dial to", host, "error:", err) mylog.Println("dial to", host, "error:", err)
return return
} }
if err = req.Write(connOut); err != nil { if err = req.Write(connOut); err != nil {
logger.Println("send to server error", err) mylog.Println("send to server error", err)
return return
} }
respOut, err = http.ReadResponse(bufio.NewReader(connOut), req) respOut, err = http.ReadResponse(bufio.NewReader(connOut), req)
if err != nil && err != io.EOF { if err != nil && err != io.EOF {
logger.Println("read response error:", err) mylog.Println("read response error:", err)
} }
} else { } else {
@ -142,17 +157,17 @@ func (hw *HandlerWrapper) DumpHTTPAndHTTPs(resp http.ResponseWriter, req *http.R
connOut, err := tls.Dial("tcp", host, hw.tlsConfig.ServerTLSConfig) connOut, err := tls.Dial("tcp", host, hw.tlsConfig.ServerTLSConfig)
if err != nil { if err != nil {
logger.Panicln("tls dial to", host, "error:", err) mylog.Panicln("tls dial to", host, "error:", err)
return return
} }
if err = req.Write(connOut); err != nil { if err = req.Write(connOut); err != nil {
logger.Println("send to server error", err) mylog.Println("send to server error", err)
return return
} }
respOut, err = http.ReadResponse(bufio.NewReader(connOut), req) respOut, err = http.ReadResponse(bufio.NewReader(connOut), req)
if err != nil && err != io.EOF { 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) respDump, err := httputil.DumpResponse(respOut, true)
if err != nil { if err != nil {
logger.Println("respDump error:", err) mylog.Println("respDump error:", err)
} }
_, err = connIn.Write(respDump) _, err = connIn.Write(respDump)
if err != nil { if err != nil {
logger.Println("connIn write error:", err) mylog.Println("connIn write error:", err)
} }
if *hw.MyConfig.Monitor { if *hw.MyConfig.Monitor {
go httpDump(req, respOut) go httpDump(reqTmp, respOut)
} }
} }
func (hw *HandlerWrapper) ServeHTTP(resp http.ResponseWriter, req *http.Request) { 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 raddr := *hw.MyConfig.Raddr
if len(raddr) != 0 { if len(raddr) != 0 {
hw.Forward(resp, req, raddr) hw.Forward(resp, req, raddr)
@ -230,7 +240,7 @@ func (hw *HandlerWrapper) InterceptHTTPs(resp http.ResponseWriter, req *http.Req
go func() { go func() {
err = http.Serve(listener, handler) err = http.Serve(listener, handler)
if err != nil && err != io.EOF { 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() connIn, _, err := resp.(http.Hijacker).Hijack()
connOut, err := net.Dial("tcp", raddr) connOut, err := net.Dial("tcp", raddr)
if err != nil { if err != nil {
logger.Println("dial tcp error", err) mylog.Println("dial tcp error", err)
} }
err = connectProxyServer(connOut, raddr) err = connectProxyServer(connOut, raddr)
if err != nil { if err != nil {
logger.Println("connectProxyServer error:", err) mylog.Println("connectProxyServer error:", err)
} }
if req.Method == "CONNECT" { 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") "Proxy-Agent: gomitmproxy/" + Version + "\r\n\r\n")
_, err := connIn.Write(b) _, err := connIn.Write(b)
if err != nil { if err != nil {
logger.Println("Write Connect err:", err) mylog.Println("Write Connect err:", err)
return return
} }
} else { } else {
req.Header.Del("Proxy-Connection") req.Header.Del("Proxy-Connection")
req.Header.Set("Connection", "Keep-Alive") req.Header.Set("Connection", "Keep-Alive")
if err = req.Write(connOut); err != nil { if err = req.Write(connOut); err != nil {
logger.Println("send to server err", err) mylog.Println("send to server err", err)
return return
} }
} }
err = Transport(connIn, connOut) err = Transport(connIn, connOut)
if err != nil { 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{ hw := &HandlerWrapper{
MyConfig: conf, MyConfig: conf,
tlsConfig: tlsConfig, tlsConfig: tlsConfig,
@ -292,6 +302,14 @@ func copyTlsConfig(template *tls.Config) *tls.Config {
return tlsConfig 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) { func respBadGateway(resp http.ResponseWriter, msg string) {
log.Println(msg) log.Println(msg)
resp.WriteHeader(502) 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 { func connectProxyServer(conn net.Conn, addr string) error {
req := &http.Request{ req := &http.Request{
Method: "CONNECT", Method: "CONNECT",
URL: &url.URL{Host: addr}, URL: &url.URL{Host: addr},

@ -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)
}

@ -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")
}

@ -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]
Loading…
Cancel
Save