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