code refactoring
@ -1,88 +0,0 @@
|
|||||||
package addon
|
|
||||||
|
|
||||||
import (
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/lqqyt2423/go-mitmproxy/connection"
|
|
||||||
"github.com/lqqyt2423/go-mitmproxy/flow"
|
|
||||||
_log "github.com/sirupsen/logrus"
|
|
||||||
)
|
|
||||||
|
|
||||||
var log = _log.WithField("at", "addon")
|
|
||||||
|
|
||||||
type Addon interface {
|
|
||||||
// A client has connected to mitmproxy. Note that a connection can correspond to multiple HTTP requests.
|
|
||||||
ClientConnected(*connection.Client)
|
|
||||||
|
|
||||||
// A client connection has been closed (either by us or the client).
|
|
||||||
ClientDisconnected(*connection.Client)
|
|
||||||
|
|
||||||
// Mitmproxy has connected to a server.
|
|
||||||
ServerConnected(*flow.ConnContext)
|
|
||||||
|
|
||||||
// A server connection has been closed (either by us or the server).
|
|
||||||
ServerDisconnected(*flow.ConnContext)
|
|
||||||
|
|
||||||
// HTTP request headers were successfully read. At this point, the body is empty.
|
|
||||||
Requestheaders(*flow.Flow)
|
|
||||||
|
|
||||||
// The full HTTP request has been read.
|
|
||||||
Request(*flow.Flow)
|
|
||||||
|
|
||||||
// HTTP response headers were successfully read. At this point, the body is empty.
|
|
||||||
Responseheaders(*flow.Flow)
|
|
||||||
|
|
||||||
// The full HTTP response has been read.
|
|
||||||
Response(*flow.Flow)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Base do nothing
|
|
||||||
type Base struct{}
|
|
||||||
|
|
||||||
func (addon *Base) ClientConnected(*connection.Client) {}
|
|
||||||
func (addon *Base) ClientDisconnected(*connection.Client) {}
|
|
||||||
func (addon *Base) ServerConnected(*flow.ConnContext) {}
|
|
||||||
func (addon *Base) ServerDisconnected(*flow.ConnContext) {}
|
|
||||||
|
|
||||||
func (addon *Base) Requestheaders(*flow.Flow) {}
|
|
||||||
func (addon *Base) Request(*flow.Flow) {}
|
|
||||||
func (addon *Base) Responseheaders(*flow.Flow) {}
|
|
||||||
func (addon *Base) Response(*flow.Flow) {}
|
|
||||||
|
|
||||||
// Log log http record
|
|
||||||
type Log struct {
|
|
||||||
Base
|
|
||||||
}
|
|
||||||
|
|
||||||
func (addon *Log) ClientConnected(client *connection.Client) {
|
|
||||||
log.Infof("%v client connect\n", client.Conn.RemoteAddr())
|
|
||||||
}
|
|
||||||
|
|
||||||
func (addon *Log) ClientDisconnected(client *connection.Client) {
|
|
||||||
log.Infof("%v client disconnect\n", client.Conn.RemoteAddr())
|
|
||||||
}
|
|
||||||
|
|
||||||
func (addon *Log) ServerConnected(connCtx *flow.ConnContext) {
|
|
||||||
log.Infof("%v server connect %v (%v)\n", connCtx.Client.Conn.RemoteAddr(), connCtx.Server.Address, connCtx.Server.Conn.RemoteAddr())
|
|
||||||
}
|
|
||||||
|
|
||||||
func (addon *Log) ServerDisconnected(connCtx *flow.ConnContext) {
|
|
||||||
log.Infof("%v server disconnect %v (%v)\n", connCtx.Client.Conn.RemoteAddr(), connCtx.Server.Address, connCtx.Server.Conn.RemoteAddr())
|
|
||||||
}
|
|
||||||
|
|
||||||
func (addon *Log) Requestheaders(f *flow.Flow) {
|
|
||||||
log := log.WithField("in", "Log")
|
|
||||||
start := time.Now()
|
|
||||||
go func() {
|
|
||||||
<-f.Done()
|
|
||||||
var StatusCode int
|
|
||||||
if f.Response != nil {
|
|
||||||
StatusCode = f.Response.StatusCode
|
|
||||||
}
|
|
||||||
var contentLen int
|
|
||||||
if f.Response != nil && f.Response.Body != nil {
|
|
||||||
contentLen = len(f.Response.Body)
|
|
||||||
}
|
|
||||||
log.Infof("%v %v %v %v %v - %v ms\n", f.ConnContext.Client.Conn.RemoteAddr(), f.Request.Method, f.Request.URL.String(), StatusCode, contentLen, time.Since(start).Milliseconds())
|
|
||||||
}()
|
|
||||||
}
|
|
@ -1,13 +1,13 @@
|
|||||||
package addon
|
package addon
|
||||||
|
|
||||||
import "github.com/lqqyt2423/go-mitmproxy/flow"
|
import "github.com/lqqyt2423/go-mitmproxy/proxy"
|
||||||
|
|
||||||
// decode content-encoding then respond to client
|
// decode content-encoding then respond to client
|
||||||
|
|
||||||
type Decoder struct {
|
type Decoder struct {
|
||||||
Base
|
proxy.BaseAddon
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *Decoder) Response(f *flow.Flow) {
|
func (d *Decoder) Response(f *proxy.Flow) {
|
||||||
f.Response.ReplaceToDecodedBody()
|
f.Response.ReplaceToDecodedBody()
|
||||||
}
|
}
|
||||||
|
@ -1,96 +0,0 @@
|
|||||||
package flowmapper
|
|
||||||
|
|
||||||
import (
|
|
||||||
"io/ioutil"
|
|
||||||
"path/filepath"
|
|
||||||
"regexp"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/lqqyt2423/go-mitmproxy/addon"
|
|
||||||
"github.com/lqqyt2423/go-mitmproxy/flow"
|
|
||||||
_log "github.com/sirupsen/logrus"
|
|
||||||
)
|
|
||||||
|
|
||||||
var log = _log.WithField("at", "changeflow addon")
|
|
||||||
var httpsRegexp = regexp.MustCompile(`^https://`)
|
|
||||||
|
|
||||||
type Mapper struct {
|
|
||||||
addon.Base
|
|
||||||
reqResMap map[string]*flow.Response
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewMapper(dirname string) *Mapper {
|
|
||||||
infos, err := ioutil.ReadDir(dirname)
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
filenames := make([]string, 0)
|
|
||||||
|
|
||||||
for _, info := range infos {
|
|
||||||
if info.IsDir() {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if !strings.HasSuffix(info.Name(), ".map.txt") {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
filenames = append(filenames, filepath.Join(dirname, info.Name()))
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(filenames) == 0 {
|
|
||||||
return &Mapper{
|
|
||||||
reqResMap: make(map[string]*flow.Response),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ch := make(chan interface{}, len(filenames))
|
|
||||||
for _, filename := range filenames {
|
|
||||||
go func(filename string, ch chan<- interface{}) {
|
|
||||||
f, err := ParseFlowFromFile(filename)
|
|
||||||
if err != nil {
|
|
||||||
log.Error(err)
|
|
||||||
ch <- err
|
|
||||||
return
|
|
||||||
}
|
|
||||||
ch <- f
|
|
||||||
}(filename, ch)
|
|
||||||
}
|
|
||||||
|
|
||||||
reqResMap := make(map[string]*flow.Response)
|
|
||||||
|
|
||||||
for i := 0; i < len(filenames); i++ {
|
|
||||||
flowOrErr := <-ch
|
|
||||||
if f, ok := flowOrErr.(*flow.Flow); ok {
|
|
||||||
key := buildReqKey(f.Request)
|
|
||||||
log.Infof("add request mapper: %v", key)
|
|
||||||
reqResMap[key] = f.Response
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return &Mapper{
|
|
||||||
reqResMap: reqResMap,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func ParseFlowFromFile(filename string) (*flow.Flow, error) {
|
|
||||||
p, err := NewParserFromFile(filename)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return p.Parse()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Mapper) Request(f *flow.Flow) {
|
|
||||||
key := buildReqKey(f.Request)
|
|
||||||
if resp, ok := c.reqResMap[key]; ok {
|
|
||||||
f.Response = resp
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func buildReqKey(req *flow.Request) string {
|
|
||||||
url := req.URL.String()
|
|
||||||
url = httpsRegexp.ReplaceAllString(url, "http://")
|
|
||||||
key := req.Method + " " + url
|
|
||||||
return key
|
|
||||||
}
|
|
@ -1,35 +0,0 @@
|
|||||||
package connection
|
|
||||||
|
|
||||||
import (
|
|
||||||
"net"
|
|
||||||
"net/http"
|
|
||||||
|
|
||||||
uuid "github.com/satori/go.uuid"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Client struct {
|
|
||||||
Id uuid.UUID
|
|
||||||
Conn net.Conn
|
|
||||||
Tls bool
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewClient(c net.Conn) *Client {
|
|
||||||
return &Client{
|
|
||||||
Id: uuid.NewV4(),
|
|
||||||
Conn: c,
|
|
||||||
Tls: false,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
type Server struct {
|
|
||||||
Id uuid.UUID
|
|
||||||
Conn net.Conn
|
|
||||||
Client *http.Client
|
|
||||||
Address string
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewServer() *Server {
|
|
||||||
return &Server{
|
|
||||||
Id: uuid.NewV4(),
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,119 +0,0 @@
|
|||||||
package flow
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"crypto/tls"
|
|
||||||
"net"
|
|
||||||
"net/http"
|
|
||||||
|
|
||||||
"github.com/lqqyt2423/go-mitmproxy/connection"
|
|
||||||
)
|
|
||||||
|
|
||||||
var ConnContextKey = new(struct{})
|
|
||||||
|
|
||||||
type ConnContext struct {
|
|
||||||
Client *connection.Client
|
|
||||||
Server *connection.Server
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewConnContext(c net.Conn) *ConnContext {
|
|
||||||
client := connection.NewClient(c)
|
|
||||||
return &ConnContext{
|
|
||||||
Client: client,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (connCtx *ConnContext) InitHttpServer(sslInsecure bool, connWrap func(net.Conn) net.Conn, whenConnected func()) {
|
|
||||||
if connCtx.Server != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if connCtx.Client.Tls {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
server := connection.NewServer()
|
|
||||||
server.Client = &http.Client{
|
|
||||||
Transport: &http.Transport{
|
|
||||||
Proxy: http.ProxyFromEnvironment,
|
|
||||||
|
|
||||||
// todo: change here
|
|
||||||
DialContext: func(ctx context.Context, network, addr string) (net.Conn, error) {
|
|
||||||
c, err := (&net.Dialer{
|
|
||||||
// Timeout: 30 * time.Second,
|
|
||||||
// KeepAlive: 30 * time.Second,
|
|
||||||
}).DialContext(ctx, network, addr)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
cw := connWrap(c)
|
|
||||||
server.Conn = cw
|
|
||||||
server.Address = addr
|
|
||||||
defer whenConnected()
|
|
||||||
return cw, nil
|
|
||||||
},
|
|
||||||
ForceAttemptHTTP2: false, // disable http2
|
|
||||||
|
|
||||||
DisableCompression: true, // To get the original response from the server, set Transport.DisableCompression to true.
|
|
||||||
TLSClientConfig: &tls.Config{
|
|
||||||
InsecureSkipVerify: sslInsecure,
|
|
||||||
KeyLogWriter: GetTlsKeyLogWriter(),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
CheckRedirect: func(req *http.Request, via []*http.Request) error {
|
|
||||||
// 禁止自动重定向
|
|
||||||
return http.ErrUseLastResponse
|
|
||||||
},
|
|
||||||
}
|
|
||||||
connCtx.Server = server
|
|
||||||
}
|
|
||||||
|
|
||||||
func (connCtx *ConnContext) InitHttpsServer(sslInsecure bool, connWrap func(net.Conn) net.Conn, whenConnected func()) {
|
|
||||||
if connCtx.Server != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if !connCtx.Client.Tls {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
server := connection.NewServer()
|
|
||||||
server.Client = &http.Client{
|
|
||||||
Transport: &http.Transport{
|
|
||||||
Proxy: http.ProxyFromEnvironment,
|
|
||||||
|
|
||||||
DialTLSContext: func(ctx context.Context, network, addr string) (net.Conn, error) {
|
|
||||||
log.Debugln("in https DialTLSContext")
|
|
||||||
|
|
||||||
plainConn, err := (&net.Dialer{}).DialContext(ctx, network, addr)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
cw := connWrap(plainConn)
|
|
||||||
server.Conn = cw
|
|
||||||
server.Address = addr
|
|
||||||
whenConnected()
|
|
||||||
|
|
||||||
firstTLSHost, _, err := net.SplitHostPort(addr)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
cfg := &tls.Config{
|
|
||||||
InsecureSkipVerify: sslInsecure,
|
|
||||||
KeyLogWriter: GetTlsKeyLogWriter(),
|
|
||||||
ServerName: firstTLSHost,
|
|
||||||
}
|
|
||||||
tlsConn := tls.Client(cw, cfg)
|
|
||||||
return tlsConn, nil
|
|
||||||
},
|
|
||||||
ForceAttemptHTTP2: false, // disable http2
|
|
||||||
|
|
||||||
DisableCompression: true, // To get the original response from the server, set Transport.DisableCompression to true.
|
|
||||||
},
|
|
||||||
CheckRedirect: func(req *http.Request, via []*http.Request) error {
|
|
||||||
// 禁止自动重定向
|
|
||||||
return http.ErrUseLastResponse
|
|
||||||
},
|
|
||||||
}
|
|
||||||
connCtx.Server = server
|
|
||||||
}
|
|
@ -1,29 +0,0 @@
|
|||||||
package flow
|
|
||||||
|
|
||||||
import (
|
|
||||||
"io"
|
|
||||||
"os"
|
|
||||||
"sync"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Wireshark 解析 https 设置
|
|
||||||
var tlsKeyLogWriter io.Writer
|
|
||||||
var tlsKeyLogOnce sync.Once
|
|
||||||
|
|
||||||
func GetTlsKeyLogWriter() io.Writer {
|
|
||||||
tlsKeyLogOnce.Do(func() {
|
|
||||||
logfile := os.Getenv("SSLKEYLOGFILE")
|
|
||||||
if logfile == "" {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
writer, err := os.OpenFile(logfile, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0666)
|
|
||||||
if err != nil {
|
|
||||||
log.WithField("in", "GetTlsKeyLogWriter").Debug(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
tlsKeyLogWriter = writer
|
|
||||||
})
|
|
||||||
return tlsKeyLogWriter
|
|
||||||
}
|
|
@ -0,0 +1,81 @@
|
|||||||
|
package proxy
|
||||||
|
|
||||||
|
import (
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Addon interface {
|
||||||
|
// A client has connected to mitmproxy. Note that a connection can correspond to multiple HTTP requests.
|
||||||
|
ClientConnected(*ClientConn)
|
||||||
|
|
||||||
|
// A client connection has been closed (either by us or the client).
|
||||||
|
ClientDisconnected(*ClientConn)
|
||||||
|
|
||||||
|
// Mitmproxy has connected to a server.
|
||||||
|
ServerConnected(*ConnContext)
|
||||||
|
|
||||||
|
// A server connection has been closed (either by us or the server).
|
||||||
|
ServerDisconnected(*ConnContext)
|
||||||
|
|
||||||
|
// HTTP request headers were successfully read. At this point, the body is empty.
|
||||||
|
Requestheaders(*Flow)
|
||||||
|
|
||||||
|
// The full HTTP request has been read.
|
||||||
|
Request(*Flow)
|
||||||
|
|
||||||
|
// HTTP response headers were successfully read. At this point, the body is empty.
|
||||||
|
Responseheaders(*Flow)
|
||||||
|
|
||||||
|
// The full HTTP response has been read.
|
||||||
|
Response(*Flow)
|
||||||
|
}
|
||||||
|
|
||||||
|
// BaseAddon do nothing
|
||||||
|
type BaseAddon struct{}
|
||||||
|
|
||||||
|
func (addon *BaseAddon) ClientConnected(*ClientConn) {}
|
||||||
|
func (addon *BaseAddon) ClientDisconnected(*ClientConn) {}
|
||||||
|
func (addon *BaseAddon) ServerConnected(*ConnContext) {}
|
||||||
|
func (addon *BaseAddon) ServerDisconnected(*ConnContext) {}
|
||||||
|
|
||||||
|
func (addon *BaseAddon) Requestheaders(*Flow) {}
|
||||||
|
func (addon *BaseAddon) Request(*Flow) {}
|
||||||
|
func (addon *BaseAddon) Responseheaders(*Flow) {}
|
||||||
|
func (addon *BaseAddon) Response(*Flow) {}
|
||||||
|
|
||||||
|
// LogAddon log connection and flow
|
||||||
|
type LogAddon struct {
|
||||||
|
BaseAddon
|
||||||
|
}
|
||||||
|
|
||||||
|
func (addon *LogAddon) ClientConnected(client *ClientConn) {
|
||||||
|
log.Infof("%v client connect\n", client.Conn.RemoteAddr())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (addon *LogAddon) ClientDisconnected(client *ClientConn) {
|
||||||
|
log.Infof("%v client disconnect\n", client.Conn.RemoteAddr())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (addon *LogAddon) ServerConnected(connCtx *ConnContext) {
|
||||||
|
log.Infof("%v server connect %v (%v)\n", connCtx.ClientConn.Conn.RemoteAddr(), connCtx.ServerConn.Address, connCtx.ServerConn.Conn.RemoteAddr())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (addon *LogAddon) ServerDisconnected(connCtx *ConnContext) {
|
||||||
|
log.Infof("%v server disconnect %v (%v)\n", connCtx.ClientConn.Conn.RemoteAddr(), connCtx.ServerConn.Address, connCtx.ServerConn.Conn.RemoteAddr())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (addon *LogAddon) Requestheaders(f *Flow) {
|
||||||
|
start := time.Now()
|
||||||
|
go func() {
|
||||||
|
<-f.Done()
|
||||||
|
var StatusCode int
|
||||||
|
if f.Response != nil {
|
||||||
|
StatusCode = f.Response.StatusCode
|
||||||
|
}
|
||||||
|
var contentLen int
|
||||||
|
if f.Response != nil && f.Response.Body != nil {
|
||||||
|
contentLen = len(f.Response.Body)
|
||||||
|
}
|
||||||
|
log.Infof("%v %v %v %v %v - %v ms\n", f.ConnContext.ClientConn.Conn.RemoteAddr(), f.Request.Method, f.Request.URL.String(), StatusCode, contentLen, time.Since(start).Milliseconds())
|
||||||
|
}()
|
||||||
|
}
|
@ -0,0 +1,232 @@
|
|||||||
|
package proxy
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"crypto/tls"
|
||||||
|
"net"
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
uuid "github.com/satori/go.uuid"
|
||||||
|
)
|
||||||
|
|
||||||
|
// client connection
|
||||||
|
type ClientConn struct {
|
||||||
|
Id uuid.UUID
|
||||||
|
Conn net.Conn
|
||||||
|
Tls bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func newClientConn(c net.Conn) *ClientConn {
|
||||||
|
return &ClientConn{
|
||||||
|
Id: uuid.NewV4(),
|
||||||
|
Conn: c,
|
||||||
|
Tls: false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// server connection
|
||||||
|
type ServerConn struct {
|
||||||
|
Id uuid.UUID
|
||||||
|
Address string
|
||||||
|
Conn net.Conn
|
||||||
|
|
||||||
|
client *http.Client
|
||||||
|
}
|
||||||
|
|
||||||
|
func newServerConn() *ServerConn {
|
||||||
|
return &ServerConn{
|
||||||
|
Id: uuid.NewV4(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// connection context ctx key
|
||||||
|
var connContextKey = new(struct{})
|
||||||
|
|
||||||
|
// connection context
|
||||||
|
type ConnContext struct {
|
||||||
|
ClientConn *ClientConn
|
||||||
|
ServerConn *ServerConn
|
||||||
|
|
||||||
|
proxy *Proxy
|
||||||
|
}
|
||||||
|
|
||||||
|
func newConnContext(c net.Conn, proxy *Proxy) *ConnContext {
|
||||||
|
clientConn := newClientConn(c)
|
||||||
|
return &ConnContext{
|
||||||
|
ClientConn: clientConn,
|
||||||
|
proxy: proxy,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (connCtx *ConnContext) InitHttpServerConn() {
|
||||||
|
if connCtx.ServerConn != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if connCtx.ClientConn.Tls {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
serverConn := newServerConn()
|
||||||
|
serverConn.client = &http.Client{
|
||||||
|
Transport: &http.Transport{
|
||||||
|
Proxy: http.ProxyFromEnvironment,
|
||||||
|
DialContext: func(ctx context.Context, network, addr string) (net.Conn, error) {
|
||||||
|
c, err := (&net.Dialer{}).DialContext(ctx, network, addr)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
cw := &wrapServerConn{
|
||||||
|
Conn: c,
|
||||||
|
proxy: connCtx.proxy,
|
||||||
|
connCtx: connCtx,
|
||||||
|
}
|
||||||
|
serverConn.Conn = cw
|
||||||
|
serverConn.Address = addr
|
||||||
|
defer func() {
|
||||||
|
for _, addon := range connCtx.proxy.Addons {
|
||||||
|
addon.ServerConnected(connCtx)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
return cw, nil
|
||||||
|
},
|
||||||
|
ForceAttemptHTTP2: false, // disable http2
|
||||||
|
DisableCompression: true, // To get the original response from the server, set Transport.DisableCompression to true.
|
||||||
|
TLSClientConfig: &tls.Config{
|
||||||
|
InsecureSkipVerify: connCtx.proxy.Opts.SslInsecure,
|
||||||
|
KeyLogWriter: getTlsKeyLogWriter(),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
CheckRedirect: func(req *http.Request, via []*http.Request) error {
|
||||||
|
// 禁止自动重定向
|
||||||
|
return http.ErrUseLastResponse
|
||||||
|
},
|
||||||
|
}
|
||||||
|
connCtx.ServerConn = serverConn
|
||||||
|
}
|
||||||
|
|
||||||
|
func (connCtx *ConnContext) InitHttpsServerConn() {
|
||||||
|
if connCtx.ServerConn != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if !connCtx.ClientConn.Tls {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
ServerConn := newServerConn()
|
||||||
|
ServerConn.client = &http.Client{
|
||||||
|
Transport: &http.Transport{
|
||||||
|
Proxy: http.ProxyFromEnvironment,
|
||||||
|
DialTLSContext: func(ctx context.Context, network, addr string) (net.Conn, error) {
|
||||||
|
log.Debugln("in https DialTLSContext")
|
||||||
|
plainConn, err := (&net.Dialer{}).DialContext(ctx, network, addr)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
cw := &wrapServerConn{
|
||||||
|
Conn: plainConn,
|
||||||
|
proxy: connCtx.proxy,
|
||||||
|
connCtx: connCtx,
|
||||||
|
}
|
||||||
|
ServerConn.Conn = cw
|
||||||
|
ServerConn.Address = addr
|
||||||
|
|
||||||
|
for _, addon := range connCtx.proxy.Addons {
|
||||||
|
addon.ServerConnected(connCtx)
|
||||||
|
}
|
||||||
|
|
||||||
|
firstTLSHost, _, err := net.SplitHostPort(addr)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
cfg := &tls.Config{
|
||||||
|
InsecureSkipVerify: connCtx.proxy.Opts.SslInsecure,
|
||||||
|
KeyLogWriter: getTlsKeyLogWriter(),
|
||||||
|
ServerName: firstTLSHost,
|
||||||
|
}
|
||||||
|
tlsConn := tls.Client(cw, cfg)
|
||||||
|
return tlsConn, nil
|
||||||
|
},
|
||||||
|
ForceAttemptHTTP2: false, // disable http2
|
||||||
|
DisableCompression: true, // To get the original response from the server, set Transport.DisableCompression to true.
|
||||||
|
},
|
||||||
|
CheckRedirect: func(req *http.Request, via []*http.Request) error {
|
||||||
|
// 禁止自动重定向
|
||||||
|
return http.ErrUseLastResponse
|
||||||
|
},
|
||||||
|
}
|
||||||
|
connCtx.ServerConn = ServerConn
|
||||||
|
}
|
||||||
|
|
||||||
|
// wrap tcpConn for remote client
|
||||||
|
type wrapClientConn struct {
|
||||||
|
net.Conn
|
||||||
|
proxy *Proxy
|
||||||
|
connCtx *ConnContext
|
||||||
|
closed bool
|
||||||
|
closeErr error
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *wrapClientConn) Close() error {
|
||||||
|
log.Debugln("in wrapClientConn close")
|
||||||
|
if c.closed {
|
||||||
|
return c.closeErr
|
||||||
|
}
|
||||||
|
|
||||||
|
c.closed = true
|
||||||
|
c.closeErr = c.Conn.Close()
|
||||||
|
|
||||||
|
for _, addon := range c.proxy.Addons {
|
||||||
|
addon.ClientDisconnected(c.connCtx.ClientConn)
|
||||||
|
}
|
||||||
|
|
||||||
|
if c.connCtx.ServerConn != nil && c.connCtx.ServerConn.Conn != nil {
|
||||||
|
c.connCtx.ServerConn.Conn.Close()
|
||||||
|
}
|
||||||
|
|
||||||
|
return c.closeErr
|
||||||
|
}
|
||||||
|
|
||||||
|
// wrap tcpListener for remote client
|
||||||
|
type wrapListener struct {
|
||||||
|
net.Listener
|
||||||
|
proxy *Proxy
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *wrapListener) Accept() (net.Conn, error) {
|
||||||
|
c, err := l.Listener.Accept()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &wrapClientConn{
|
||||||
|
Conn: c,
|
||||||
|
proxy: l.proxy,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// wrap tcpConn for remote server
|
||||||
|
type wrapServerConn struct {
|
||||||
|
net.Conn
|
||||||
|
proxy *Proxy
|
||||||
|
connCtx *ConnContext
|
||||||
|
closed bool
|
||||||
|
closeErr error
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *wrapServerConn) Close() error {
|
||||||
|
log.Debugln("in wrapServerConn close")
|
||||||
|
if c.closed {
|
||||||
|
return c.closeErr
|
||||||
|
}
|
||||||
|
|
||||||
|
c.closed = true
|
||||||
|
c.closeErr = c.Conn.Close()
|
||||||
|
|
||||||
|
for _, addon := range c.proxy.Addons {
|
||||||
|
addon.ServerDisconnected(c.connCtx)
|
||||||
|
}
|
||||||
|
|
||||||
|
c.connCtx.ClientConn.Conn.Close()
|
||||||
|
|
||||||
|
return c.closeErr
|
||||||
|
}
|
Before Width: | Height: | Size: 3.8 KiB After Width: | Height: | Size: 3.8 KiB |
Before Width: | Height: | Size: 5.2 KiB After Width: | Height: | Size: 5.2 KiB |
Before Width: | Height: | Size: 9.4 KiB After Width: | Height: | Size: 9.4 KiB |
Before Width: | Height: | Size: 3.8 KiB After Width: | Height: | Size: 3.8 KiB |
Before Width: | Height: | Size: 5.2 KiB After Width: | Height: | Size: 5.2 KiB |
Before Width: | Height: | Size: 9.4 KiB After Width: | Height: | Size: 9.4 KiB |