diff --git a/.idea/modules.xml b/.idea/modules.xml index 894984f..e8e9535 100644 --- a/.idea/modules.xml +++ b/.idea/modules.xml @@ -2,7 +2,7 @@ - + \ No newline at end of file diff --git a/.idea/socks2https.iml b/.idea/proxy.iml similarity index 100% rename from .idea/socks2https.iml rename to .idea/proxy.iml diff --git a/config/ca/ca.crt b/config/ca/ca.crt deleted file mode 100644 index efb7335..0000000 --- a/config/ca/ca.crt +++ /dev/null @@ -1,22 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIDuzCCAqOgAwIBAgIQBbdO7vYmnqfQFuurcuTtdDANBgkqhkiG9w0BAQsFADB2 -MQswCQYDVQQGEwJVUzENMAsGA1UECBMEVXRhaDENMAsGA1UEBxMETGVoaTEXMBUG -A1UEChMORGlnaUNlcnQsIEluYy4xGTAXBgNVBAMTEHd3dy5kaWdpY2VydC5jb20x -FTATBgNVBAUTDDUyOTk1MzctMDE0MjAeFw0yNDA5MDkxMjM1MjdaFw0yNTA5MDkx -MjM1MjdaMHYxCzAJBgNVBAYTAlVTMQ0wCwYDVQQIEwRVdGFoMQ0wCwYDVQQHEwRM -ZWhpMRcwFQYDVQQKEw5EaWdpQ2VydCwgSW5jLjEZMBcGA1UEAxMQd3d3LmRpZ2lj -ZXJ0LmNvbTEVMBMGA1UEBRMMNTI5OTUzNy0wMTQyMIIBIjANBgkqhkiG9w0BAQEF -AAOCAQ8AMIIBCgKCAQEAt7+4AMVcG3L2J2VetGobBLqVgUOitr81Y2JNo9HQYjWM -e6WVaB2p/4YFaIx9VojgmnQQiHPjUdJQt4nNNhRUtiB3dgedyCL80vH2Q/rDK/vi -EZdK1KHdW5IXsH7ZwFJ/2QYW8ynw58Q+JEMjXTjFMGsonskzF0/GmXVYUow1TJ9L -EEph6ePawe/NGL17I1qMqeuY1zJJB5gPTrArVcZiAoRH5I/hrFAxcOgbIBqDK378 -NA067V/z9dOVKQOGUiVcLrKLPELp7I7xOHAd74bFFAWbxbMup4xvg5c4JuYsvadO -ot0JzMZq6JUbV3qhl9pdjxftgrNxZUzjSTLoHvHvuQIDAQABo0UwQzAOBgNVHQ8B -Af8EBAMCBaAwEgYDVR0TAQH/BAgwBgEB/wIBADAdBgNVHQ4EFgQUS7jP4grsrU+f -HS70jdnh7id1FWswDQYJKoZIhvcNAQELBQADggEBABnS87ylRipEasYHJWSOfXjQ -spzWIVhHbJz1kXq7EHxoDPcsAiB+S579i7znBsMFHkx7eQ12egg1AbqohB8+xJkh -L1kWCW1TL+6VaMdlQYBGwZz1/3hhuTyKICLOFpX7/p0ZBbU/apPjSSkkVlvbFNC7 -a2roHGw1tMVjiuMsA3iLzPJYkIWJafpKS/z3Il5bYie1etMr7kXjrMI30zZLgPlT -/ac3eihnWejzjcDQHqAzM6XM/sVGGYuvrW448y+mOlz/NjadzbIVv8j+aKyeHiWT -k/BIYu/7Qf2giuBoMox+ynJk6zTUSYNu6dyh1C7gLzCdRpn8vkFp+q7VIn7WUdU= ------END CERTIFICATE----- diff --git a/config/ca/ca.key b/config/ca/ca.key deleted file mode 100644 index eac2b96..0000000 Binary files a/config/ca/ca.key and /dev/null differ diff --git a/config/config.yaml b/config/config.yaml deleted file mode 100644 index 5fc6fc1..0000000 --- a/config/config.yaml +++ /dev/null @@ -1,59 +0,0 @@ -log: - # 日志颜色开关,默认开启 - colorSwitch: true - # 日志等级,5为开启debug日志,4为普通日志 - level: 4 -mitm: - # socks5服务监听地址,默认监听本地1080端口 - host: 0.0.0.0:10800 - # 工具线程数,默认最大 - threads: 0 - # 超时设置 - timeout: - # 是否设置连接超时,默认不启用超时设置 - switch: false - # 超时时间,默认60s - client: 60s - target: 60s - # socks5服务的DNS解析开关,默认关闭 - bound: false - # 是否开启TCP中间人攻击的开关,默认开启(注意:关闭后就只是一个单纯的socks5代理服务) - switch: true - # 打印TCP流到控制台(对于无法识别的协议,即:HTTP、HTTPS之外的协议) - dump: - # 默认关闭 - switch: false - # 要跟踪打印目标服务的端口(假设目标服务8000端口开放了一个IM服务,可以根据目标服务端口打印TCP流信息) - port: 8000 -tls: - # 是否开启TLS中间人攻击,默认开启 - mitmSwitch: true - # 是否开启Finished握手消息校验,默认关闭 - verifyFinished: false - # 是否开启TLS记录MAC校验,默认关闭 - verifyMAC: false - # 默认SNI,如果ClientHello没有SNI扩展时,工具会通过默认SNI来获取服务器证书,这里必须配置!!! - defaultSNI: okii.com -http: - # HTTP中间人攻击开关,默认开启 - mitmSwitch: true - # HTTP上游代理设置,会把HTTP和HTTPS数据包转发到上游代理服务器,为空则不走代理 - proxy: http://127.0.0.1:8081 -# DNS服务器设置,用于查询域名对应的CDN IP,并将解析记录存储到缓存,方便后续TLS握手进行IP反查域名获取证书 -dns: 114.114.114.114 -ca: - # CA证书颁发机构的域名,可以通过设置这个来伪造一个CA证书并保存到配置文件夹 - domain: www.digicert.com - # CA证书路径 - cert: config/ca/ca.crt - # CA私钥路径 - key: config/ca/ca.key -db: - cache: - # sqlite缓存模式debug日志开关 - logSwitch: false - main: - # sqlite持久化模式debug日志开关 - logSwitch: false - # sqlite数据库路径 - path: config/sqlite/main.db \ No newline at end of file diff --git a/config/sqlite/main.db b/config/sqlite/main.db deleted file mode 100644 index 9b02061..0000000 Binary files a/config/sqlite/main.db and /dev/null differ diff --git a/connect/direct.go b/connect/direct.go deleted file mode 100644 index 0f08229..0000000 --- a/connect/direct.go +++ /dev/null @@ -1,84 +0,0 @@ -package connect - -import ( - "bufio" - "errors" - "fmt" - yaklog "github.com/yaklang/yaklang/common/log" - "io" - "net" - "os" - "socks2https/context" - "socks2https/pkg/colorutils" - "socks2https/setting" - "sync" - "time" -) - -func Direct(reader *bufio.Reader, conn net.Conn, ctx *context.Context) { - defer conn.Close() - addr := fmt.Sprintf("%s:%d", ctx.Host, ctx.Port) - dst, err := net.Dial("tcp", addr) - if err != nil { - yaklog.Errorf("%s New Target Connection Failed to Established : %v", ctx.Mitm2TargetLog, err) - return - } - defer dst.Close() - yaklog.Infof("%s New Target Connection Successfully Established.", ctx.Mitm2TargetLog) - if setting.Config.MITM.Timeout.Switch { - if err = dst.SetDeadline(time.Now().Add(setting.Config.MITM.Timeout.Target)); err != nil { - yaklog.Warnf("%s Failed to Set Target Connection Deadline : %v", ctx.Mitm2TargetLog, err) - } - } - wg := new(sync.WaitGroup) - wg.Add(2) - go func() { - defer wg.Done() - if setting.Config.MITM.Dump.Switch && ctx.Port == setting.Config.MITM.Dump.Port { - yaklog.Infof("%s %s", ctx.Mitm2TargetLog, colorutils.SetColor(colorutils.RED_COLOR_TYPE, "Reading Client IM Data")) - if _, err = io.Copy(dst, io.TeeReader(reader, os.Stdout)); err != nil { - if errors.Is(err, io.ErrUnexpectedEOF) { - yaklog.Infof("%s Forward Data Finished.", ctx.Mitm2TargetLog) - } else { - yaklog.Warnf("%s Forward Data to Target Failed : %v", ctx.Mitm2TargetLog, err) - } - return - } - } else { - if _, err = io.Copy(dst, reader); err != nil { - if errors.Is(err, io.ErrUnexpectedEOF) { - yaklog.Infof("%s Forward Data Finished.", ctx.Mitm2TargetLog) - } else { - yaklog.Warnf("%s Forward Data to Target Failed : %v", ctx.Mitm2TargetLog, err) - } - return - } - } - yaklog.Infof("%s Forward Data Finished.", ctx.Mitm2TargetLog) - }() - go func() { - defer wg.Done() - if setting.Config.MITM.Dump.Switch && ctx.Port == setting.Config.MITM.Dump.Port { - yaklog.Infof("%s %s", ctx.Mitm2TargetLog, colorutils.SetColor(colorutils.RED_COLOR_TYPE, "Reading Target IM Data")) - if _, err = io.Copy(conn, io.TeeReader(dst, os.Stdout)); err != nil { - if errors.Is(err, io.ErrUnexpectedEOF) { - yaklog.Infof("%s Forward Data Finished.", ctx.Target2MitmLog) - } else { - yaklog.Warnf("%s Forward Data to Client Failed : %v", ctx.Target2MitmLog, err) - } - return - } - } else { - if _, err = io.Copy(conn, dst); err != nil { - if errors.Is(err, io.ErrUnexpectedEOF) { - yaklog.Infof("%s Forward Data Finished.", ctx.Target2MitmLog) - } else { - yaklog.Warnf("%s Forward Data to Client Failed : %v", ctx.Target2MitmLog, err) - } - return - } - } - yaklog.Infof("%s Forward Data Finished.", ctx.Target2MitmLog) - }() - wg.Wait() -} diff --git a/connect/http.go b/connect/http.go deleted file mode 100644 index 9d96540..0000000 --- a/connect/http.go +++ /dev/null @@ -1,34 +0,0 @@ -package connect - -import ( - "bufio" - yaklog "github.com/yaklang/yaklang/common/log" - "net" - "socks2https/context" - "socks2https/mitm" - "socks2https/pkg/httptools" -) - -func HandleHTTPConnection(reader *bufio.Reader, conn net.Conn, ctx *context.Context) { - defer conn.Close() - var err error - ctx.HTTPContext.Request, err = httptools.ReadRequest(reader, "http") - if err != nil { - yaklog.Errorf("%s %v", ctx.Client2MitmLog, err) - return - } - - if err = mitm.HandleHTTPFragment(ctx); err != nil { - yaklog.Errorf("%s %v", ctx.Client2MitmLog, err) - return - } - - yaklog.Infof("%s Successfully Write HTTP Request.", ctx.Client2MitmLog) - - if err = ctx.HTTPContext.Response.Write(conn); err != nil { - yaklog.Errorf("%s Write HTTP Response Failed : %v", ctx.Mitm2ClientLog, err) - return - } - - yaklog.Infof("%s Successfully Write HTTP Response.", ctx.Mitm2ClientLog) -} diff --git a/connect/tls.go b/connect/tls.go deleted file mode 100644 index 8998617..0000000 --- a/connect/tls.go +++ /dev/null @@ -1,17 +0,0 @@ -package connect - -import ( - "bufio" - "net" - "socks2https/context" - "socks2https/handler/tlshandler" -) - -func HandleTLSConnection(reader *bufio.Reader, conn net.Conn, ctx *context.Context) { - defer conn.Close() - for _, tlsHandler := range tlshandler.TLSHandlers { - if err := tlsHandler(reader, conn, ctx); err != nil { - return - } - } -} diff --git a/context/context.go b/context/context.go deleted file mode 100644 index c5e15b6..0000000 --- a/context/context.go +++ /dev/null @@ -1,106 +0,0 @@ -package context - -import ( - "crypto/rsa" - "crypto/sha1" - "crypto/tls" - "crypto/x509" - "github.com/google/uuid" - "hash" - "net" - "net/http" - "strings" - "time" -) - -const ( - KeyExchangeRSA uint8 = iota - KeyExchangeDHE - KeyExchangeECDHE - KeyExchangePSK -) - -type TLSContext struct { - Version uint16 - HandshakeMessages [][]byte - SNI string - ClientRandom [32]byte - ServerRandom [32]byte - KeyDER *rsa.PrivateKey - CertDER *x509.Certificate - CipherSuite uint16 - KeyExchange uint8 - MACLength int - BlockLength int - HashFunc func() hash.Hash - MasterSecret []byte - ClientMACKey []byte - ServerMACKey []byte - ClientKey []byte - ServerKey []byte - ClientIV []byte - ServerIV []byte - ClientEncrypted bool - ServerEncrypted bool - ClientSeqNum uint64 - ServerSeqNum uint64 - Protocol string -} - -// NewTLSContext 创建一个默认的 tls context -func NewTLSContext() *TLSContext { - return &TLSContext{ - Version: tls.VersionTLS12, - CipherSuite: tls.TLS_RSA_WITH_AES_128_CBC_SHA, - KeyExchange: KeyExchangeRSA, - MACLength: 20, - BlockLength: 16, - HashFunc: sha1.New, - } -} - -type HTTPContext struct { - HttpClient *http.Client - Request *http.Request - Response *http.Response -} - -// NewHTTPContext 创建一个默认的 http context -func NewHTTPContext() *HTTPContext { - return &HTTPContext{ - HttpClient: &http.Client{ - Transport: &http.Transport{ - DialContext: (&net.Dialer{ - Timeout: 15 * time.Second, - KeepAlive: 15 * time.Second, - }).DialContext, - TLSClientConfig: &tls.Config{ - InsecureSkipVerify: true, - }, - ForceAttemptHTTP2: false, - }, - }, - } -} - -type Context struct { - ContextId string - LogTamplate string - Host string - Port uint16 - Cmd uint8 - Client2MitmLog string - Mitm2ClientLog string - Mitm2TargetLog string - Target2MitmLog string - Protocol string - TLSContext *TLSContext - HTTPContext *HTTPContext -} - -// NewContext 创建一个默认的 context -func NewContext() *Context { - return &Context{ - ContextId: strings.ReplaceAll(uuid.New().String(), "-", "")[:16], - } -} diff --git a/ctx.go b/ctx.go new file mode 100644 index 0000000..b39ea93 --- /dev/null +++ b/ctx.go @@ -0,0 +1,61 @@ +package proxy + +import ( + "fmt" + "github.com/google/uuid" + "net" + "net/http" + "strings" +) + +type Context struct { + Id string + ClientAddr string + RemoteIp string + RemoteHost string + RemotePort string + ServName string + Request *http.Request + Response *http.Response + IsTLS bool + Protocol string + ThirdCtx interface{} +} + +func NewContext() *Context { + id := strings.ReplaceAll(uuid.New().String(), "-", "")[:16] + return &Context{ + Id: id, + IsTLS: false, + Protocol: "TCP", + } +} + +func (c *Context) Preffix(args ...interface{}) (preffix string) { + preffixSB := strings.Builder{} + if c.Id != "" { + preffixSB.WriteString("[" + c.Id + "]") + } + + if len(args) > 0 { + if args[0].(bool) { + preffixSB.WriteString(" " + fmt.Sprintf("[%s => %s]", net.JoinHostPort(c.RemoteHost, c.RemotePort), c.ClientAddr) + " [Response]") + } else { + preffixSB.WriteString(" " + fmt.Sprintf("[%s => %s]", c.ClientAddr, net.JoinHostPort(c.RemoteHost, c.RemotePort)) + " [Request]") + } + } else { + if c.ClientAddr != "" { + preffixSB.WriteString(" " + "[" + c.ClientAddr + "]") + } + + if c.RemoteHost != "" { + preffixSB.WriteString(" " + "[" + net.JoinHostPort(c.RemoteHost, c.RemotePort) + "]") + } + } + + if c.Protocol != "" { + preffixSB.WriteString(" " + "[" + c.Protocol + "]") + } + + return preffixSB.String() +} diff --git a/database/cachedb.go b/database/cachedb.go deleted file mode 100644 index abd3464..0000000 --- a/database/cachedb.go +++ /dev/null @@ -1,42 +0,0 @@ -package database - -import ( - yaklog "github.com/yaklang/yaklang/common/log" - "gorm.io/driver/sqlite" - "gorm.io/gorm" - "gorm.io/gorm/logger" - "socks2https/models" - "socks2https/setting" -) - -var Cache *gorm.DB - -var LogFunc = map[bool]logger.Interface{ - true: logger.Default, - false: logger.Discard, -} - -func init() { - - var err error - - Cache, err = gorm.Open(sqlite.Open("file::memory:?cache=shared"), &gorm.Config{ - Logger: LogFunc[setting.Config.DB.Cache.LogSwitch], - }) - if err != nil { - yaklog.Fatalf("Open In-Memory SQLite Failed : %v", err) - } - - yaklog.Infof("In-memory SQLite Connected Established Successfully.") - - err = Cache.AutoMigrate( - &models.IPMapping{}, - &models.DomainMapping{}, - &models.CertMapping{}, - ) - if err != nil { - yaklog.Fatalf("Database Migration Failed : %v", err) - } - - yaklog.Infof("In-memory SQLite Migrated Completed Successfully.") -} diff --git a/database/maindb.go b/database/maindb.go deleted file mode 100644 index cb8e530..0000000 --- a/database/maindb.go +++ /dev/null @@ -1,35 +0,0 @@ -package database - -import ( - yaklog "github.com/yaklang/yaklang/common/log" - "gorm.io/driver/sqlite" - "gorm.io/gorm" - "socks2https/models" - "socks2https/setting" -) - -var DB *gorm.DB - -func init() { - var err error - - DB, err = gorm.Open(sqlite.Open(setting.Config.DB.Main.Path), &gorm.Config{ - Logger: LogFunc[setting.Config.DB.Main.LogSwitch], - }) - if err != nil { - yaklog.Fatalf("Open SQLite Failed : %v", err) - } - - yaklog.Info("SQLite Connection Established Successfully.") - - err = DB.AutoMigrate( - //&models.IPMapping{}, - &models.DomainMapping{}, - &models.CertMapping{}, - ) - if err != nil { - yaklog.Fatalf("SQLite Migrate Failed : %v", err) - } - - yaklog.Info("SQLite Migration Completed Successfully.") -} diff --git a/dial.go b/dial.go new file mode 100644 index 0000000..925b6ee --- /dev/null +++ b/dial.go @@ -0,0 +1,114 @@ +package proxy + +import ( + "bufio" + "context" + "crypto/tls" + "fmt" + "golang.org/x/net/proxy" + "net" + "net/http" + "net/url" +) + +type Dialer interface { + proxy.Dialer + SetTLS(isTLS bool) +} + +type HttpDialer struct { + proxyURL *url.URL + isTLS bool +} + +func (h *HttpDialer) Dial(network, addr string) (c net.Conn, err error) { + c, err = net.Dial(network, h.proxyURL.Host) + if err != nil { + return nil, err + } + + if h.isTLS { + _, _ = httpsHandshake(c, addr) + + return DailTLS(c) + } + + return c, nil +} + +func (h *HttpDialer) SetTLS(isTLS bool) { + h.isTLS = isTLS +} + +type DefaultDialer struct { + dialer proxy.Dialer + isTLS bool +} + +func (d *DefaultDialer) Dial(network, addr string) (c net.Conn, err error) { + c, err = d.dialer.Dial(network, addr) + if err != nil { + return nil, err + } + + if d.isTLS { + return DailTLS(c) + } + return +} + +func (d *DefaultDialer) SetTLS(isTLS bool) { + d.isTLS = isTLS +} + +func FromURL(httpClient *http.Client, rawURL string) (dialer proxy.Dialer, err error) { + proxyURL, err := url.Parse(rawURL) + if err != nil { + return nil, err + } + + transport := httpClient.Transport.(*http.Transport) + + switch proxyURL.Scheme { + case "http": + transport.Proxy = http.ProxyURL(proxyURL) + + return &HttpDialer{proxyURL: proxyURL}, nil + default: + dialer, err = proxy.FromURL(proxyURL, proxy.Direct) + if err != nil { + return nil, err + } + + transport.DialContext = func(ctx context.Context, network, addr string) (net.Conn, error) { + return dialer.Dial(network, addr) + } + + return &DefaultDialer{dialer: dialer}, nil + } +} + +func httpsHandshake(c net.Conn, addr string) (code int, err error) { + connReq := fmt.Sprintf("CONNECT %s HTTP/1.1\r\n", addr) + connReq += fmt.Sprintf("Host: %s\r\n", addr) + connReq += "Connection: close\r\n\r\n" + + if _, err = c.Write([]byte(connReq)); err != nil { + return 0, err + } + + connResp, err := http.ReadResponse(bufio.NewReader(c), nil) + if err != nil { + return 0, err + } + + return connResp.StatusCode, nil +} + +func DailTLS(c net.Conn) (tlsClient *tls.Conn, err error) { + tlsClient = tls.Client(c, &tls.Config{InsecureSkipVerify: true}) + if err = tlsClient.Handshake(); err != nil { + return nil, err + } + return tlsClient, nil +} diff --git a/dns.go b/dns.go new file mode 100644 index 0000000..7e422d6 --- /dev/null +++ b/dns.go @@ -0,0 +1,33 @@ +package proxy + +import ( + "crypto/tls" + "net" + "sync" +) + +var ( + ServName = new(sync.Map) + NsLookup = new(sync.Map) +) + +func fetchDNS(host string, port string) string { + tlsRemote, err := tls.Dial("tcp", host+":"+port, &tls.Config{InsecureSkipVerify: true}) + if err != nil { + return "" + } + defer tlsRemote.Close() + + ip, _, _ := net.SplitHostPort(tlsRemote.RemoteAddr().String()) + NsLookup.Store(ip, host) + + if err = tlsRemote.Handshake(); err != nil { + return "" + } + + sni := tlsRemote.ConnectionState().ServerName + + ServName.Store(host, sni) + + return sni +} diff --git a/go.mod b/go.mod index 98b123f..ceae817 100644 --- a/go.mod +++ b/go.mod @@ -1,31 +1,26 @@ -module socks2https +module github.com/vpxuser/proxy -go 1.22 - -toolchain go1.22.3 +go 1.22.10 require ( - github.com/google/uuid v1.5.0 - github.com/jinzhu/gorm v1.9.2 - github.com/kataras/golog v0.1.12 - github.com/logrusorgru/aurora v2.0.3+incompatible + github.com/elazarl/goproxy v1.7.0 + github.com/gobwas/ws v1.4.0 + github.com/google/uuid v1.6.0 + github.com/inconshreveable/go-vhost v1.0.0 github.com/yaklang/yaklang v1.3.3 - gopkg.in/yaml.v3 v3.0.1 - gorm.io/driver/sqlite v1.5.6 + golang.org/x/net v0.34.0 ) require ( - github.com/jinzhu/inflection v1.0.0 // indirect - github.com/jinzhu/now v1.1.5 // indirect - github.com/jonboulle/clockwork v0.1.0 // indirect - github.com/kataras/pio v0.0.13 // indirect - github.com/kr/pretty v0.1.0 // indirect + github.com/gobwas/httphead v0.1.0 // indirect + github.com/gobwas/pool v0.2.1 // indirect + github.com/jonboulle/clockwork v0.5.0 // indirect + github.com/kataras/golog v0.0.10 // indirect + github.com/kataras/pio v0.0.2 // indirect github.com/lestrrat/go-file-rotatelogs v0.0.0-20180223000712-d3151e2a480f // indirect github.com/lestrrat/go-strftime v0.0.0-20180220042222-ba3bf9c1d042 // indirect - github.com/mattn/go-sqlite3 v1.14.22 // indirect github.com/pkg/errors v0.9.1 // indirect - golang.org/x/sys v0.19.0 // indirect - gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 // indirect + golang.org/x/sys v0.29.0 // indirect + golang.org/x/text v0.21.0 // indirect gopkg.in/natefinch/lumberjack.v2 v2.0.0 // indirect - gorm.io/gorm v1.25.7-0.20240204074919-46816ad31dde // indirect ) diff --git a/go.sum b/go.sum index d6b1901..48ca2c8 100644 --- a/go.sum +++ b/go.sum @@ -2,79 +2,54 @@ github.com/BurntSushi/toml v1.3.2 h1:o7IhLm0Msx3BaB+n3Ag7L8EVlByGnpq14C4YWiu/gL8 github.com/BurntSushi/toml v1.3.2/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/denisenkom/go-mssqldb v0.12.3 h1:pBSGx9Tq67pBOTLmxNuirNTeB8Vjmf886Kx+8Y+8shw= -github.com/denisenkom/go-mssqldb v0.12.3/go.mod h1:k0mtMFOnU+AihqFxPMiF05rtiDrorD1Vrm1KEz5hxDo= -github.com/erikstmartin/go-testdb v0.0.0-20160219214506-8d10e4a1bae5 h1:Yzb9+7DPaBjB8zlTR87/ElzFsnQfuHnVUVqpZZIcV5Y= -github.com/erikstmartin/go-testdb v0.0.0-20160219214506-8d10e4a1bae5/go.mod h1:a2zkGnVExMxdzMo3M0Hi/3sEU+cWnZpSni0O6/Yb/P0= +github.com/elazarl/goproxy v1.7.0 h1:EXv2nV4EjM60ZtsEVLYJG4oBXhDGutMKperpHsZ/v+0= +github.com/elazarl/goproxy v1.7.0/go.mod h1:X/5W/t+gzDyLfHW4DrMdpjqYjpXsURlBt9lpBDxZZZQ= github.com/fastly/go-utils v0.0.0-20180712184237-d95a45783239 h1:Ghm4eQYC0nEPnSJdVkTrXpu9KtoVCSo1hg7mtI7G9KU= github.com/fastly/go-utils v0.0.0-20180712184237-d95a45783239/go.mod h1:Gdwt2ce0yfBxPvZrHkprdPPTTS3N5rwmLE8T22KBXlw= -github.com/go-sql-driver/mysql v1.5.0 h1:ozyZYNQW3x3HtqT1jira07DN2PArx2v7/mN66gGcHOs= -github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= -github.com/gofrs/uuid v4.0.0+incompatible h1:1SD/1F5pU8p29ybwgQSwpQk+mwdRrXCYuPhW6m+TnJw= -github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= -github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe h1:lXe2qZdvpiX5WZkZR4hgp4KJVfY3nMkvmwbVkpv1rVY= -github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0= -github.com/golang-sql/sqlexp v0.1.0 h1:ZCD6MBpcuOVfGVqsEmY5/4FtYiKz6tSyUv9LPEDei6A= -github.com/golang-sql/sqlexp v0.1.0/go.mod h1:J4ad9Vo8ZCWQ2GMrC4UCQy1JpCbwU9m3EOqtpKwwwHI= -github.com/google/uuid v1.5.0 h1:1p67kYwdtXjb0gL0BPiP1Av9wiZPo5A8z2cWkTZ+eyU= -github.com/google/uuid v1.5.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/gobwas/httphead v0.1.0 h1:exrUm0f4YX0L7EBwZHuCF4GDp8aJfVeBrlLQrs6NqWU= +github.com/gobwas/httphead v0.1.0/go.mod h1:O/RXo79gxV8G+RqlR/otEwx4Q36zl9rqC5u12GKvMCM= +github.com/gobwas/pool v0.2.1 h1:xfeeEhW7pwmX8nuLVlqbzVc7udMDrwetjEv+TZIz1og= +github.com/gobwas/pool v0.2.1/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw= +github.com/gobwas/ws v1.4.0 h1:CTaoG1tojrh4ucGPcoJFiAQUAsEWekEWvLy7GsVNqGs= +github.com/gobwas/ws v1.4.0/go.mod h1:G3gNqMNtPppf5XUz7O4shetPpcZ1VJ7zt18dlUeakrc= +github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= +github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/inconshreveable/go-vhost v1.0.0 h1:IK4VZTlXL4l9vz2IZoiSFbYaaqUW7dXJAiPriUN5Ur8= +github.com/inconshreveable/go-vhost v1.0.0/go.mod h1:aA6DnFhALT3zH0y+A39we+zbrdMC2N0X/q21e6FI0LU= github.com/jehiah/go-strftime v0.0.0-20171201141054-1d33003b3869 h1:IPJ3dvxmJ4uczJe5YQdrYB16oTJlGSC/OyZDqUk9xX4= github.com/jehiah/go-strftime v0.0.0-20171201141054-1d33003b3869/go.mod h1:cJ6Cj7dQo+O6GJNiMx+Pa94qKj+TG8ONdKHgMNIyyag= -github.com/jinzhu/gorm v1.9.2 h1:lCvgEaqe/HVE+tjAR2mt4HbbHAZsQOv3XAZiEZV37iw= -github.com/jinzhu/gorm v1.9.2/go.mod h1:Vla75njaFJ8clLU1W44h34PjIkijhjHIYnZxMqCdxqo= -github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E= -github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= -github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ= -github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= -github.com/jonboulle/clockwork v0.1.0 h1:VKV+ZcuP6l3yW9doeqz6ziZGgcynBVQO+obU0+0hcPo= -github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= -github.com/kataras/golog v0.1.12 h1:Bu7I/G4ilJlbfzjmU39O9N+2uO1pBcMK045fzZ4ytNg= -github.com/kataras/golog v0.1.12/go.mod h1:wrGSbOiBqbQSQznleVNX4epWM8rl9SJ/rmEacl0yqy4= -github.com/kataras/pio v0.0.13 h1:x0rXVX0fviDTXOOLOmr4MUxOabu1InVSTu5itF8CXCM= -github.com/kataras/pio v0.0.13/go.mod h1:k3HNuSw+eJ8Pm2lA4lRhg3DiCjVgHlP8hmXApSej3oM= -github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= -github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= -github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= -github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= -github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/jonboulle/clockwork v0.5.0 h1:Hyh9A8u51kptdkR+cqRpT1EebBwTn1oK9YfGYbdFz6I= +github.com/jonboulle/clockwork v0.5.0/go.mod h1:3mZlmanh0g2NDKO5TWZVJAfofYk64M7XN3SzBPjZF60= +github.com/kataras/golog v0.0.10 h1:vRDRUmwacco/pmBAm8geLn8rHEdc+9Z4NAr5Sh7TG/4= +github.com/kataras/golog v0.0.10/go.mod h1:yJ8YKCmyL+nWjERB90Qwn+bdyBZsaQwU3bTVFgkFIp8= +github.com/kataras/pio v0.0.2 h1:6NAi+uPJ/Zuid6mrAKlgpbI11/zK/lV4B2rxWaJN98Y= +github.com/kataras/pio v0.0.2/go.mod h1:hAoW0t9UmXi4R5Oyq5Z4irTbaTsOemSrDGUtaTl7Dro= github.com/lestrrat/go-envload v0.0.0-20180220120943-6ed08b54a570 h1:0iQektZGS248WXmGIYOwRXSQhD4qn3icjMpuxwO7qlo= github.com/lestrrat/go-envload v0.0.0-20180220120943-6ed08b54a570/go.mod h1:BLt8L9ld7wVsvEWQbuLrUZnCMnUmLZ+CGDzKtclrTlE= github.com/lestrrat/go-file-rotatelogs v0.0.0-20180223000712-d3151e2a480f h1:sgUSP4zdTUZYZgAGGtN5Lxk92rK+JUFOwf+FT99EEI4= github.com/lestrrat/go-file-rotatelogs v0.0.0-20180223000712-d3151e2a480f/go.mod h1:UGmTpUd3rjbtfIpwAPrcfmGf/Z1HS95TATB+m57TPB8= github.com/lestrrat/go-strftime v0.0.0-20180220042222-ba3bf9c1d042 h1:Bvq8AziQ5jFF4BHGAEDSqwPW1NJS3XshxbRCxtjFAZc= github.com/lestrrat/go-strftime v0.0.0-20180220042222-ba3bf9c1d042/go.mod h1:TPpsiPUEh0zFL1Snz4crhMlBe60PYxRHr5oFF3rRYg0= -github.com/lib/pq v1.1.0 h1:/5u4a+KGJptBRqGzPvYQL9p0d/tPR4S31+Tnzj9lEO4= -github.com/lib/pq v1.1.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= -github.com/logrusorgru/aurora v2.0.3+incompatible h1:tOpm7WcpBTn4fjmVfgpQq0EfczGlG91VSDkswnjF5A8= -github.com/logrusorgru/aurora v2.0.3+incompatible/go.mod h1:7rIyQOR62GCctdiQpZ/zOJlFyk6y+94wXzv6RNZgaR4= -github.com/mattn/go-sqlite3 v1.14.22 h1:2gZY6PC6kBnID23Tichd1K+Z0oS6nE/XwU+Vz/5o4kU= -github.com/mattn/go-sqlite3 v1.14.22/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= -github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= +github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/tebeka/strftime v0.1.3 h1:5HQXOqWKYRFfNyBMNVc9z5+QzuBtIXy03psIhtdJYto= github.com/tebeka/strftime v0.1.3/go.mod h1:7wJm3dZlpr4l/oVK0t1HYIc4rMzQ2XJlOMIUJUJH6XQ= github.com/yaklang/yaklang v1.3.3 h1:UujduG9XmPl0vMbIDRKKPnkGXJkmhivdU2jA4TMKjeY= github.com/yaklang/yaklang v1.3.3/go.mod h1:eQIYc5LMNmBsBX+TjOk2cM7XH9ZqwtOPEJyhISbyQJQ= -golang.org/x/crypto v0.17.0 h1:r8bRNjWL3GshPW3gkd+RpvzWrZAwPS49OmTGZ/uhM4k= -golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4= -golang.org/x/net v0.19.0 h1:zTwKpTd2XuCqf8huc7Fo2iSy+4RHPd10s4KzeTnVr1c= -golang.org/x/net v0.19.0/go.mod h1:CfAk/cbD4CthTvqiEl8NpboMuiuOYsAr/7NOjZJtv1U= -golang.org/x/sys v0.19.0 h1:q5f1RH2jigJ1MoAWp2KTp3gm5zAGFUTarQZ5U386+4o= -golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= -gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +golang.org/x/net v0.34.0 h1:Mb7Mrk043xzHgnRM88suvJFwzVrRfHEHJEl5/71CKw0= +golang.org/x/net v0.34.0/go.mod h1:di0qlW3YNM5oh6GqDGQr92MyTozJPmybPK4Ev/Gm31k= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.29.0 h1:TPYlXGxvx1MGTn2GiZDhnjPA9wZzZeGKHHmKhHYvgaU= +golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo= +golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= gopkg.in/natefinch/lumberjack.v2 v2.0.0 h1:1Lc07Kr7qY4U2YPouBjpCLxpiyxIVoxqXgkXLknAOE8= gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gorm.io/driver/sqlite v1.5.6 h1:fO/X46qn5NUEEOZtnjJRWRzZMe8nqJiQ9E+0hi+hKQE= -gorm.io/driver/sqlite v1.5.6/go.mod h1:U+J8craQU6Fzkcvu8oLeAQmi50TkwPEhHDEjQZXDah4= -gorm.io/gorm v1.25.7-0.20240204074919-46816ad31dde h1:9DShaph9qhkIYw7QF91I/ynrr4cOO2PZra2PFD7Mfeg= -gorm.io/gorm v1.25.7-0.20240204074919-46816ad31dde/go.mod h1:hbnx/Oo0ChWMn1BIhpy1oYozzpM15i4YPuHDmfYtwg8= diff --git a/handler/httphandler/debug.go b/handler/httphandler/debug.go deleted file mode 100644 index 751f50a..0000000 --- a/handler/httphandler/debug.go +++ /dev/null @@ -1,43 +0,0 @@ -package httphandler - -import ( - "fmt" - yaklog "github.com/yaklang/yaklang/common/log" - "net/http" - "net/http/httputil" - "socks2https/context" - "socks2https/pkg/colorutils" -) - -var DebugRequest = RequestHandler(func(req *http.Request, ctx *context.Context) (*http.Request, *http.Response) { - var tamplate string - if ctx.TLSContext != nil { - tamplate = fmt.Sprintf("%s [%s] [%s]", ctx.Client2MitmLog, colorutils.SetColor(colorutils.YELLOW_COLOR_TYPE, "HTTP"), colorutils.SetColor(colorutils.RED_COLOR_TYPE, "Request")) - } else { - tamplate = fmt.Sprintf("%s [%s]", ctx.Client2MitmLog, colorutils.SetColor(colorutils.RED_COLOR_TYPE, "Request")) - } - - dump, err := httputil.DumpRequestOut(req, true) - if err != nil { - yaklog.Warnf("%s Failed to Dump Request : %v", tamplate, err) - } else { - yaklog.Infof("%s\n%s", tamplate, dump) - } - return req, nil -}) - -var DebugResponse = ResponseHandler(func(resp *http.Response, ctx *context.Context) *http.Response { - var tamplate string - if ctx.TLSContext != nil { - tamplate = fmt.Sprintf("%s [%s] [%s]", ctx.Mitm2ClientLog, colorutils.SetColor(colorutils.YELLOW_COLOR_TYPE, "HTTP"), colorutils.SetColor(colorutils.RED_COLOR_TYPE, "Request")) - } else { - tamplate = fmt.Sprintf("%s [%s]", ctx.Mitm2ClientLog, colorutils.SetColor(colorutils.RED_COLOR_TYPE, "Request")) - } - dump, err := httputil.DumpResponse(resp, true) - if err != nil { - yaklog.Warnf("%s Failed to Dump Response : %v", tamplate, err) - } else { - yaklog.Infof("%s\n%s", tamplate, dump) - } - return resp -}) diff --git a/handler/httphandler/dns.go b/handler/httphandler/dns.go deleted file mode 100644 index bff20a1..0000000 --- a/handler/httphandler/dns.go +++ /dev/null @@ -1,28 +0,0 @@ -package httphandler - -import ( - yaklog "github.com/yaklang/yaklang/common/log" - "net/http" - "socks2https/context" - "socks2https/database" - "socks2https/pkg/colorutils" - "socks2https/pkg/dnsutils" - "socks2https/services" - "socks2https/setting" -) - -var DNSRequest = RequestHandler(func(req *http.Request, ctx *context.Context) (*http.Request, *http.Response) { - if _, err := services.GetIPByDomain(database.Cache, req.Host); err != nil { - ipv4s, err := dnsutils.DNS2IPv4(req.Host, setting.Config.DNS) - if err != nil { - yaklog.Warnf(colorutils.SetColor(colorutils.MAGENTA_COLOR_TYPE, err)) - return req, nil - } - for _, ipv4 := range ipv4s { - if err = services.AddIPMapping(database.Cache, ipv4, req.Host); err != nil { - yaklog.Warnf(colorutils.SetColor(colorutils.MAGENTA_COLOR_TYPE, err)) - } - } - } - return req, nil -}) diff --git a/handler/httphandler/httpdns.go b/handler/httphandler/httpdns.go deleted file mode 100644 index 6d13e8a..0000000 --- a/handler/httphandler/httpdns.go +++ /dev/null @@ -1,58 +0,0 @@ -package httphandler - -import ( - "bytes" - "encoding/json" - yaklog "github.com/yaklang/yaklang/common/log" - "io" - "net/http" - "socks2https/context" - "socks2https/database" - "socks2https/pkg/colorutils" - "socks2https/services" -) - -type BaiduHTTPDNS struct { - Clientip string `json:"clientip"` - Data map[string]struct { - IPv4 struct { - Ip []string `json:"ip"` - Ttl int `json:"ttl"` - Msg string `json:"msg"` - } `json:"ipv4"` - IPv6 struct { - Ip []string `json:"ip"` - Ttl int `json:"ttl"` - Msg string `json:"msg"` - } `json:"ipv6"` - } `json:"data"` - Msg string `json:"msg"` - Serverip struct { - Ipv4 []string `json:"ipv4"` - } `json:"serverip"` - Timestamp int `json:"timestamp"` -} - -var HTTPDNSResponse = ResponseHandler(func(resp *http.Response, ctx *context.Context) *http.Response { - switch ctx.HTTPContext.Request.Host { - case "httpdns.baidubce.com": - baiduDNS := &BaiduHTTPDNS{} - body, err := io.ReadAll(resp.Body) - if err != nil { - yaklog.Warnf("read Response Body failed : %v", err) - } - resp.Body = io.NopCloser(bytes.NewReader(body)) - if err = json.Unmarshal(body, baiduDNS); err != nil { - yaklog.Warnf("parse Response Body failed : %v", err) - } - for domain, ip := range baiduDNS.Data { - for _, ipv4 := range ip.IPv4.Ip { - if err = services.AddIPMapping(database.Cache, ipv4, domain); err != nil { - yaklog.Warnf(colorutils.SetColor(colorutils.MAGENTA_COLOR_TYPE, err)) - return resp - } - } - } - } - return resp -}) diff --git a/handler/httphandler/httphandler.go b/handler/httphandler/httphandler.go deleted file mode 100644 index e2c9c09..0000000 --- a/handler/httphandler/httphandler.go +++ /dev/null @@ -1,23 +0,0 @@ -package httphandler - -import ( - "net/http" - "socks2https/context" -) - -type RequestHandler func(req *http.Request, ctx *context.Context) (*http.Request, *http.Response) - -type ResponseHandler func(resp *http.Response, ctx *context.Context) *http.Response - -var ( - RequestHandlers = []RequestHandler{ - DNSRequest, - DebugRequest, - } - ResponseHandlers = []ResponseHandler{ - GzipDecompressResponse, - HTTPDNSResponse, - GzipCompressResponse, - DebugResponse, - } -) diff --git a/handler/httphandler/zip.go b/handler/httphandler/zip.go deleted file mode 100644 index 8e37886..0000000 --- a/handler/httphandler/zip.go +++ /dev/null @@ -1,49 +0,0 @@ -package httphandler - -import ( - "bytes" - yaklog "github.com/yaklang/yaklang/common/log" - "io" - "net/http" - "socks2https/context" - "socks2https/pkg/zip" -) - -var GzipDecompressResponse = ResponseHandler(func(resp *http.Response, ctx *context.Context) *http.Response { - if resp.Header.Get("Content-Encoding") == "gzip" { - body, err := io.ReadAll(resp.Body) - if err != nil { - yaklog.Warnf("read gzip body failed : %v", err) - return resp - } - decompressedBody, err := zip.GzipDecompress(body) - if err != nil { - yaklog.Warnf("gzip decompress body failed : %v", err) - return resp - } - resp.Body = io.NopCloser(bytes.NewBuffer(decompressedBody)) - resp.ContentLength = int64(len(decompressedBody)) - //colorutils.DumpResponse(resp, true, colorutils.RED_COLOR_TYPE) - //resp.ContentLength = int64(len(body)) - //resp.Body = io.NopCloser(bytes.NewBuffer(body)) - } - return resp -}) - -var GzipCompressResponse = ResponseHandler(func(resp *http.Response, ctx *context.Context) *http.Response { - if resp.Header.Get("Content-Encoding") == "gzip" { - body, err := io.ReadAll(resp.Body) - if err != nil { - yaklog.Warnf("read gzip body failed : %v", err) - return resp - } - compressedBody, err := zip.GzipCompress(body) - if err != nil { - yaklog.Warnf("gzip compress body failed : %v", err) - return resp - } - resp.Body = io.NopCloser(bytes.NewBuffer(compressedBody)) - resp.ContentLength = int64(len(compressedBody)) - } - return resp -}) diff --git a/handler/tlshandler/application_data.go b/handler/tlshandler/application_data.go deleted file mode 100644 index 0f0c98e..0000000 --- a/handler/tlshandler/application_data.go +++ /dev/null @@ -1,113 +0,0 @@ -package tlshandler - -import ( - "bufio" - "bytes" - "errors" - "fmt" - yaklog "github.com/yaklang/yaklang/common/log" - "net" - "net/http" - "net/http/httputil" - "net/url" - "socks2https/context" - "socks2https/mitm" - "socks2https/pkg/colorutils" - "socks2https/pkg/finger" - "socks2https/pkg/httptools" - "socks2https/pkg/tlsutils" - "socks2https/setting" -) - -var ReadApplicationData = TLSHandler(func(reader *bufio.Reader, conn net.Conn, ctx *context.Context) error { - tamplate := fmt.Sprintf("%s [%s]", ctx.Client2MitmLog, colorutils.SetColor(colorutils.YELLOW_COLOR_TYPE, "Application Data")) - - record, err := tlsutils.FilterRecord(reader, tlsutils.ContentTypeApplicationData, 0xff, ctx) - if err != nil { - //yaklog.Errorf("%s %v", tamplate, err) - yaklog.Errorf("%s %v", ctx.Client2MitmLog, err) - return err - } - - yaklog.Infof("%s Successfully Read Application Data.", tamplate) - - switch finger.Inspect(bufio.NewReader(bytes.NewReader(record.Fragment[:7]))) { - case finger.HTTP: - ctx.TLSContext.Protocol = finger.HTTP - - ctx.HTTPContext = context.NewHTTPContext() - if setting.Config.HTTP.Proxy != "" { - proxyURL, err := url.Parse(setting.Config.HTTP.Proxy) - if err != nil { - yaklog.Fatalf("Proxy URL is Invalid : %v", err) - } - ctx.HTTPContext.HttpClient.Transport.(*http.Transport).Proxy = http.ProxyURL(proxyURL) - } - - ctx.HTTPContext.Request, err = httptools.ReadRequest(bufio.NewReader(bytes.NewReader(record.Fragment)), "https") - if err != nil { - yaklog.Errorf("%s %v", tamplate, err) - return err - } - - if err := mitm.HandleHTTPFragment(ctx); err != nil { - yaklog.Errorf("%s %v", tamplate, err) - return err - } - default: - err = errors.New("Not Support Application Data Protocol") - yaklog.Errorf("%s %v", tamplate, err) - return err - } - - return nil -}) - -var WriteApplicationData = TLSHandler(func(reader *bufio.Reader, conn net.Conn, ctx *context.Context) error { - tamplate := fmt.Sprintf("%s [%s]", ctx.Client2MitmLog, colorutils.SetColor(colorutils.YELLOW_COLOR_TYPE, "Application Data")) - - var fragment []byte - var err error - switch ctx.TLSContext.Protocol { - case finger.HTTP: - fragment, err = httputil.DumpResponse(ctx.HTTPContext.Response, true) - if err != nil { - yaklog.Errorf("%s Writing Request Failed : %v", tamplate, err) - return err - } - default: - err = errors.New("Not Support TLS Protocol") - yaklog.Errorf("%s %v", tamplate, err) - return err - } - - record, err := tlsutils.NewApplicationData(ctx.TLSContext.Version, fragment) - if err != nil { - yaklog.Errorf("%s %v", tamplate, err) - return err - } - - blockRecord, err := tlsutils.NewBlockRecord(record, ctx) - if err != nil { - yaklog.Errorf("%s %v", tamplate, err) - return err - } - - if _, err = conn.Write(blockRecord); err != nil { - yaklog.Errorf("%s Failed to Write Application Data : %v", tamplate, err) - return err - } - - yaklog.Infof("%s Successfully Write Application Data.", tamplate) - - blockRecord, err = tlsutils.NewBlockRecord(tlsutils.NewAlert(ctx.TLSContext.Version, tlsutils.AlertLevelWarning, tlsutils.AlertDescriptionCloseNotify), ctx) - if err != nil { - yaklog.Errorf("%s %v", tamplate, err) - return err - } - if _, err = conn.Write(blockRecord); err != nil { - yaklog.Errorf("%s Failed to Write Alert : %v", tamplate, err) - return err - } - return nil -}) diff --git a/handler/tlshandler/certificate.go b/handler/tlshandler/certificate.go deleted file mode 100644 index a8e8180..0000000 --- a/handler/tlshandler/certificate.go +++ /dev/null @@ -1,95 +0,0 @@ -package tlshandler - -import ( - "bufio" - "crypto/rand" - "crypto/rsa" - "crypto/x509" - "errors" - "fmt" - yaklog "github.com/yaklang/yaklang/common/log" - "gorm.io/gorm" - "net" - "socks2https/context" - "socks2https/pkg/certutils" - "socks2https/pkg/colorutils" - "socks2https/pkg/tlsutils" - "socks2https/services" - "socks2https/setting" - "strings" -) - -var WriteCertificate = TLSHandler(func(reader *bufio.Reader, conn net.Conn, ctx *context.Context) error { - tamplate := fmt.Sprintf("%s [%s] [%s]", ctx.Mitm2ClientLog, colorutils.SetColor(colorutils.YELLOW_COLOR_TYPE, "Handshake"), colorutils.SetColor(colorutils.RED_COLOR_TYPE, "Certificate")) - var realCert *x509.Certificate - wildcardDomain, err := services.GetWildcardDomain(ctx.TLSContext.SNI) - if errors.Is(err, gorm.ErrRecordNotFound) { - realCert, err = certutils.GetRealCertificateWithTCP(ctx.TLSContext.SNI) - if err != nil { - yaklog.Errorf("%s %v", tamplate, err) - return err - } - wildcardDomain = ctx.TLSContext.SNI - // 提取 CN 字段中的通配符域名 - if strings.HasPrefix(realCert.Subject.CommonName, "*.") { - wildcardDomain = realCert.Subject.CommonName - } else { - // 提取 SAN 扩展中的 DNS 名称 - for _, dnsName := range realCert.DNSNames { - if strings.HasPrefix(dnsName, "*.") { - wildcardDomain = dnsName - break - } - } - } - if err = services.AddDomainMapping(ctx.TLSContext.SNI, wildcardDomain); err != nil { - yaklog.Errorf("Creating Domain Mapping Failed : %v", err) - return err - } - } else if err != nil { - yaklog.Errorf("%s Failed to Get Wildcard Domain : %v", tamplate, err) - return err - } - - ctx.TLSContext.CertDER, ctx.TLSContext.KeyDER, err = services.GetCertAndKey(wildcardDomain) - if errors.Is(err, gorm.ErrRecordNotFound) { - if realCert == nil { - realCert, err = certutils.GetRealCertificateWithTCP(ctx.TLSContext.SNI) - if err != nil { - yaklog.Errorf("%s %v", tamplate, err) - return err - } - } - - ctx.TLSContext.KeyDER, err = rsa.GenerateKey(rand.Reader, 2048) - if err != nil { - yaklog.Errorf("Creating Fake Private Key Failed : %v", err) - return err - } - ctx.TLSContext.CertDER, err = certutils.ForgedCertificate(setting.CACert, setting.CAKey, realCert, ctx.TLSContext.KeyDER) - if err != nil { - yaklog.Errorf("%s %v", tamplate, err) - return err - } - if err := services.AddCertMapping(wildcardDomain, ctx.TLSContext.CertDER, ctx.TLSContext.KeyDER); err != nil { - yaklog.Errorf("Creating Cert Mapping Failed : %v", err) - return err - } - } else if err != nil { - yaklog.Errorf("%s Failed to Get Certificate And Private Key : %v", tamplate, err) - return err - } - - record, err := tlsutils.NewCertificate(ctx.TLSContext.Version, []*x509.Certificate{ctx.TLSContext.CertDER}) - if err != nil { - yaklog.Errorf("%s %v", tamplate, err) - return err - } - ctx.TLSContext.HandshakeMessages = append(ctx.TLSContext.HandshakeMessages, record.Fragment) - if _, err = conn.Write(record.GetRaw()); err != nil { - yaklog.Errorf("%s Write Certificate Failed : %v", tamplate, err) - return err - } - yaklog.Infof("%s Write Certificate Successfully.", tamplate) - return nil -}) diff --git a/handler/tlshandler/change_cipher_spec.go b/handler/tlshandler/change_cipher_spec.go deleted file mode 100644 index 6556a8c..0000000 --- a/handler/tlshandler/change_cipher_spec.go +++ /dev/null @@ -1,33 +0,0 @@ -package tlshandler - -import ( - "bufio" - "fmt" - yaklog "github.com/yaklang/yaklang/common/log" - "net" - "socks2https/context" - "socks2https/pkg/colorutils" - "socks2https/pkg/tlsutils" -) - -var ReadChangeCipherSpec = TLSHandler(func(reader *bufio.Reader, conn net.Conn, ctx *context.Context) error { - tamplate := fmt.Sprintf("%s [%s]", ctx.Client2MitmLog, colorutils.SetColor(colorutils.YELLOW_COLOR_TYPE, "Change Cipher Spec")) - if _, err := tlsutils.FilterRecord(reader, tlsutils.ContentTypeChangeCipherSpec, 0xff, ctx); err != nil { - //yaklog.Errorf("%s %v", tamplate, err) - yaklog.Errorf("%s %v", ctx.Client2MitmLog, err) - return err - } - ctx.TLSContext.ClientEncrypted = true - yaklog.Infof("%s Client Start Encrypt Fragment", tamplate) - return nil -}) - -var WriteChangeCipherSpec = TLSHandler(func(reader *bufio.Reader, conn net.Conn, ctx *context.Context) error { - tamplate := fmt.Sprintf("%s [%s]", ctx.Mitm2ClientLog, colorutils.SetColor(colorutils.YELLOW_COLOR_TYPE, "Change Cipher Spec")) - if _, err := conn.Write(tlsutils.NewChangeCipherSpec(ctx.TLSContext.Version).GetRaw()); err != nil { - yaklog.Errorf("%s Write ChangeCipherSpec Failed : %v", tamplate, err) - return err - } - yaklog.Infof("%s Server Start Encrypt Fragment", tamplate) - return nil -}) diff --git a/handler/tlshandler/client_hello.go b/handler/tlshandler/client_hello.go deleted file mode 100644 index 45c6fd7..0000000 --- a/handler/tlshandler/client_hello.go +++ /dev/null @@ -1,59 +0,0 @@ -package tlshandler - -import ( - "bufio" - "errors" - "fmt" - yaklog "github.com/yaklang/yaklang/common/log" - "net" - "regexp" - "socks2https/context" - "socks2https/database" - "socks2https/pkg/colorutils" - "socks2https/pkg/tlsutils" - "socks2https/services" -) - -var ReadClientHello = TLSHandler(func(reader *bufio.Reader, conn net.Conn, ctx *context.Context) error { - tamplate := fmt.Sprintf("%s [%s] [%s]", ctx.Client2MitmLog, colorutils.SetColor(colorutils.YELLOW_COLOR_TYPE, "Handshake"), colorutils.SetColor(colorutils.RED_COLOR_TYPE, "Client Hello")) - record, err := tlsutils.FilterRecord(reader, tlsutils.ContentTypeHandshake, tlsutils.HandshakeTypeClientHello, ctx) - if err != nil { - yaklog.Errorf("%s %v", ctx.Client2MitmLog, err) - return err - } - ctx.TLSContext.HandshakeMessages = append(ctx.TLSContext.HandshakeMessages, record.Fragment) - clientHello := record.Handshake.ClientHello - ctx.TLSContext.ClientRandom = clientHello.Random - for _, cipherSuite := range clientHello.CipherSuites { - if cipherSuite != ctx.TLSContext.CipherSuite { - continue - } - for _, extension := range clientHello.Extensions { - if extension.Type != tlsutils.ExtensionTypeServerName { - continue - } - ctx.TLSContext.SNI = extension.ServerName.List[0].Name - yaklog.Infof("%s Domain : %s", tamplate, ctx.TLSContext.SNI) - return nil - } - - // 如果客户端使用的是http隧道可直接获取sni - if regexp.MustCompile(`^(?:(?:[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?\.)+[a-zA-Z]{2,}|localhost)$`).MatchString(ctx.Host) { - ctx.TLSContext.SNI = ctx.Host - yaklog.Infof("%s HTTP CONNECT Domain : %s", tamplate, ctx.Host) - return nil - } - - domain, err := services.GetDomainByIP(database.Cache, ctx.Host) - if err != nil { - yaklog.Infof("%s Use Default Domain : %s", tamplate, ctx.TLSContext.SNI) - return nil - } - ctx.TLSContext.SNI = domain - yaklog.Infof("%s Reverse : %s => %s", tamplate, ctx.Host, domain) - return nil - } - err = errors.New("Not Support Cipher Suites") - yaklog.Errorf("%s %v", tamplate, err) - return err -}) diff --git a/handler/tlshandler/client_key_exchange.go b/handler/tlshandler/client_key_exchange.go deleted file mode 100644 index 58553cf..0000000 --- a/handler/tlshandler/client_key_exchange.go +++ /dev/null @@ -1,56 +0,0 @@ -package tlshandler - -import ( - "bufio" - "encoding/binary" - "fmt" - yaklog "github.com/yaklang/yaklang/common/log" - "net" - "socks2https/context" - "socks2https/pkg/colorutils" - "socks2https/pkg/crypt" - "socks2https/pkg/tlsutils" -) - -var ReadClientKeyExchange = TLSHandler(func(reader *bufio.Reader, conn net.Conn, ctx *context.Context) error { - tamplate := fmt.Sprintf("%s [%s] [%s]", ctx.Client2MitmLog, colorutils.SetColor(colorutils.YELLOW_COLOR_TYPE, "Handshake"), colorutils.SetColor(colorutils.RED_COLOR_TYPE, "Client Key Exchange")) - - record, err := tlsutils.FilterRecord(reader, tlsutils.ContentTypeHandshake, tlsutils.HandshakeTypeClientKeyExchange, ctx) - if err != nil { - //yaklog.Errorf("%s %v", tamplate, err) - yaklog.Errorf("%s %v", ctx.Client2MitmLog, err) - return err - } - - // 存储握手记录,用于后续Finished的Verify_Data计算 - ctx.TLSContext.HandshakeMessages = append(ctx.TLSContext.HandshakeMessages, record.Fragment) - - // RSA解密Pre_Master_Secret - clientKeyExchange := record.Handshake.ClientKeyExchange.(*tlsutils.RSAClientKeyExchange) - preMasterSecret, err := crypt.DecryptRSAPKCS(ctx.TLSContext.KeyDER, clientKeyExchange.EncrypedPreMasterSecret) - if err != nil { - yaklog.Errorf("%s %v", tamplate, err) - return err - } - - yaklog.Infof("%s PreMasterSecret : %x", tamplate, preMasterSecret) - - // 使用PRF算法计算出Master_Secret - version := binary.BigEndian.Uint16(preMasterSecret[:2]) - masterSecret := crypt.PRF[version](preMasterSecret, []byte(crypt.LabelMasterSecret), append(ctx.TLSContext.ClientRandom[:], ctx.TLSContext.ServerRandom[:]...), len(preMasterSecret)) - ctx.TLSContext.MasterSecret = masterSecret - - // 使用PRF算法和Master_Secret计算Session_Key(会话密钥) - sessionKey := crypt.PRF[version](masterSecret, []byte(crypt.LabelKeyExpansion), append(ctx.TLSContext.ServerRandom[:], ctx.TLSContext.ClientRandom[:]...), 2*(ctx.TLSContext.MACLength+2*ctx.TLSContext.BlockLength)) - - // 从会话密钥截取后续加解密消息类型使用的HMAC签名密钥 - ctx.TLSContext.ClientMACKey, ctx.TLSContext.ServerMACKey = sessionKey[:ctx.TLSContext.MACLength], sessionKey[ctx.TLSContext.MACLength:2*ctx.TLSContext.MACLength] - - // 从会话密钥截取后续加解密消息类型使用的对称密钥 - ctx.TLSContext.ClientKey, ctx.TLSContext.ServerKey = sessionKey[2*ctx.TLSContext.MACLength:2*ctx.TLSContext.MACLength+ctx.TLSContext.BlockLength], sessionKey[2*ctx.TLSContext.MACLength+ctx.TLSContext.BlockLength:2*(ctx.TLSContext.MACLength+ctx.TLSContext.BlockLength)] - - // 从会话密钥截取后续加解密消息类型使用的对称向量,向量一般不需要生成,下面代码可以不要 - ctx.TLSContext.ClientIV, ctx.TLSContext.ServerIV = sessionKey[2*(ctx.TLSContext.MACLength+ctx.TLSContext.BlockLength):2*(ctx.TLSContext.MACLength+ctx.TLSContext.BlockLength)+ctx.TLSContext.BlockLength], sessionKey[2*(ctx.TLSContext.MACLength+ctx.TLSContext.BlockLength)+ctx.TLSContext.BlockLength:] - - return nil -}) diff --git a/handler/tlshandler/finished.go b/handler/tlshandler/finished.go deleted file mode 100644 index 274b1a0..0000000 --- a/handler/tlshandler/finished.go +++ /dev/null @@ -1,58 +0,0 @@ -package tlshandler - -import ( - "bufio" - "crypto/hmac" - "errors" - "fmt" - yaklog "github.com/yaklang/yaklang/common/log" - "net" - "socks2https/context" - "socks2https/pkg/colorutils" - "socks2https/pkg/crypt" - "socks2https/pkg/tlsutils" - "socks2https/setting" -) - -var ReadFinished = TLSHandler(func(reader *bufio.Reader, conn net.Conn, ctx *context.Context) error { - tamplate := fmt.Sprintf("%s [%s] [%s]", ctx.Client2MitmLog, colorutils.SetColor(colorutils.YELLOW_COLOR_TYPE, "Handshake"), colorutils.SetColor(colorutils.RED_COLOR_TYPE, "Finished")) - - record, err := tlsutils.FilterRecord(reader, tlsutils.ContentTypeHandshake, tlsutils.HandshakeTypeFinished, ctx) - if err != nil { - //yaklog.Errorf("%s %v", tamplate, err) - yaklog.Errorf("%s %v", ctx.Client2MitmLog, err) - return err - } - - ctx.TLSContext.HandshakeMessages = append(ctx.TLSContext.HandshakeMessages, record.Fragment) - - if setting.Config.TLS.VerifyFinished { - verifyData := tlsutils.VerifyPRF(ctx.TLSContext.Version, ctx.TLSContext.MasterSecret, []byte(crypt.LabelClientFinished), ctx.TLSContext.HandshakeMessages, 12) - if hmac.Equal(verifyData, record.Handshake.Payload) { - err = errors.New("Verify Client Finished Failed") - yaklog.Errorf("%s %s", tamplate, err) - return err - } - yaklog.Infof("%s Verify Client Finished Successfully", tamplate) - } else { - yaklog.Infof("%s Not Need to Verify Finished", tamplate) - } - return nil -}) - -var WriteFinished = TLSHandler(func(reader *bufio.Reader, conn net.Conn, ctx *context.Context) error { - tamplate := fmt.Sprintf("%s [%s] [%s]", ctx.Mitm2ClientLog, colorutils.SetColor(colorutils.YELLOW_COLOR_TYPE, "Handshake"), colorutils.SetColor(colorutils.RED_COLOR_TYPE, "Finished")) - blockRecord, err := tlsutils.NewBlockRecord(tlsutils.NewFinished(ctx), ctx) - if err != nil { - yaklog.Errorf("%s %v", tamplate, err) - return err - } - - if _, err := conn.Write(blockRecord); err != nil { - yaklog.Errorf("%s Failed to Write Server Finished : %v", tamplate, err) - return err - } - - yaklog.Infof("%s Successfully Write Server Finished.", tamplate) - return nil -}) diff --git a/handler/tlshandler/server_hello.go b/handler/tlshandler/server_hello.go deleted file mode 100644 index 8079d77..0000000 --- a/handler/tlshandler/server_hello.go +++ /dev/null @@ -1,29 +0,0 @@ -package tlshandler - -import ( - "bufio" - "fmt" - yaklog "github.com/yaklang/yaklang/common/log" - "net" - "socks2https/context" - "socks2https/pkg/colorutils" - "socks2https/pkg/tlsutils" -) - -var WriteServerHello = TLSHandler(func(reader *bufio.Reader, conn net.Conn, ctx *context.Context) error { - tamplate := fmt.Sprintf("%s [%s] [%s]", ctx.Mitm2ClientLog, colorutils.SetColor(colorutils.YELLOW_COLOR_TYPE, "Handshake"), colorutils.SetColor(colorutils.RED_COLOR_TYPE, "Server Hello")) - record, err := tlsutils.NewServerHello(ctx.TLSContext.Version, ctx.TLSContext.CipherSuite) - if err != nil { - yaklog.Errorf("%s %v", tamplate, err) - return err - } - ctx.TLSContext.ServerRandom = record.Handshake.ServerHello.Random - serverHello := record.GetRaw() - ctx.TLSContext.HandshakeMessages = append(ctx.TLSContext.HandshakeMessages, serverHello[5:]) - if _, err = conn.Write(serverHello); err != nil { - yaklog.Errorf("%s Write ServerHello Failed : %v", tamplate, err) - return err - } - yaklog.Infof("%s Write ServerHello Successfully", tamplate) - return nil -}) diff --git a/handler/tlshandler/server_hello_done.go b/handler/tlshandler/server_hello_done.go deleted file mode 100644 index 6c52886..0000000 --- a/handler/tlshandler/server_hello_done.go +++ /dev/null @@ -1,23 +0,0 @@ -package tlshandler - -import ( - "bufio" - "fmt" - yaklog "github.com/yaklang/yaklang/common/log" - "net" - "socks2https/context" - "socks2https/pkg/colorutils" - "socks2https/pkg/tlsutils" -) - -var WriteServerHelloDone = TLSHandler(func(reader *bufio.Reader, conn net.Conn, ctx *context.Context) error { - tamplate := fmt.Sprintf("%s [%s] [%s]", ctx.Mitm2ClientLog, colorutils.SetColor(colorutils.YELLOW_COLOR_TYPE, "Handshake"), colorutils.SetColor(colorutils.RED_COLOR_TYPE, "Server Hello Done")) - record := tlsutils.NewServerHelloDone(ctx.TLSContext.Version) - ctx.TLSContext.HandshakeMessages = append(ctx.TLSContext.HandshakeMessages, record.Fragment) - if _, err := conn.Write(record.GetRaw()); err != nil { - yaklog.Errorf("%s Write ServerHelloDone Failed : %v", tamplate, err) - return err - } - yaklog.Infof("%s Write ServerHelloDone Successfully.", tamplate) - return nil -}) diff --git a/handler/tlshandler/tlshandler.go b/handler/tlshandler/tlshandler.go deleted file mode 100644 index e31b4ae..0000000 --- a/handler/tlshandler/tlshandler.go +++ /dev/null @@ -1,23 +0,0 @@ -package tlshandler - -import ( - "bufio" - "net" - "socks2https/context" -) - -type TLSHandler func(reader *bufio.Reader, conn net.Conn, ctx *context.Context) error - -var TLSHandlers = []TLSHandler{ - ReadClientHello, - WriteServerHello, - WriteCertificate, - WriteServerHelloDone, - ReadClientKeyExchange, - ReadChangeCipherSpec, - ReadFinished, - WriteChangeCipherSpec, - WriteFinished, - ReadApplicationData, - WriteApplicationData, -} diff --git a/hook.go b/hook.go new file mode 100644 index 0000000..cf19b80 --- /dev/null +++ b/hook.go @@ -0,0 +1,257 @@ +package proxy + +import ( + "github.com/gobwas/ws" + "net/http" + "strings" +) + +type ReqCond interface { + MatchReq(req *http.Request, ctx *Context) bool +} + +type ReqConds struct { + httpProxy *HttpProxy + conds []ReqCond +} + +func (h *HttpProxy) OnRequest(conds ...ReqCond) *ReqConds { + return &ReqConds{httpProxy: h, conds: conds} +} + +func (r *ReqConds) Do(handle HandleReq) { + r.httpProxy.reqHandlers = append(r.httpProxy.reqHandlers, + func(req *http.Request, ctx *Context) (*http.Request, *http.Response) { + for _, cond := range r.conds { + if !cond.MatchReq(req, ctx) { + return req, nil + } + } + return handle(req, ctx) + }) +} + +func (h *HttpProxy) filterReq(req *http.Request, ctx *Context) (*http.Request, *http.Response) { + for _, handle := range h.reqHandlers { + req, ctx.Response = handle(req, ctx) + if req == nil { + break + } + } + return req, ctx.Response +} + +type ReqMatch func(req *http.Request, ctx *Context) bool + +func (r ReqMatch) MatchResp(resp *http.Response, ctx *Context) bool { + return r(ctx.Request, ctx) +} + +func (r ReqMatch) MatchReq(req *http.Request, ctx *Context) bool { + return r(req, ctx) +} + +func Not(cond ReqCond) ReqMatch { + return func(req *http.Request, ctx *Context) bool { + return !cond.MatchReq(req, ctx) + } +} + +func ReqHostIs(hosts ...string) ReqMatch { + hostSet := make(map[string]struct{}) + for _, host := range hosts { + hostSet[host] = struct{}{} + } + + return func(req *http.Request, ctx *Context) bool { + _, ok := hostSet[req.Host] + return ok + } +} + +func ReqWildcardIs(hosts ...string) ReqMatch { + wildcardSet := make(map[string]struct{}) + for _, host := range hosts { + if strings.Contains(host, "*") { + wildcardSet[host] = struct{}{} + } + } + + return func(req *http.Request, ctx *Context) bool { + _, ok := wildcardSet[WildcardFQDN(req.Host)] + return ok + } +} + +func ReqUrlIs(urls ...string) ReqMatch { + urlSet := make(map[string]struct{}) + for _, url := range urls { + urlSet[url] = struct{}{} + } + + return func(req *http.Request, ctx *Context) bool { + _, ok := urlSet[req.Host+req.URL.Path] + return ok + } +} + +func ReqContentTypeIs(contentTypes ...string) ReqMatch { + contentTypeSet := make(map[string]struct{}) + for _, contentType := range contentTypes { + contentTypeSet[contentType] = struct{}{} + } + + return func(req *http.Request, ctx *Context) bool { + _, ok := contentTypeSet[req.Header.Get("Content-Type")] + return ok + } +} + +func ReqUrlLike(urls ...string) ReqMatch { + urlSet := make(map[string]struct{}) + for _, url := range urls { + urlSet[url] = struct{}{} + } + + return func(req *http.Request, ctx *Context) bool { + paths := strings.Split(req.URL.Path, "/")[1:] + var path strings.Builder + for _, p := range paths { + path.Write([]byte("/" + p)) + if _, ok := urlSet[req.Host+path.String()]; ok { + return true + } + } + return false + } +} + +func ReqMethodIs(methods ...string) ReqMatch { + methodSet := make(map[string]struct{}) + for _, method := range methods { + methodSet[method] = struct{}{} + } + + return func(req *http.Request, ctx *Context) bool { + _, ok := methodSet[req.Method] + return ok + } +} + +type RespCond interface { + ReqCond + MatchResp(resp *http.Response, ctx *Context) bool +} + +type RespConds struct { + httpProxy *HttpProxy + conds []RespCond +} + +func (h *HttpProxy) OnResponse(conds ...RespCond) *RespConds { + return &RespConds{httpProxy: h, conds: conds} +} + +func (r *RespConds) Do(handle HandleResp) { + r.httpProxy.respHandlers = append(r.httpProxy.respHandlers, + func(resp *http.Response, ctx *Context) *http.Response { + for _, cond := range r.conds { + if !cond.MatchReq(ctx.Request, ctx) { + return resp + } + if !cond.MatchResp(resp, ctx) { + return resp + } + } + return handle(resp, ctx) + }) +} + +func (h *HttpProxy) filterResp(resp *http.Response, ctx *Context) *http.Response { + for _, handle := range h.respHandlers { + resp = handle(resp, ctx) + } + return resp +} + +type WebSocketCond interface { + Match(frame ws.Frame, reverse bool, ctx *Context) bool +} + +type WebSocketConds struct { + httpProxy *HttpProxy + conds []WebSocketCond +} + +func (h *HttpProxy) OnWebSocket(conds ...WebSocketCond) *WebSocketConds { + return &WebSocketConds{httpProxy: h, conds: conds} +} + +func (w *WebSocketConds) Do(handle HandleWebSocket) { + w.httpProxy.webSocketHandlers = append(w.httpProxy.webSocketHandlers, + func(frame ws.Frame, reverse bool, ctx *Context) ws.Frame { + for _, cond := range w.conds { + if !cond.Match(frame, reverse, ctx) { + return frame + } + } + return handle(frame, reverse, ctx) + }) +} + +func (h *HttpProxy) filterWebSocket(frame ws.Frame, reverse bool, ctx *Context) ws.Frame { + for _, handle := range h.webSocketHandlers { + frame = handle(frame, reverse, ctx) + } + return frame +} + +type RawCond interface { + Match(raw []byte, reverse bool, ctx *Context) bool +} + +type RawConds struct { + httpProxy *HttpProxy + conds []RawCond +} + +func (h *HttpProxy) OnRaw(conds ...RawCond) *RawConds { + return &RawConds{httpProxy: h, conds: conds} +} + +func (r *RawConds) Do(handle HandleRaw) { + r.httpProxy.rawHandlers = append(r.httpProxy.rawHandlers, + func(raw []byte, reverse bool, ctx *Context) []byte { + for _, cond := range r.conds { + if !cond.Match(raw, reverse, ctx) { + return raw + } + } + return handle(raw, reverse, ctx) + }) +} + +func (h *HttpProxy) filterRaw(raw []byte, reverse bool, ctx *Context) []byte { + for _, handle := range h.rawHandlers { + raw = handle(raw, reverse, ctx) + } + return raw +} + +type RawMatch func(raw []byte, reverse bool, ctx *Context) bool + +func (r RawMatch) Match(raw []byte, reverse bool, ctx *Context) bool { + return r(raw, reverse, ctx) +} + +func RemoteIs(hosts ...string) RawMatch { + hostSet := make(map[string]struct{}) + for _, host := range hosts { + hostSet[host] = struct{}{} + } + + return func(raw []byte, reverse bool, ctx *Context) bool { + _, ok := hostSet[ctx.RemoteHost+":"+ctx.RemotePort] + return ok + } +} diff --git a/http.go b/http.go new file mode 100644 index 0000000..84394d7 --- /dev/null +++ b/http.go @@ -0,0 +1,39 @@ +package proxy + +import ( + "errors" + yaklog "github.com/yaklang/yaklang/common/log" + "net" +) + +func (h *HttpProxy) handleHttp(client net.Conn, ctx *Context) (err error) { + if ctx.IsTLS { + ctx.Protocol, ctx.Request.URL.Scheme = "HTTPS", "https" + } + + ctx.Request.URL.Host, ctx.Request.RequestURI = ctx.Request.Host, "" + + ctx.Request, ctx.Response = h.filterReq(ctx.Request, ctx) + + if ctx.Response == nil { + if ctx.Request != nil { + ctx.Response, err = h.HTTPClient.Do(ctx.Request) + if err != nil { + yaklog.Errorf("%s send request to remote failed - %v", ctx.Preffix(), err) + return err + } + } else { + errNil := errors.New("request and response is nil") + yaklog.Errorf("%s fliterReq error - %v", ctx.Preffix(), errNil) + return errNil + } + ctx.Response = h.filterResp(ctx.Response, ctx) + } + + if err = ctx.Response.Write(client); err != nil { + yaklog.Errorf("%s send response to client failed - %v", ctx.Preffix(), err) + return err + } + + return nil +} diff --git a/images/1.png b/images/1.png deleted file mode 100644 index 2bbd01d..0000000 Binary files a/images/1.png and /dev/null differ diff --git a/images/2.png b/images/2.png deleted file mode 100644 index 37533e0..0000000 Binary files a/images/2.png and /dev/null differ diff --git a/images/just_trust_me.png b/images/just_trust_me.png deleted file mode 100644 index e10d817..0000000 Binary files a/images/just_trust_me.png and /dev/null differ diff --git a/images/move_certificate.png b/images/move_certificate.png deleted file mode 100644 index d6a9bf6..0000000 Binary files a/images/move_certificate.png and /dev/null differ diff --git a/io.go b/io.go new file mode 100644 index 0000000..a7053e7 --- /dev/null +++ b/io.go @@ -0,0 +1,42 @@ +package proxy + +import ( + "bytes" + "io" + "net" + "sync" +) + +type Conn struct { + sync.Mutex + Buffer *bytes.Buffer + io.Reader + net.Conn +} + +func (c *Conn) Read(p []byte) (n int, err error) { + c.Mutex.Lock() + defer c.Mutex.Unlock() + + if c.Buffer == nil || c.Buffer.Len() == 0 { + return c.Conn.Read(p) + } + + n, err = c.Buffer.Read(p) + if err == io.EOF { + c.Buffer.Reset() + var size int + size, err = c.Conn.Read(p[n:]) + n += size + } + return n, err +} + +func NewConn(conn net.Conn) *Conn { + c := &Conn{ + Conn: conn, + Buffer: bytes.NewBuffer(make([]byte, 0, 1024)), + } + c.Reader = io.TeeReader(conn, c.Buffer) + return c +} diff --git a/main.go b/main.go deleted file mode 100644 index ec518a1..0000000 --- a/main.go +++ /dev/null @@ -1,24 +0,0 @@ -package main - -import ( - "fmt" - yaklog "github.com/yaklang/yaklang/common/log" - "socks2https/porxy" - "socks2https/setting" -) - -const PROGRAM_NAME = "\n███████╗ ██████╗ ██████╗██╗ ██╗███████╗██████╗ ██╗ ██╗████████╗████████╗██████╗ ███████╗\n██╔════╝██╔═══██╗██╔════╝██║ ██╔╝██╔════╝╚════██╗██║ ██║╚══██╔══╝╚══██╔══╝██╔══██╗██╔════╝\n███████╗██║ ██║██║ █████╔╝ ███████╗ █████╔╝███████║ ██║ ██║ ██████╔╝███████╗\n╚════██║██║ ██║██║ ██╔═██╗ ╚════██║██╔═══╝ ██╔══██║ ██║ ██║ ██╔═══╝ ╚════██║\n███████║╚██████╔╝╚██████╗██║ ██╗███████║███████╗██║ ██║ ██║ ██║ ██║ ███████║\n╚══════╝ ╚═════╝ ╚═════╝╚═╝ ╚═╝╚══════╝╚══════╝╚═╝ ╚═╝ ╚═╝ ╚═╝ ╚═╝ ╚══════╝\n \n" - -func init() { - fmt.Println(PROGRAM_NAME) - yaklog.SetLevel(setting.Config.Log.Level) -} - -func main() { - mitmSocks := porxy.NewMITMServer() - mitmSocks.Host = setting.Config.MITM.Host - mitmSocks.Threads = setting.Config.MITM.Threads - mitmSocks.ClientTimeout = setting.Config.MITM.Timeout.Client - mitmSocks.TargetTimeout = setting.Config.MITM.Timeout.Target - mitmSocks.Run() -} diff --git a/mitm/http.go b/mitm/http.go deleted file mode 100644 index 355ba74..0000000 --- a/mitm/http.go +++ /dev/null @@ -1,25 +0,0 @@ -package mitm - -import ( - "fmt" - "socks2https/context" - "socks2https/handler/httphandler" -) - -func HandleHTTPFragment(ctx *context.Context) error { - for _, requestHandler := range httphandler.RequestHandlers { - ctx.HTTPContext.Request, ctx.HTTPContext.Response = requestHandler(ctx.HTTPContext.Request, ctx) - } - - if ctx.HTTPContext.Response == nil { - resp, err := ctx.HTTPContext.HttpClient.Do(ctx.HTTPContext.Request) - if err != nil { - return fmt.Errorf("Writing Request Failed : %v", err) - } - ctx.HTTPContext.Response = resp - for _, modifyResponse := range httphandler.ResponseHandlers { - ctx.HTTPContext.Response = modifyResponse(ctx.HTTPContext.Response, ctx) - } - } - return nil -} diff --git a/mitmall.exe b/mitmall.exe deleted file mode 100644 index 2e4ed69..0000000 Binary files a/mitmall.exe and /dev/null differ diff --git a/mode.go b/mode.go new file mode 100644 index 0000000..9c441c1 --- /dev/null +++ b/mode.go @@ -0,0 +1,215 @@ +package proxy + +import ( + "bufio" + "crypto/tls" + "github.com/elazarl/goproxy" + "github.com/inconshreveable/go-vhost" + yaklog "github.com/yaklang/yaklang/common/log" + "net" + "net/http" + "strings" +) + +type Mode interface { + HandleConnect(client net.Conn, h *HttpProxy, ctx *Context) (err error) +} + +type Manual struct{} + +func (m *Manual) HandleConnect(client net.Conn, h *HttpProxy, ctx *Context) (err error) { + ctx.Request, err = http.ReadRequest(bufio.NewReader(client)) + if err != nil { + yaklog.Errorf("%s read http request failed - %v", ctx.Preffix(), err) + return err + } + + ctx.Request.URL.Scheme, ctx.Protocol = "http", "HTTP" + + ctx.RemoteHost, ctx.RemotePort, err = net.SplitHostPort(ctx.Request.Host) + if err != nil { + if strings.Contains(err.Error(), "missing port in address") { + ctx.RemoteHost, ctx.RemotePort = ctx.Request.Host, "80" + } else { + yaklog.Errorf("%s split remote host failed - %v", ctx.Preffix(), err) + return err + } + } + + if ctx.Request.Method == http.MethodConnect { + ctx.IsTLS, ctx.Request.URL.Scheme, ctx.Protocol = true, "https", "HTTPS" + + if _, err = client.Write([]byte("HTTP/1.1 200 Connection established\r\n\r\n")); err != nil { + yaklog.Errorf("%s write http response failed - %v", ctx.Preffix(), err) + return err + } + + subConf := goproxy.NewProxyHttpServer() + //proxyConf.Tr.DisableCompression = true + + tlsConfig, err := goproxy.TLSConfigFromCA(&tls.Certificate{ + Certificate: [][]byte{h.Cert.Raw}, + PrivateKey: h.Key, + })(ctx.RemoteHost, &goproxy.ProxyCtx{ + Proxy: subConf, + }) + + client = tls.Server(client, tlsConfig) + + ctx.Request, err = http.ReadRequest(bufio.NewReader(client)) + if err != nil { + yaklog.Errorf("%s read https request failed - %v", ctx.Preffix(), err) + return err + } + } + + if ctx.Request.Header.Get("Upgrade") == "websocket" { + _ = h.handleWebSocket(client, ctx) + } else { + _ = h.handleHttp(client, ctx) + } + + return nil +} + +var HttpMethod = map[string]struct{}{ + http.MethodGet[:3]: {}, + http.MethodHead[:3]: {}, + http.MethodPost[:3]: {}, + http.MethodPut[:3]: {}, + http.MethodPatch[:3]: {}, + http.MethodConnect[:3]: {}, + http.MethodDelete[:3]: {}, + http.MethodOptions[:3]: {}, + http.MethodTrace[:3]: {}, +} + +type Transparent struct{} + +func (t *Transparent) HandleConnect(client net.Conn, h *HttpProxy, ctx *Context) (err error) { + ctx.Request, err = http.ReadRequest(bufio.NewReader(client)) + if err != nil { + yaklog.Errorf("%s read http connect request failed - %v", ctx.Preffix(), err) + return err + } + + if ctx.Request.Method == http.MethodConnect { + if _, err = client.Write([]byte("HTTP/1.1 200 Connection established\r\n\r\n")); err != nil { + yaklog.Errorf("%s write http connect response failed - %v", ctx.Preffix(), err) + return err + } + } + + ctx.RemoteHost, ctx.RemotePort, err = net.SplitHostPort(ctx.Request.Host) + if err != nil { + if strings.Contains(err.Error(), "missing port in address") { + ctx.RemoteHost, ctx.RemotePort = ctx.Request.Host, "80" + } else { + yaklog.Errorf("%s split remote host failed - %v", ctx.Preffix(), err) + return err + } + } + + remoteIp := ctx.RemoteHost + + ioClient, buf := NewConn(client), make([]byte, 3) + if _, err = ioClient.Reader.Read(buf); err != nil { + yaklog.Errorf("%s peek buf failed - %v", ctx.Preffix(), err) + return err + } + + if buf[0] == 0x16 { + ctx.IsTLS, ctx.Protocol = true, "TLS" + + var ( + vhostClient *vhost.TLSConn + fqdn string + servName string + ) + + if IsDomain(remoteIp) { + fqdn = remoteIp + } else { + if host, ok := NsLookup.Load(remoteIp); ok { + fqdn = host.(string) + } else { + vhostClient, err = vhost.TLS(ioClient) + if err != nil { + yaklog.Errorf("%s parse client hello failed - %v", ctx.Preffix(), err) + return err + } + + fqdn = vhostClient.Host() + } + } + + if fqdn != "" { + if host, ok := ServName.Load(fqdn); ok { + servName = host.(string) + } else { + servName = fetchDNS(fqdn, ctx.RemotePort) + } + } else { + servName = h.DefaultSNI + } + + ctx.ServName = servName + + subConfig := goproxy.NewProxyHttpServer() + + tlsConfig, err := goproxy.TLSConfigFromCA(&tls.Certificate{ + Certificate: [][]byte{h.Cert.Raw}, + PrivateKey: h.Key, + })(servName, &goproxy.ProxyCtx{ + Proxy: subConfig, + }) + + if vhostClient != nil { + ioClient = NewConn(tls.Server(vhostClient, tlsConfig)) + } else { + ioClient = NewConn(tls.Server(ioClient, tlsConfig)) + } + + if _, err = ioClient.Reader.Read(buf); err != nil { + yaklog.Errorf("%s remote server name invalid - %v", ctx.Preffix(), err) + return err + } + } + + if _, ok := HttpMethod[string(buf)]; ok { + ctx.Request, err = http.ReadRequest(bufio.NewReader(ioClient)) + if err != nil { + yaklog.Errorf("%s read http request failed - %v", ctx.Preffix(), err) + return err + } + + ctx.RemoteHost, _, err = net.SplitHostPort(ctx.Request.Host) + if err != nil { + if strings.Contains(err.Error(), "missing port in address") { + ctx.RemoteHost = ctx.Request.Host + } + } + + if ctx.IsTLS { + if _, ok = NsLookup.Load(remoteIp); !ok && !IsDomain(remoteIp) { + NsLookup.Store(remoteIp, ctx.RemoteHost) + } + + if _, ok = ServName.Load(ctx.RemoteHost); !ok { + ServName.Store(ctx.RemoteHost, ctx.ServName) + } + } + + if ctx.Request.Header.Get("Upgrade") == "websocket" { + _ = h.handleWebSocket(ioClient, ctx) + } else { + ctx.Protocol, ctx.Request.URL.Scheme = "HTTP", "http" + _ = h.handleHttp(ioClient, ctx) + } + } else { + ctx.RemoteHost = remoteIp + _ = h.handleTCP(ioClient, ctx) + } + + return nil +} diff --git a/models/models.go b/models/models.go deleted file mode 100644 index c8f9e23..0000000 --- a/models/models.go +++ /dev/null @@ -1,20 +0,0 @@ -package models - -type IPMapping struct { - ID uint `gorm:"primaryKey;autoIncrement"` - IP string `gorm:"not null"` - Domain string `gorm:"not null"` -} - -type DomainMapping struct { - ID uint `gorm:"primaryKey;autoIncrement"` - Domain string `gorm:"unique;not null"` - WildcardDomain string `gorm:"not null"` -} - -type CertMapping struct { - ID uint `gorm:"primaryKey;autoIncrement"` - WildcardDomain string `gorm:"unique;not null"` - Certificate []byte `gorm:"not null"` // 存储证书 - PrivateKey []byte `gorm:"not null"` // 存储私钥 -} diff --git a/net.go b/net.go new file mode 100644 index 0000000..18527d1 --- /dev/null +++ b/net.go @@ -0,0 +1,22 @@ +package proxy + +import ( + "regexp" + "strings" +) + +func WildcardFQDN(fqdn string) string { + fqdnSplit := strings.Split(fqdn, ".") + if len(fqdnSplit) < 2 { + return fqdn + } + return "*." + strings.Join(fqdnSplit[len(fqdnSplit)-2:], ".") +} + +func IsDomain(host string) bool { + matched, err := regexp.MatchString(`^([a-zA-Z0-9-]+\.)+[a-zA-Z]{2,}$`, host) + if err != nil { + return false + } + return matched +} diff --git a/pkg/certutils/certutils.go b/pkg/certutils/certutils.go deleted file mode 100644 index 70668d2..0000000 --- a/pkg/certutils/certutils.go +++ /dev/null @@ -1,176 +0,0 @@ -package certutils - -import ( - "crypto/rand" - "crypto/rsa" - "crypto/tls" - "crypto/x509" - "encoding/pem" - "fmt" - "math/big" - "net/http" - "os" - "time" -) - -func ForgedRootCACertificate(realCert *x509.Certificate, keyDER *rsa.PrivateKey) (*x509.Certificate, error) { - certDER := &x509.Certificate{ - SerialNumber: realCert.SerialNumber, // 使用新的序列号 - Subject: realCert.Subject, // 复制主体信息,使其看起来与原始证书一致 - NotBefore: time.Now(), // 修改有效期 - NotAfter: time.Now().AddDate(1, 0, 0), // 证书有效期为1年 - KeyUsage: x509.KeyUsageDigitalSignature | x509.KeyUsageKeyEncipherment, - BasicConstraintsValid: true, - IsCA: true, - MaxPathLen: 0, - MaxPathLenZero: true, - } - certRaw, err := x509.CreateCertificate(rand.Reader, certDER, certDER, &keyDER.PublicKey, keyDER) - if err != nil { - return nil, fmt.Errorf("Failed to Create CA Certificate : %v", err) - } - certDER, err = x509.ParseCertificate(certRaw) - if err != nil { - return nil, fmt.Errorf("Failed to Parse CA Certificate : %v", err) - } - return certDER, nil -} - -func LoadCert(path string) (*x509.Certificate, error) { - certRaw, err := os.ReadFile(path) - if err != nil { - return nil, fmt.Errorf("read Cert file failed: %v", err) - } - block, _ := pem.Decode(certRaw) - if block != nil { - certPEM, err := x509.ParseCertificate(block.Bytes) - if err != nil { - return nil, fmt.Errorf("parse Cert PEM failed : %v", err) - } - return certPEM, nil - } - certDER, err := x509.ParseCertificate(certRaw) - if err != nil { - return nil, fmt.Errorf("unkonwn Cert format : %v", err) - } - return certDER, nil -} - -func LoadKey(path string) (*rsa.PrivateKey, error) { - keyRaw, err := os.ReadFile(path) - if err != nil { - return nil, fmt.Errorf("read Key file failed : %v", err) - } - block, _ := pem.Decode(keyRaw) - if block != nil { - keyPEM, err := x509.ParsePKCS1PrivateKey(block.Bytes) - if err != nil { - return nil, fmt.Errorf("parse Key PEM failed : %v", err) - } - return keyPEM, nil - } - keyDER, err := x509.ParsePKCS1PrivateKey(keyRaw) - if err != nil { - return nil, fmt.Errorf("unknown Key format : %v", err) - } - return keyDER, nil -} - -func GetRealCertificateWithTCP(domain string) (*x509.Certificate, error) { - conn, err := tls.Dial("tcp", domain+":443", &tls.Config{ - InsecureSkipVerify: true, // 忽略证书验证 - }) - if err != nil { - return nil, fmt.Errorf("Connect to [%s:443] Failed : %v", domain, err) - } - defer conn.Close() - - // 获取证书链 - certs := conn.ConnectionState().PeerCertificates - if len(certs) > 0 { - return certs[0], nil - } - return nil, fmt.Errorf("No Certificate Exist") -} - -func GetRealCertificateWithHTTPS(domain string) (*x509.Certificate, error) { - client := &http.Client{ - Transport: &http.Transport{ - TLSClientConfig: &tls.Config{ - InsecureSkipVerify: true, // 跳过证书验证,仅用于测试 - }, - }, - } - url := fmt.Sprintf("https://%s", domain) - //yaklog.Debugf(colorutils.SetColor(colorutils.YELLOW_COLOR_TYPE, fmt.Sprintf("get Certificate from : %s", url))) - resp, err := client.Get(url) - if err != nil { - return nil, fmt.Errorf("get Certificate Template failed : %v", err) - } - defer resp.Body.Close() - tlsState := resp.TLS - if tlsState == nil { - return nil, fmt.Errorf("no TLS Connection") - } - if len(tlsState.PeerCertificates) > 0 { - return tlsState.PeerCertificates[0], nil - } - return nil, fmt.Errorf("no Certificate exist") -} - -// ForgedCertificate 用于生成 MITM 证书的函数,传入 CA 证书、密钥和目标域名证书模板 -func ForgedCertificate(caCert *x509.Certificate, caKey *rsa.PrivateKey, realCert *x509.Certificate, key *rsa.PrivateKey) (*x509.Certificate, error) { - certDER := &x509.Certificate{ - SerialNumber: big.NewInt(1234), // 使用新的序列号 - Subject: realCert.Subject, // 复制主体信息,使其看起来与原始证书一致 - Issuer: caCert.Subject, // 使用传入的 CA 证书的颁发者信息 - NotBefore: time.Now(), // 修改有效期 - NotAfter: time.Now().AddDate(1, 0, 0), // 证书有效期为1年 - KeyUsage: x509.KeyUsageDigitalSignature | x509.KeyUsageKeyEncipherment, - ExtKeyUsage: realCert.ExtKeyUsage, - BasicConstraintsValid: true, - DNSNames: realCert.DNSNames, // 保留原始的DNS名 - } - certRAW, err := x509.CreateCertificate(rand.Reader, certDER, caCert, &key.PublicKey, caKey) - if err != nil { - return nil, fmt.Errorf("Failed to Forged Certificate : %v", err) - } - certDER, err = x509.ParseCertificate(certRAW) - if err != nil { - return nil, fmt.Errorf("Failed to Parse Certificate : %v", err) - } - return certDER, nil -} - -func SaveKey(path string, keyDER *rsa.PrivateKey) error { - block := &pem.Block{ - Type: "RSA PRIVATE KEY", - Bytes: x509.MarshalPKCS1PrivateKey(keyDER), - } - keyPEM, err := os.Create(path) - if err != nil { - return fmt.Errorf("Failed to Create Private Key PEM : %v", err) - } - defer keyPEM.Close() - if err = pem.Encode(keyPEM, block); err != nil { - return fmt.Errorf("Failed to Write Private Key PEM : %v", err) - } - return nil -} - -func SaveCertificate(path string, certDER *x509.Certificate) error { - block := &pem.Block{ - Type: "CERTIFICATE", - Bytes: certDER.Raw, - } - certPEM, err := os.Create(path) - if err != nil { - return fmt.Errorf("Failed to Create Certificate PEM : %v", err) - } - defer certPEM.Close() - err = pem.Encode(certPEM, block) - if err != nil { - return fmt.Errorf("Failed to Write Certificate PEM : %v", err) - } - return nil -} diff --git a/pkg/colorutils/print.go b/pkg/colorutils/print.go deleted file mode 100644 index 271b57b..0000000 --- a/pkg/colorutils/print.go +++ /dev/null @@ -1,63 +0,0 @@ -package colorutils - -import ( - "fmt" - "github.com/logrusorgru/aurora" - yaklog "github.com/yaklang/yaklang/common/log" - "net/http" - "net/http/httputil" - "socks2https/setting" -) - -const ( - RED_COLOR_TYPE = iota - YELLOW_COLOR_TYPE - BLUE_COLOR_TYPE - GREEN_COLOR_TYPE - WHITE_COLOR_TYPE - MAGENTA_COLOR_TYPE - - RED_BG_COLOR_TYPE - YELLOW_BG_COLOR_TYPE -) - -var colorMap = map[int]func(arg any) aurora.Value{ - RED_COLOR_TYPE: aurora.BrightRed, - YELLOW_COLOR_TYPE: aurora.BrightYellow, - BLUE_COLOR_TYPE: aurora.BrightBlue, - GREEN_COLOR_TYPE: aurora.BrightGreen, - WHITE_COLOR_TYPE: aurora.BrightWhite, - MAGENTA_COLOR_TYPE: aurora.BrightMagenta, - - RED_BG_COLOR_TYPE: aurora.BgBrightRed, - YELLOW_BG_COLOR_TYPE: aurora.BgBrightYellow, -} - -// SetColor 设置字符串颜色 -func SetColor(colorType int, payload any) string { - str := fmt.Sprintf("%v", payload) - if setting.Config.Log.ColorSwitch { - str = fmt.Sprint(colorMap[colorType](payload)) - } - return str -} - -// DumpRequest 打印更美观的 request 信息 -func DumpRequest(req *http.Request, display bool, colorType int) { - dump, err := httputil.DumpRequestOut(req, display) - if err != nil { - yaklog.Errorf("Dump Request Failed : %v", err) - return - } - yaklog.Debugf("Dump Request : \n%s", SetColor(colorType, string(dump))) -} - -// DumpResponse 打印更美观的 response 信息 -func DumpResponse(resp *http.Response, display bool, colorType int) { - dump, err := httputil.DumpResponse(resp, display) - if err != nil { - yaklog.Errorf("Dump Response Failed : %v", err) - return - } - yaklog.Debugf("Dump Response : \n%s", SetColor(colorType, string(dump))) -} diff --git a/pkg/crypt/aes.go b/pkg/crypt/aes.go deleted file mode 100644 index 906bc5c..0000000 --- a/pkg/crypt/aes.go +++ /dev/null @@ -1,72 +0,0 @@ -package crypt - -import ( - "crypto/aes" - "crypto/cipher" - "fmt" - yaklog "github.com/yaklang/yaklang/common/log" - "socks2https/pkg/colorutils" -) - -func PKCS7AESCBCEncrypt(plainText []byte, key, iv []byte) ([]byte, error) { - block, err := aes.NewCipher(key) - if err != nil { - return nil, fmt.Errorf("parse Key failed: %v", err) - } - paddedText := Pad(plainText, block.BlockSize()) - cipherText := make([]byte, len(paddedText)) - mode := cipher.NewCBCEncrypter(block, iv) - mode.CryptBlocks(cipherText, paddedText) - return cipherText, nil -} - -func AESCBCEncrypt(plainText []byte, key, iv []byte) ([]byte, error) { - block, err := aes.NewCipher(key) - if err != nil { - return nil, fmt.Errorf("parse Key failed: %v", err) - } - cipherText := make([]byte, len(plainText)) - mode := cipher.NewCBCEncrypter(block, iv) - mode.CryptBlocks(cipherText, plainText) - return cipherText, nil -} - -func AESCBCDecrypt(cipherText []byte, key, iv []byte) ([]byte, error) { - block, err := aes.NewCipher(key) - if err != nil { - return nil, fmt.Errorf("parse Key failed : %v", err) - } - if len(iv) != block.BlockSize() { - return nil, fmt.Errorf("invalid IV length: expected %d, got %d", block.BlockSize(), len(iv)) - } - if len(cipherText)%block.BlockSize() != 0 { - return nil, fmt.Errorf("invalid ciphertext length: not a multiple of block size") - } - mode := cipher.NewCBCDecrypter(block, iv) - plainText := make([]byte, len(cipherText)) - mode.CryptBlocks(plainText, cipherText) - //yaklog.Debugf(colorutils.SetColor(colorutils.RED_COLOR_TYPE, fmt.Sprintf("Padded Data Length : %d , Padded Data : %v", len(plainText), plainText))) - return plainText, nil -} - -func PKCS7AESCBCDecrypt(cipherText []byte, key, iv []byte) ([]byte, error) { - block, err := aes.NewCipher(key) - if err != nil { - return nil, fmt.Errorf("parse Key failed : %v", err) - } - if len(iv) != block.BlockSize() { - return nil, fmt.Errorf("invalid IV length: expected %d, got %d", block.BlockSize(), len(iv)) - } - if len(cipherText)%block.BlockSize() != 0 { - return nil, fmt.Errorf("invalid ciphertext length: not a multiple of block size") - } - mode := cipher.NewCBCDecrypter(block, iv) - plainText := make([]byte, len(cipherText)) - mode.CryptBlocks(plainText, cipherText) - yaklog.Debugf(colorutils.SetColor(colorutils.RED_COLOR_TYPE, fmt.Sprintf("Padded Data Length : %d , Padded Data : %v", len(plainText), plainText))) - unPadText, err := UnPad(plainText, block.BlockSize()) - if err != nil { - return nil, err - } - return unPadText, nil -} diff --git a/pkg/crypt/ecb.go b/pkg/crypt/ecb.go deleted file mode 100644 index fdb0c62..0000000 --- a/pkg/crypt/ecb.go +++ /dev/null @@ -1,52 +0,0 @@ -package crypt - -import ( - "crypto/cipher" - "errors" -) - -// ECB分块对象 -type ecb struct { - b cipher.Block - blockSize int -} - -type ecbEncrypter ecb - -// NewECBEncrypter 创建AES ECB模式加密器 -func NewECBEncrypter(b cipher.Block) *ecbEncrypter { - return &ecbEncrypter{b, b.BlockSize()} -} - -// CryptBlocks 加密数据块 -func (e *ecbEncrypter) CryptBlocks(dst, src []byte) error { - if len(src)%e.blockSize != 0 || len(dst) < len(src) { - return errors.New("ecbEncrypter: input not full blocks") - } - for len(src) > 0 { - e.b.Encrypt(dst, src[:e.blockSize]) - src = src[e.blockSize:] - dst = dst[e.blockSize:] - } - return nil -} - -type ecbDecrypter ecb - -// NewECBDecrypter 创建AES ECB模式解密器 -func NewECBDecrypter(b cipher.Block) *ecbDecrypter { - return &ecbDecrypter{b, b.BlockSize()} -} - -// CryptBlocks 解密数据块 -func (e *ecbDecrypter) CryptBlocks(dst, src []byte) error { - if len(src)%e.blockSize != 0 || len(dst) < len(src) { - return errors.New("ecbEncrypter: input not full blocks") - } - for len(src) > 0 { - e.b.Decrypt(dst, src[:e.blockSize]) - src = src[e.blockSize:] - dst = dst[e.blockSize:] - } - return nil -} diff --git a/pkg/crypt/pkcs.go b/pkg/crypt/pkcs.go deleted file mode 100644 index c421f9f..0000000 --- a/pkg/crypt/pkcs.go +++ /dev/null @@ -1,37 +0,0 @@ -package crypt - -import ( - "bytes" - "fmt" - yaklog "github.com/yaklang/yaklang/common/log" -) - -func Pad(plainText []byte, blockSize int) []byte { - paddingLen := blockSize - len(plainText)%blockSize - paddingText := bytes.Repeat([]byte{byte(paddingLen - 1)}, paddingLen) - return append(plainText, paddingText...) -} - -func PKCSPad(cipherText []byte, blockSize int) []byte { - paddingLen := blockSize - len(cipherText)%blockSize - paddingText := bytes.Repeat([]byte{byte(paddingLen)}, paddingLen) - return append(cipherText, paddingText...) -} - -func UnPad(plainText []byte, blockSize int) ([]byte, error) { - length := len(plainText) - if length == 0 || length%blockSize != 0 { - return nil, fmt.Errorf("invalid padding size : length = %d , blockSize = %d", length, blockSize) - } - paddingLen := int(plainText[length-1]) - yaklog.Debugf("Padding length : %d", paddingLen) - if paddingLen < 1 || paddingLen > blockSize || paddingLen > length { - return nil, fmt.Errorf("invalid padding length : paddingLen = %d , blockSize = %d", paddingLen, blockSize) - } - for i := length - paddingLen; i < length; i++ { - if int(plainText[i]) != paddingLen { - return nil, fmt.Errorf("invalid padding value at index %d : expected %d , got %d", i, paddingLen, plainText[i]) - } - } - return plainText[:(length - paddingLen)], nil -} diff --git a/pkg/crypt/prf.go b/pkg/crypt/prf.go deleted file mode 100644 index d8e267f..0000000 --- a/pkg/crypt/prf.go +++ /dev/null @@ -1,46 +0,0 @@ -package crypt - -import ( - "crypto/md5" - "crypto/sha1" - "crypto/sha256" - "crypto/tls" -) - -const ( - LabelMasterSecret = "master secret" - LabelKeyExpansion = "key expansion" - LabelClientFinished = "client finished" - LabelServerFinished = "server finished" - LabelClientEAPMasterSecret = "client EAP master secret" - LabelServerEAPMasterSecret = "server EAP master secret" - LabelExtendedMasterSecret = "extended master secret" - LabelResumptionMasterSecret = "resumption master secret" - LabelExporterMasterSecret = "exporter master secret" - LabelEarlyTrafficSecret = "early traffic secret" - LabelHandshakeTrafficSecret = "handshake traffic secret" - LabelApplicationTrafficSecret = "application traffic secret" - LabelExporter = "EXPORTER" - LabelFinished = "finished" - LabelBinding = "binding" - LabelSessionTicket = "session ticket" -) - -var PRF = map[uint16]prf{ - tls.VersionTLS10: TLS10to11PRF, - tls.VersionTLS11: TLS10to11PRF, - tls.VersionTLS12: TLS12PRF, -} - -type prf func(secret, label, seed []byte, outputLength int) []byte - -var TLS10to11PRF = prf(func(secret, label, seed []byte, outputLength int) []byte { - pMD5 := PHash(secret, append(label, seed...), outputLength, md5.New) - pSHA1 := PHash(secret, append(label, seed...), outputLength, sha1.New) - return XOR(pMD5, pSHA1)[:outputLength] -}) - -var TLS12PRF = prf(func(secret, label, seed []byte, outputLength int) []byte { - pSHA256 := PHash(secret, append(label, seed...), outputLength, sha256.New) - return pSHA256[:outputLength] -}) diff --git a/pkg/crypt/rsa.go b/pkg/crypt/rsa.go deleted file mode 100644 index 02b2486..0000000 --- a/pkg/crypt/rsa.go +++ /dev/null @@ -1,21 +0,0 @@ -package crypt - -import ( - "crypto/rand" - "crypto/rsa" - "fmt" -) - -// EncryptRSAPKCS PKCS1填充 RSA加密 -func EncryptRSAPKCS(pubKey *rsa.PublicKey, plainText []byte) ([]byte, error) { - cipherText, err := rsa.EncryptPKCS1v15(rand.Reader, pubKey, plainText) - if err != nil { - return nil, fmt.Errorf("PKCS1 RSA Encrypt failed : %v", err) - } - return cipherText, nil -} - -// DecryptRSAPKCS PKCS1填充 RSA解密 -func DecryptRSAPKCS(privateKey *rsa.PrivateKey, chiperText []byte) ([]byte, error) { - return rsa.DecryptPKCS1v15(rand.Reader, privateKey, chiperText) -} diff --git a/pkg/crypt/tls.go b/pkg/crypt/tls.go deleted file mode 100644 index 65b79af..0000000 --- a/pkg/crypt/tls.go +++ /dev/null @@ -1,34 +0,0 @@ -package crypt - -import ( - "crypto/hmac" - "hash" -) - -func Label(label string) []byte { - return []byte(label) -} - -func HmacHash(secret, A []byte, hashFunc func() hash.Hash) []byte { - hmacFunc := hmac.New(hashFunc, secret) - hmacFunc.Write(A) - return hmacFunc.Sum(nil) -} - -func PHash(secret, seed []byte, outputLength int, hashFunc func() hash.Hash) []byte { - var result []byte - A := seed - for len(result) < outputLength { - A = HmacHash(secret, A, hashFunc) - result = append(result, HmacHash(secret, append(A, seed...), hashFunc)...) - } - return result -} - -func XOR(pMD5, pSHA1 []byte) []byte { - var result []byte - for i := 0; i < len(pMD5); i++ { - result = append(result, pMD5[i]^pSHA1[i]) - } - return result -} diff --git a/pkg/dnsutils/dnstools.go b/pkg/dnsutils/dnstools.go deleted file mode 100644 index b89f025..0000000 --- a/pkg/dnsutils/dnstools.go +++ /dev/null @@ -1,41 +0,0 @@ -package dnsutils - -import ( - "context" - "fmt" - "net" - "time" -) - -// DNS2IPv4 DNS查询过滤IPv4地址 -func DNS2IPv4(domain, dns string) ([]string, error) { - ips, err := DNS2IP(domain, dns) - if err != nil { - return nil, fmt.Errorf("DNS Query failed : %v", err) - } - ipv4s := make([]string, 0) - for _, ip := range ips { - if ip.To4() != nil { - ipv4s = append(ipv4s, ip.String()) - } - } - return ipv4s, nil -} - -// DNS2IP DNS查询 -func DNS2IP(domain, dns string) ([]net.IP, error) { - resolver := &net.Resolver{ - PreferGo: true, - Dial: func(ctx context.Context, network, address string) (net.Conn, error) { - d := net.Dialer{ - Timeout: time.Second * 5, - } - return d.DialContext(ctx, network, dns+":53") - }, - } - ips, err := resolver.LookupIP(context.Background(), "ip", domain) - if err != nil { - return nil, fmt.Errorf("resolve %s failed : %v", domain, err) - } - return ips, nil -} diff --git a/pkg/finger/Inspect.go b/pkg/finger/Inspect.go deleted file mode 100644 index 7181f4b..0000000 --- a/pkg/finger/Inspect.go +++ /dev/null @@ -1,54 +0,0 @@ -package finger - -import ( - "bufio" - "bytes" - "crypto/tls" - "encoding/binary" - "net/http" - "socks2https/pkg/tlsutils" - "strings" -) - -const ( - TCP = "TCP" - SOCKS = "SOCKS" - TLS = "TLS" - HTTP = "HTTP" -) - -var ( - SOCKSFingers = []byte{0x05, 0x00} - HTTPFingers = []string{ - http.MethodGet, - http.MethodHead, - http.MethodPost, - http.MethodPut, - http.MethodPatch, - http.MethodDelete, - http.MethodConnect, - http.MethodOptions, - http.MethodTrace, - "HTTP/", - } -) - -func Inspect(reader *bufio.Reader) string { - peek, err := reader.Peek(7) - if err != nil { - return TCP - } - if bytes.Equal(peek[:2], SOCKSFingers) { - return SOCKS - } - version := binary.BigEndian.Uint16(peek[1:3]) - if _, ok := tlsutils.ContentType[peek[0]]; ok && version >= tls.VersionSSL30 && version <= tls.VersionTLS13 { - return TLS - } - for _, finger := range HTTPFingers { - if strings.Contains(string(peek), finger) { - return HTTP - } - } - return TCP -} diff --git a/pkg/httptools/httptools.go b/pkg/httptools/httptools.go deleted file mode 100644 index 1bf461f..0000000 --- a/pkg/httptools/httptools.go +++ /dev/null @@ -1,38 +0,0 @@ -package httptools - -import ( - "bufio" - "fmt" - "net/http" - "strconv" - "strings" -) - -func ReadRequest(reader *bufio.Reader, scheme string) (*http.Request, error) { - req, err := http.ReadRequest(reader) - if err != nil { - return nil, fmt.Errorf("Read Request Failed : %v", err) - } - req.URL.Scheme = scheme - req.URL.Host = req.Host - req.RequestURI = "" - return req, nil -} - -func NewConnectResponse() *http.Response { - return &http.Response{ - ProtoMajor: 1, - ProtoMinor: 1, - StatusCode: http.StatusOK, - Status: "Connection Established", - } -} - -func ParseHostAndPort(addr string) (string, uint16, error) { - str := strings.Split(addr, ":") - port, err := strconv.ParseUint(str[1], 10, 16) - if err != nil { - return str[0], 0, fmt.Errorf("Failed to Parse Port From Address : %v", err) - } - return str[0], uint16(port), nil -} diff --git a/pkg/ioutils/ioutils.go b/pkg/ioutils/ioutils.go deleted file mode 100644 index 7fe9d4e..0000000 --- a/pkg/ioutils/ioutils.go +++ /dev/null @@ -1,21 +0,0 @@ -package ioutils - -import ( - "bufio" - "fmt" -) - -func ReadBytes(reader *bufio.Reader, length int) ([]byte, error) { - if length <= 0 { - return nil, fmt.Errorf("length must be greater than 0") - } - buf := make([]byte, length) - for offset := 0; offset < length; { - n, err := reader.Read(buf[offset:]) - if err != nil { - return nil, err - } - offset += n - } - return buf, nil -} diff --git a/pkg/osutils/file.go b/pkg/osutils/file.go deleted file mode 100644 index 03d25ee..0000000 --- a/pkg/osutils/file.go +++ /dev/null @@ -1,16 +0,0 @@ -package osutils - -import ( - "os" - "path/filepath" -) - -func MkDir(path string) error { - dirPath := filepath.Dir(path) - if _, err := os.Stat(dirPath); os.IsNotExist(err) { - if err = os.MkdirAll(dirPath, os.ModePerm); err != nil { - return err - } - } - return nil -} diff --git a/pkg/tlsutils/alert.go b/pkg/tlsutils/alert.go deleted file mode 100644 index b2caced..0000000 --- a/pkg/tlsutils/alert.go +++ /dev/null @@ -1,113 +0,0 @@ -package tlsutils - -import ( - "fmt" -) - -// 定义TLS Alert级别常量 -const ( - AlertLevelWarning uint8 = 1 // 警告级别 - AlertLevelFatal uint8 = 2 // 严重错误级别 -) - -// 定义TLS Alert描述常量 -const ( - AlertDescriptionCloseNotify uint8 = 0 // 关闭通知 - AlertDescriptionUnexpectedMessage uint8 = 10 // 意外的消息 - AlertDescriptionBadRecordMAC uint8 = 20 // 错误的记录MAC - AlertDescriptionDecryptionFailed uint8 = 21 // 解密失败 (仅TLS 1.0) - AlertDescriptionRecordOverflow uint8 = 22 // 记录溢出 - AlertDescriptionDecompressionFailure uint8 = 30 // 解压失败 - AlertDescriptionHandshakeFailure uint8 = 40 // 握手失败 - AlertDescriptionNoCertificate uint8 = 41 // 没有证书 (SSL 3.0) - AlertDescriptionBadCertificate uint8 = 42 // 错误的证书 - AlertDescriptionUnsupportedCertificate uint8 = 43 // 不支持的证书 - AlertDescriptionCertificateRevoked uint8 = 44 // 证书被撤销 - AlertDescriptionCertificateExpired uint8 = 45 // 证书已过期 - AlertDescriptionCertificateUnknown uint8 = 46 // 未知证书 - AlertDescriptionIllegalParameter uint8 = 47 // 非法参数 - AlertDescriptionUnknownCA uint8 = 48 // 未知的CA - AlertDescriptionAccessDenied uint8 = 49 // 访问被拒绝 - AlertDescriptionDecodeError uint8 = 50 // 解码错误 - AlertDescriptionDecryptError uint8 = 51 // 解密错误 - AlertDescriptionProtocolVersion uint8 = 70 // 协议版本错误 - AlertDescriptionInsufficientSecurity uint8 = 71 // 安全级别不足 (TLS 1.2) - AlertDescriptionInternalError uint8 = 80 // 内部错误 - AlertDescriptionInappropriateFallback uint8 = 86 // 不适当的回退 (TLS 1.3) - AlertDescriptionUserCanceled uint8 = 90 // 用户取消 - AlertDescriptionNoRenegotiation uint8 = 100 // 不允许重新协商 - AlertDescriptionMissingExtension uint8 = 109 // 缺少扩展 (TLS 1.3) - AlertDescriptionUnsupportedExtension uint8 = 110 // 不支持的扩展 - AlertDescriptionCertificateRequired uint8 = 116 // 需要证书 (TLS 1.3) - AlertDescriptionNoApplicationProtocol uint8 = 120 // 没有应用层协议 (TLS 1.3) -) - -var AlertLevel = map[uint8]string{ - AlertLevelWarning: "WARNING", - AlertLevelFatal: "FATAL", -} - -var AlertDescription = map[uint8]string{ - AlertDescriptionCloseNotify: "Close Notify", - AlertDescriptionUnexpectedMessage: "Unexpected Message", - AlertDescriptionBadRecordMAC: "Bad Record MAC", - AlertDescriptionDecryptionFailed: "Decryption Failed", - AlertDescriptionRecordOverflow: "Record Overflow", - AlertDescriptionDecompressionFailure: "Decompression Failure", - AlertDescriptionHandshakeFailure: "Handshake Failure", - AlertDescriptionNoCertificate: "No Certificate", - AlertDescriptionBadCertificate: "Bad Certificate", - AlertDescriptionUnsupportedCertificate: "Unsupported Certificate", - AlertDescriptionCertificateRevoked: "Certificate Revoked", - AlertDescriptionCertificateExpired: "Certificate Expired", - AlertDescriptionCertificateUnknown: "Certificate Unknown", - AlertDescriptionIllegalParameter: "Illegal Parameter", - AlertDescriptionUnknownCA: "Unknown CA", - AlertDescriptionAccessDenied: "Access Denied", - AlertDescriptionDecodeError: "Decode Error", - AlertDescriptionDecryptError: "Decrypt Error", - AlertDescriptionProtocolVersion: "Protocol Version", - AlertDescriptionInsufficientSecurity: "Insufficient Security", - AlertDescriptionInternalError: "Internal Error", - AlertDescriptionInappropriateFallback: "Inappropriate Fallback", - AlertDescriptionUserCanceled: "User Canceled", - AlertDescriptionNoRenegotiation: "No Renegotiation", - AlertDescriptionMissingExtension: "Missing Extension", - AlertDescriptionUnsupportedExtension: "Unsupported Extension", - AlertDescriptionCertificateRequired: "Certificate Required", - AlertDescriptionNoApplicationProtocol: "No Application Protocol", -} - -// Alert 告警消息类型 -type Alert struct { - Level uint8 `json:"level,omitempty"` // 告警级别 - Description uint8 `json:"description,omitempty"` // 告警描述 -} - -func ParseAlert(data []byte) (*Alert, error) { - if len(data) != 2 { - return nil, fmt.Errorf("Alert is invaild") - } - return &Alert{ - Level: data[0], - Description: data[1], - }, nil -} - -func (a *Alert) GetRaw() []byte { - return []byte{a.Level, a.Description} -} - -func NewAlert(version uint16, level, description uint8) *Record { - alert := &Alert{ - Level: level, - Description: description, - } - return &Record{ - ContentType: ContentTypeAlert, - Version: version, - Length: 2, - Fragment: alert.GetRaw(), - Alert: alert, - } -} diff --git a/pkg/tlsutils/application_data.go b/pkg/tlsutils/application_data.go deleted file mode 100644 index 51066d1..0000000 --- a/pkg/tlsutils/application_data.go +++ /dev/null @@ -1,11 +0,0 @@ -package tlsutils - -func NewApplicationData(version uint16, fragment []byte) (*Record, error) { - return &Record{ - ContentType: ContentTypeApplicationData, - Version: version, - Length: uint16(len(fragment)), - Fragment: fragment, - ApplicationData: fragment, - }, nil -} diff --git a/pkg/tlsutils/certificate.go b/pkg/tlsutils/certificate.go deleted file mode 100644 index 6ca899c..0000000 --- a/pkg/tlsutils/certificate.go +++ /dev/null @@ -1,76 +0,0 @@ -package tlsutils - -import ( - "crypto/x509" - "fmt" -) - -// Certificate 证书消息类型 -type Certificate struct { - CertificatesLength uint32 `json:"certificatesLength,omitempty"` // 3个字节 - Certificates []struct { - CertificateLength uint32 // 3个字节 - Certificate []byte - } `json:"certificates,omitempty"` -} - -func NewCertificate(version uint16, certDERs []*x509.Certificate) (*Record, error) { - certificate := &Certificate{} - for _, certDER := range certDERs { - certificateLength := uint32(len(certDER.Raw)) - certificate.CertificatesLength += 3 + certificateLength - certificate.Certificates = append(certificate.Certificates, struct { - CertificateLength uint32 - Certificate []byte - }{CertificateLength: certificateLength, Certificate: certDER.Raw}) - } - certificateRaw := certificate.GetRaw() - handshake := &Handshake{ - HandshakeType: HandshakeTypeCertificate, - Length: uint32(len(certificateRaw)), - Certificate: certificate, - Payload: certificateRaw, - } - handshakeRaw := handshake.GetRaw() - return &Record{ - ContentType: ContentTypeHandshake, - Version: version, - Length: uint16(len(handshakeRaw)), - Handshake: handshake, - Fragment: handshakeRaw, - }, nil -} - -func (c *Certificate) GetRaw() []byte { - certificatesLength := []byte{byte(c.CertificatesLength >> 16), byte(c.CertificatesLength >> 8), byte(c.CertificatesLength)} - certificates := certificatesLength - for _, certificate := range c.Certificates { - certificateLength := []byte{byte(certificate.CertificateLength >> 16), byte(certificate.CertificateLength >> 8), byte(certificate.CertificateLength)} - certificates = append(certificates, append(certificateLength, certificate.Certificate...)...) - } - return certificates -} - -// ParseCertificate 从 []byte 数据解析出 Certificate 结构体 -func ParseCertificate(data []byte) (*Certificate, error) { - if len(data) < 3 { - return nil, fmt.Errorf("TLS Handshake Data is incomplete") - } - offset := 0 - certificatesLength := uint32(data[0])<<16 | uint32(data[1])<<8 | uint32(data[2]) - offset += 3 - certificate := &Certificate{CertificatesLength: certificatesLength} - for offset < len(data) { - if offset+3 > len(data) { - return nil, fmt.Errorf("Certificate Entry is invalid") - } - certificateLength := uint32(data[offset])<<16 | uint32(data[offset+1])<<8 | uint32(data[offset+2]) - offset += 3 - certificate.Certificates = append(certificate.Certificates, struct { - CertificateLength uint32 - Certificate []byte - }{CertificateLength: certificateLength, Certificate: data[offset : offset+int(certificateLength)]}) - offset += int(certificateLength) - } - return certificate, nil -} diff --git a/pkg/tlsutils/change_cipher_spec.go b/pkg/tlsutils/change_cipher_spec.go deleted file mode 100644 index 8232e1a..0000000 --- a/pkg/tlsutils/change_cipher_spec.go +++ /dev/null @@ -1,10 +0,0 @@ -package tlsutils - -func NewChangeCipherSpec(version uint16) *Record { - return &Record{ - ContentType: ContentTypeChangeCipherSpec, - Version: version, - Length: 1, - Fragment: []byte{0x01}, - } -} diff --git a/pkg/tlsutils/client_hello.go b/pkg/tlsutils/client_hello.go deleted file mode 100644 index 781b562..0000000 --- a/pkg/tlsutils/client_hello.go +++ /dev/null @@ -1,55 +0,0 @@ -package tlsutils - -import ( - "encoding/binary" -) - -// ClientHello 客户端握手记录 -type ClientHello struct { - Version uint16 `json:"version,omitempty"` - Random [32]byte `json:"random,omitempty"` - SessionIDLength uint8 `json:"sessionIDLength,omitempty"` - SessionID []byte `json:"sessionID,omitempty"` - CipherSuitesLength uint16 `json:"cipherSuitesLength,omitempty"` - CipherSuites []uint16 `json:"cipherSuites,omitempty"` - CompressionMethodsLength uint8 `json:"compressionMethodsLength,omitempty"` - CompressionMethods []uint8 `json:"compressionMethods,omitempty"` - ExtensionsLength uint16 `json:"extensionsLength,omitempty"` - Extensions []*Extension `json:"extensions,omitempty"` -} - -// ParseClientHello 解析Clienthello函数 -func ParseClientHello(data []byte) (*ClientHello, error) { - clientHello := &ClientHello{ - Version: binary.BigEndian.Uint16(data[0:2]), - Random: [32]byte(data[2:34]), - SessionIDLength: data[34], - } - offset := 35 - clientHello.SessionID = data[offset : offset+int(clientHello.SessionIDLength)] - offset += int(clientHello.SessionIDLength) - clientHello.CipherSuitesLength = binary.BigEndian.Uint16(data[offset : offset+2]) - offset += 2 - for i := 0; i < int(clientHello.CipherSuitesLength/2); i++ { - clientHello.CipherSuites = append(clientHello.CipherSuites, binary.BigEndian.Uint16(data[offset:offset+2])) - offset += 2 - } - clientHello.CompressionMethodsLength = data[offset] - offset += 1 - for i := 0; i < int(clientHello.CompressionMethodsLength); i++ { - clientHello.CompressionMethods = append(clientHello.CompressionMethods, data[offset]) - offset += 1 - } - clientHello.ExtensionsLength = binary.BigEndian.Uint16(data[offset : offset+2]) - offset += 2 - extensions := data[offset : offset+int(clientHello.ExtensionsLength)] - for i := 0; i < int(clientHello.ExtensionsLength); { - extension, err := ParseExtension(extensions[i:]) - if err != nil { - return nil, err - } - clientHello.Extensions = append(clientHello.Extensions, extension) - i += 2 + 2 + int(extension.Length) - } - return clientHello, nil -} diff --git a/pkg/tlsutils/client_key_exchange.go b/pkg/tlsutils/client_key_exchange.go deleted file mode 100644 index 8e96e93..0000000 --- a/pkg/tlsutils/client_key_exchange.go +++ /dev/null @@ -1,43 +0,0 @@ -package tlsutils - -import ( - "encoding/binary" - "fmt" - "socks2https/context" -) - -// ClientKeyExchange 定义 ClientKeyExchange 的通用接口 -type ClientKeyExchange interface { - Parse(data []byte) error -} - -// RSAClientKeyExchange 表示 RSA 密钥交换的 ClientKeyExchange -type RSAClientKeyExchange struct { - EncrypedPreMasterLength uint16 - EncrypedPreMasterSecret []byte -} - -// Parse 实现 ClientKeyExchange 接口的 Parse 方法 -func (r *RSAClientKeyExchange) Parse(data []byte) error { - if len(data) < 2 { - return fmt.Errorf("RSA ClientKeyExchange is invalid") - } - r.EncrypedPreMasterLength = binary.BigEndian.Uint16(data[0:2]) - r.EncrypedPreMasterSecret = data[2 : 2+r.EncrypedPreMasterLength] - return nil -} - -// ParseClientKeyExchange 解析 ClientKeyExchange 消息 -func ParseClientKeyExchange(data []byte, ctx *context.Context) (ClientKeyExchange, error) { - var clientKeyExchange ClientKeyExchange - switch ctx.TLSContext.KeyExchange { - case context.KeyExchangeRSA: - clientKeyExchange = &RSAClientKeyExchange{} - default: - return nil, fmt.Errorf("not supported Client Key Exchange Algorithm : %d", ctx.TLSContext.KeyExchange) - } - if err := clientKeyExchange.Parse(data); err != nil { - return nil, err - } - return clientKeyExchange, nil -} diff --git a/pkg/tlsutils/extension.go b/pkg/tlsutils/extension.go deleted file mode 100644 index 9a7cd6c..0000000 --- a/pkg/tlsutils/extension.go +++ /dev/null @@ -1,135 +0,0 @@ -package tlsutils - -import ( - "encoding/binary" - "fmt" - yaklog "github.com/yaklang/yaklang/common/log" - "socks2https/pkg/colorutils" -) - -const ( - ExtensionTypeServerName uint16 = 0x0000 // server_name - ExtensionTypeMaxFragmentLength uint16 = 0x0001 // max_fragment_length - ExtensionTypeStatusRequest uint16 = 0x0005 // status_request - ExtensionTypeSupportedGroups uint16 = 0x000a // supported_groups (formerly known as "elliptic_curves") - ExtensionTypeSignatureAlgorithms uint16 = 0x000d // signature_algorithms - ExtensionTypeUseSrtp uint16 = 0x000e // use_srtp - ExtensionTypeHeartbeat uint16 = 0x000f // heartbeat - ExtensionTypeApplicationLayerProtocolNegotiation uint16 = 0x0010 // application_layer_protocol_negotiation (ALPN) - ExtensionTypeSignedCertificateTimestamp uint16 = 0x0012 // signed_certificate_timestamp - ExtensionTypeClientCertificateType uint16 = 0x0013 // client_certificate_type - ExtensionTypeServerCertificateType uint16 = 0x0014 // server_certificate_type - ExtensionTypePadding uint16 = 0x0015 // padding - ExtensionTypePreSharedKey uint16 = 0x0029 // pre_shared_key (TLS 1.3) - ExtensionTypeEarlyData uint16 = 0x002a // early_data (TLS 1.3) - ExtensionTypeSupportedVersions uint16 = 0x002b // supported_versions (TLS 1.3) - ExtensionTypeCookie uint16 = 0x002c // cookie (TLS 1.3) - ExtensionTypePskKeyExchangeModes uint16 = 0x002d // psk_key_exchange_modes (TLS 1.3) - ExtensionTypeCertificateAuthorities uint16 = 0x002f // certificate_authorities (TLS 1.3) - ExtensionTypeOidFilters uint16 = 0x0030 // oid_filters (TLS 1.3) - ExtensionTypePostHandshakeAuth uint16 = 0x0031 // post_handshake_auth (TLS 1.3) - ExtensionTypeSignatureAlgorithmsCert uint16 = 0x0032 // signature_algorithms_cert (TLS 1.3) - ExtensionTypeKeyShare uint16 = 0x0033 // key_share (TLS 1.3) -) - -// Extension 扩展字段 -type Extension struct { - Type uint16 `json:"type"` - Length uint16 `json:"length"` - Payload []byte `json:"payload,omitempty"` - ServerName *ServerName `json:"serverName,omitempty"` -} - -func ParseExtension(data []byte) (*Extension, error) { - if len(data) < 4 { - return nil, fmt.Errorf("Extension is invaild") - } - extension := &Extension{ - Type: binary.BigEndian.Uint16(data[0:2]), - Length: binary.BigEndian.Uint16(data[2:4]), - } - if len(data) < 4+int(extension.Length) { - return nil, fmt.Errorf("Extension is incomplete") - } - extension.Payload = data[4 : 4+extension.Length] - switch extension.Type { - case ExtensionTypeServerName: - serverName, err := ParseServerName(extension.Payload) - if err != nil { - return nil, fmt.Errorf("parse ServerName failed : %v", err) - } - extension.ServerName = serverName - } - return extension, nil -} - -func (e *Extension) GetRaw() []byte { - typ := make([]byte, 2) - binary.BigEndian.PutUint16(typ, e.Type) - length := make([]byte, 2) - binary.BigEndian.PutUint16(length, e.Length) - extension := append(typ, length...) - if e.Payload == nil { - switch e.Type { - case ExtensionTypeServerName: - return append(extension, e.ServerName.GetRaw()...) - default: - yaklog.Warnf(colorutils.SetColor(colorutils.MAGENTA_COLOR_TYPE, fmt.Sprintf("not support Extension Type : %d", e.Type))) - } - } - return append(extension, e.Payload...) -} - -type ServerName struct { - ListLength uint16 `json:"listLength"` - List []struct { - Type uint8 `json:"type"` - Length uint16 `json:"length"` - Name string `json:"name"` - } `json:"list"` -} - -func ParseServerName(data []byte) (*ServerName, error) { - if len(data) < 2 { - return nil, fmt.Errorf("ServerName is invaild") - } - serverName := &ServerName{ListLength: binary.BigEndian.Uint16(data[:2])} - if len(data) != 2+int(serverName.ListLength) { - return nil, fmt.Errorf("ServerName is incomplete") - } - offset := 2 - for i := 0; offset < len(data); i++ { - if offset+3 > len(data) { - return nil, fmt.Errorf("ServerName Payload is invalid") - } - payload := struct { - Type uint8 `json:"type"` - Length uint16 `json:"length"` - Name string `json:"name"` - }{} - payload.Type, payload.Length = data[offset], binary.BigEndian.Uint16(data[offset+1:offset+3]) - offset += 3 - index := offset + int(payload.Length) - if index > len(data) { - return nil, fmt.Errorf("ServerName Payload is incomplete") - } - payload.Name = string(data[offset:index]) - offset = index - serverName.List = append(serverName.List, payload) - } - return serverName, nil -} - -func (s *ServerName) GetRaw() []byte { - listLength := make([]byte, 2) - binary.BigEndian.PutUint16(listLength, s.ListLength) - serverName := listLength - for _, payload := range s.List { - serverName = append(serverName, payload.Type) - length := make([]byte, 2) - binary.BigEndian.PutUint16(length, payload.Length) - serverName = append(serverName, length...) - serverName = append(serverName, []byte(payload.Name)...) - } - return serverName -} diff --git a/pkg/tlsutils/finished.go b/pkg/tlsutils/finished.go deleted file mode 100644 index 9869196..0000000 --- a/pkg/tlsutils/finished.go +++ /dev/null @@ -1,70 +0,0 @@ -package tlsutils - -import ( - "crypto/sha256" - "crypto/tls" - "hash" - "socks2https/context" - "socks2https/pkg/crypt" -) - -const ( - // TLS 1.2 Cipher Suites - TLS_RSA_WITH_AES_128_CBC_SHA uint16 = 0x002F - TLS_RSA_WITH_AES_256_CBC_SHA uint16 = 0x0035 - TLS_RSA_WITH_AES_128_CBC_SHA256 uint16 = 0x003C - TLS_RSA_WITH_AES_256_CBC_SHA256 uint16 = 0x003D - TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA uint16 = 0xC013 - TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA uint16 = 0xC014 - TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 uint16 = 0xC027 - TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384 uint16 = 0xC028 - - // TLS 1.3 Cipher Suites - TLS_AES_128_GCM_SHA256 uint16 = 0x1301 - TLS_AES_256_GCM_SHA384 uint16 = 0x1302 - TLS_CHACHA20_POLY1305_SHA256 uint16 = 0x1303 - TLS_AES_128_CCM_SHA256 uint16 = 0x1304 - TLS_AES_128_CCM_8_SHA256 uint16 = 0x1305 - - // Other Common Cipher Suites - TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 uint16 = 0xC02B - TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 uint16 = 0xC02C - TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 uint16 = 0xC02F - TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 uint16 = 0xC030 - TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256 uint16 = 0xCCA9 - TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256 uint16 = 0xCCA8 -) - -// VerifyPRF 消息记录校验算法 -func VerifyPRF(version uint16, secret, label []byte, handshakeMessages [][]byte, outputLength int) []byte { - var hashFunc hash.Hash - switch version { - case tls.VersionTLS12: - hashFunc = sha256.New() - default: - return nil - } - for _, message := range handshakeMessages { - hashFunc.Write(message) - } - return crypt.PRF[version](secret, label, hashFunc.Sum(nil), outputLength) -} - -func NewFinished(ctx *context.Context) *Record { - verifyData := VerifyPRF(ctx.TLSContext.Version, ctx.TLSContext.MasterSecret, []byte(crypt.LabelServerFinished), ctx.TLSContext.HandshakeMessages, 12) - - handshake := &Handshake{ - HandshakeType: HandshakeTypeFinished, - Length: uint32(len(verifyData)), - Payload: verifyData, - Finished: verifyData, - } - handshakeRaw := handshake.GetRaw() - return &Record{ - ContentType: ContentTypeHandshake, - Version: ctx.TLSContext.Version, - Length: uint16(len(handshakeRaw)), - Fragment: handshakeRaw, - Handshake: handshake, - } -} diff --git a/pkg/tlsutils/handshake.go b/pkg/tlsutils/handshake.go deleted file mode 100644 index 947dd38..0000000 --- a/pkg/tlsutils/handshake.go +++ /dev/null @@ -1,106 +0,0 @@ -package tlsutils - -import ( - "fmt" - yaklog "github.com/yaklang/yaklang/common/log" - "socks2https/context" - "socks2https/pkg/colorutils" -) - -// TLS 握手消息类型 -const ( - HandshakeTypeHelloRequest uint8 = 0x00 // 请求客户端发起Hello消息 - HandshakeTypeClientHello uint8 = 0x01 // 客户端发起握手请求 - HandshakeTypeServerHello uint8 = 0x02 // 服务器响应客户端Hello消息 - HandshakeTypeHelloRetryRequest uint8 = 0x03 // 服务器请求客户端重新发起Hello消息 - HandshakeTypeNewSessionTicket uint8 = 0x04 // 会话票据 - HandshakeTypeEndOfEarlyData uint8 = 0x05 // 结束早期数据交换 - HandshakeTypeCertificate uint8 = 0x0B // 服务器或客户端发送的证书 - HandshakeTypeServerKeyExchange uint8 = 0x0C // 服务器密钥交换 - HandshakeTypeCertificateRequest uint8 = 0x0D // 服务器请求客户端证书 - HandshakeTypeServerHelloDone uint8 = 0x0E // 服务器完成Hello阶段 - HandshakeTypeCertificateVerify uint8 = 0x0F // 客户端或服务器验证证书 - HandshakeTypeClientKeyExchange uint8 = 0x10 // 客户端密钥交换 - HandshakeTypeFinished uint8 = 0x14 // 握手完成消息 -) - -var HandshakeType = map[byte]string{ - HandshakeTypeHelloRequest: "Hello Request", - HandshakeTypeClientHello: "Client Hello", - HandshakeTypeServerHello: "Server Hello", - HandshakeTypeHelloRetryRequest: "Hello Retry Request", - HandshakeTypeNewSessionTicket: "New Session Ticket", - HandshakeTypeEndOfEarlyData: "End of Early Data", - HandshakeTypeCertificate: "Certificate", - HandshakeTypeServerKeyExchange: "Server Key Exchange", - HandshakeTypeCertificateRequest: "Certificate Request", - HandshakeTypeServerHelloDone: "Server Hello Done", - HandshakeTypeCertificateVerify: "Certificate Verify", - HandshakeTypeClientKeyExchange: "Client Key Exchange", - HandshakeTypeFinished: "Finished", -} - -// Handshake 握手消息记录 -type Handshake struct { - HandshakeType uint8 `json:"handshakeType,omitempty"` // 握手消息类型 - Length uint32 `json:"length,omitempty"` // 有效载荷长度(3 字节) - Payload []byte `json:"payload,omitempty"` // 有效载荷数据 - ClientHello *ClientHello `json:"clientHello,omitempty"` - ServerHello *ServerHello `json:"serverHello,omitempty"` - Certificate *Certificate `json:"certificate,omitempty"` - ClientKeyExchange ClientKeyExchange `json:"clientKeyExchange,omitempty"` - Finished []byte `json:"finished,omitempty"` -} - -func ParseHandshake(data []byte, ctx *context.Context) (*Handshake, error) { - if len(data) < 4 { - return nil, fmt.Errorf("TLS Handshake is invaild") - } - handshake := &Handshake{ - HandshakeType: data[0], - Length: uint32(data[1])<<16 | uint32(data[2])<<8 | uint32(data[3]), - } - if len(data) != 4+int(handshake.Length) { - return nil, fmt.Errorf("TLS Handshake Payload is incomplete") - } - handshake.Payload = data[4 : 4+handshake.Length] - switch handshake.HandshakeType { - case HandshakeTypeClientHello: - clientHello, err := ParseClientHello(handshake.Payload) - if err != nil { - return nil, err - } - handshake.ClientHello = clientHello - case HandshakeTypeClientKeyExchange: - clientKeyExchange, err := ParseClientKeyExchange(handshake.Payload, ctx) - if err != nil { - return nil, err - } - handshake.ClientKeyExchange = clientKeyExchange - case HandshakeTypeFinished: - handshake.Finished = data[4 : 4+handshake.Length] - default: - yaklog.Warnf(colorutils.SetColor(colorutils.MAGENTA_COLOR_TYPE, fmt.Sprintf("not support Handshake Type : %d", handshake.HandshakeType))) - } - return handshake, nil -} - -func (h *Handshake) GetRaw() []byte { - length := []byte{byte(h.Length >> 16), byte(h.Length >> 8), byte(h.Length)} - handshake := append([]byte{h.HandshakeType}, length...) - if h.Payload == nil { - switch h.HandshakeType { - case HandshakeTypeServerHello: - return append(handshake, h.ServerHello.GetRaw()...) - case HandshakeTypeCertificate: - return append(handshake, h.Certificate.GetRaw()...) - case HandshakeTypeServerHelloDone: - return handshake - case HandshakeTypeFinished: - return append(handshake, h.Payload...) - default: - yaklog.Warnf(colorutils.SetColor(colorutils.MAGENTA_COLOR_TYPE, fmt.Sprintf("not support Handshake Type : %d", h.HandshakeType))) - } - } - return append(handshake, h.Payload...) -} diff --git a/pkg/tlsutils/server_hello.go b/pkg/tlsutils/server_hello.go deleted file mode 100644 index 5abf086..0000000 --- a/pkg/tlsutils/server_hello.go +++ /dev/null @@ -1,67 +0,0 @@ -package tlsutils - -import ( - "crypto/rand" - "encoding/binary" - "fmt" - "time" -) - -// ServerHello 服务端握手消息记录 -type ServerHello struct { - Version uint16 `json:"version,omitempty"` - Random [32]byte `json:"random,omitempty"` - SessionIDLength uint8 `json:"sessionIDLength,omitempty"` - SessionID []byte `json:"sessionID,omitempty"` - CipherSuite uint16 `json:"cipherSuite,omitempty"` - CompressionMethod uint8 `json:"compressionMethod,omitempty"` - ExtensionsLength uint16 `json:"extensionsLength,omitempty"` - Extensions []*Extension `json:"extensions,omitempty"` -} - -func (s *ServerHello) GetRaw() []byte { - version := make([]byte, 2) - binary.BigEndian.PutUint16(version, s.Version) - serverHello := append(version, append(s.Random[:], append([]byte{s.SessionIDLength}, s.SessionID...)...)...) - cipherSuite := make([]byte, 2) - binary.BigEndian.PutUint16(cipherSuite, s.CipherSuite) - serverHello = append(serverHello, append(cipherSuite, s.CompressionMethod)...) - extensionsLength := make([]byte, 2) - binary.BigEndian.PutUint16(extensionsLength, s.ExtensionsLength) - serverHello = append(serverHello, extensionsLength...) - for _, extension := range s.Extensions { - serverHello = append(serverHello, extension.GetRaw()...) - } - return serverHello -} - -func NewServerHello(version, cipherSuite uint16) (*Record, error) { - serverHello := &ServerHello{Version: version} - binary.BigEndian.PutUint32(serverHello.Random[0:4], uint32(time.Now().Unix())) - if _, err := rand.Read(serverHello.Random[4:]); err != nil { - return nil, fmt.Errorf("create Random failed : %v", err) - } - serverHello.SessionIDLength = 32 - serverHello.SessionID = make([]byte, serverHello.SessionIDLength) - if _, err := rand.Read(serverHello.SessionID); err != nil { - return nil, fmt.Errorf("create SessionID failed : %v", err) - } - serverHello.CipherSuite = cipherSuite - serverHello.CompressionMethod = 0 - serverHello.ExtensionsLength = 0 - serverHelloRaw := serverHello.GetRaw() - handshake := &Handshake{ - HandshakeType: HandshakeTypeServerHello, - Length: uint32(len(serverHelloRaw)), - ServerHello: serverHello, - Payload: serverHelloRaw, - } - handshakeRaw := handshake.GetRaw() - return &Record{ - ContentType: ContentTypeHandshake, - Version: version, - Length: uint16(len(handshakeRaw)), - Handshake: handshake, - Fragment: handshakeRaw, - }, nil -} diff --git a/pkg/tlsutils/server_hello_done.go b/pkg/tlsutils/server_hello_done.go deleted file mode 100644 index 64aa416..0000000 --- a/pkg/tlsutils/server_hello_done.go +++ /dev/null @@ -1,18 +0,0 @@ -package tlsutils - -// NewServerHelloDone 创建一个ServerHelloDone消息记录 -func NewServerHelloDone(version uint16) *Record { - handshake := &Handshake{ - HandshakeType: HandshakeTypeServerHelloDone, - Length: 0, - } - handshakeRaw := handshake.GetRaw() - - return &Record{ - ContentType: ContentTypeHandshake, - Version: version, - Length: uint16(len(handshakeRaw)), - Handshake: handshake, - Fragment: handshakeRaw, - } -} diff --git a/pkg/tlsutils/tls_filter.go b/pkg/tlsutils/tls_filter.go deleted file mode 100644 index b421c72..0000000 --- a/pkg/tlsutils/tls_filter.go +++ /dev/null @@ -1,52 +0,0 @@ -package tlsutils - -import ( - "bufio" - "fmt" - "socks2https/context" - "socks2https/pkg/colorutils" -) - -func readUnknownRecord(data []byte, ctx *context.Context) (*Record, error) { - if ctx.TLSContext.ClientEncrypted && data[0] != ContentTypeChangeCipherSpec { - record, err := ParseBlockRecord(data, ctx) - if err != nil { - return nil, err - } - return record, nil - } - record, err := ParseRecord(data, ctx) - if err != nil { - return nil, err - } - return record, nil -} - -// FilterRecord 消息记录过滤器,过滤出想要的消息记录类型 -func FilterRecord(reader *bufio.Reader, contentType uint8, handshakeType uint8, ctx *context.Context) (*Record, error) { - unknownRecord, err := ReadTLSRecord(reader) - if err != nil { - return nil, err - } - - record, err := readUnknownRecord(unknownRecord, ctx) - if err != nil { - return nil, err - } - - if record.ContentType != contentType { - switch record.ContentType { - case ContentTypeAlert: - alertLevel := colorutils.SetColor(colorutils.RED_COLOR_TYPE, AlertLevel[record.Alert.Level]) - alertDescription := colorutils.SetColor(colorutils.RED_COLOR_TYPE, AlertDescription[record.Alert.Description]) - return nil, fmt.Errorf("[%s] [%s] %s", colorutils.SetColor(colorutils.YELLOW_COLOR_TYPE, "Alert"), alertLevel, alertDescription) - default: - return nil, fmt.Errorf("not supported Content Type : %v , Value : %d", colorutils.SetColor(colorutils.YELLOW_COLOR_TYPE, ContentType[record.ContentType]), record.ContentType) - } - } - - if record.ContentType == ContentTypeHandshake && record.Handshake.HandshakeType != handshakeType { - return nil, fmt.Errorf("[%s] [%s] Unknown Handshake Type : %d", colorutils.SetColor(colorutils.YELLOW_COLOR_TYPE, "Handshake"), colorutils.SetColor(colorutils.YELLOW_COLOR_TYPE, HandshakeType[record.Handshake.HandshakeType]), record.Handshake.HandshakeType) - } - return record, nil -} diff --git a/pkg/tlsutils/tls_record.go b/pkg/tlsutils/tls_record.go deleted file mode 100644 index fd61c03..0000000 --- a/pkg/tlsutils/tls_record.go +++ /dev/null @@ -1,211 +0,0 @@ -package tlsutils - -import ( - "bytes" - "crypto/hmac" - "encoding/binary" - "fmt" - yaklog "github.com/yaklang/yaklang/common/log" - "socks2https/context" - "socks2https/pkg/colorutils" - "socks2https/pkg/crypt" - "socks2https/setting" -) - -// TLS 常见消息类型 -const ( - ContentTypeChangeCipherSpec uint8 = 20 // 0x14 用于更改密码规范消息 - ContentTypeAlert uint8 = 21 // 0x15 用于警报消息 - ContentTypeHandshake uint8 = 22 // 0x16 用于握手消息 - ContentTypeApplicationData uint8 = 23 // 0x17 用于应用数据 - ContentTypeHeartbeat uint8 = 24 // 0x18 用于心跳消息(仅适用于某些版本) -) - -// TLS 不常见消息类型 -const ( - ContentTypeTLSPlaintext uint8 = 0 // 明文TLS数据,未加密 (非正式标准) - ContentTypeTLSInnerPlaintext uint8 = 0xFF // 用于 TLS 1.3 的 InnerPlaintext - ContentTypeSSL20ClientHello uint8 = 0x80 // SSL 2.0 ClientHello 消息类型 - ContentTypeCompressed uint8 = 0x19 // 用于压缩的 TLS 数据 - ContentTypeEncryptedExtensions uint8 = 0x08 // TLS 1.3 扩展,安全后协商内容 - ContentTypeSupplementalData uint8 = 0x0C // 补充数据消息 (SSL 3.0/TLS 1.0) - ContentTypeCustomExperimental uint8 = 0xE0 // 实验性自定义消息类型 -) - -var ContentType = map[uint8]string{ - ContentTypeChangeCipherSpec: "Change Cipher Spec", - ContentTypeAlert: "Alert", - ContentTypeHandshake: "Handshake", - ContentTypeApplicationData: "Application Data", - ContentTypeHeartbeat: "Heartbeat", - ContentTypeTLSPlaintext: "TLS Plaintext", - ContentTypeTLSInnerPlaintext: "TLS Inner Plaintext", - ContentTypeSSL20ClientHello: "SSL20 ClientHello", - ContentTypeCompressed: "Compressed", - ContentTypeEncryptedExtensions: "Encrypted Extensions", - ContentTypeSupplementalData: "Supplemental Data", - ContentTypeCustomExperimental: "Custom Experimental", -} - -// Record 记录消息类型 -type Record struct { - ContentType uint8 `json:"contentType"` //1 byte - Version uint16 `json:"version"` //2 byte - Length uint16 `json:"length"` //2 byte - Fragment []byte `json:"fragment,omitempty"` - Handshake *Handshake `json:"handshake,omitempty"` - ChangeCipherSpec byte `json:"changeCipherSpec,omitempty"` - Alert *Alert `json:"alert,omitempty"` - ApplicationData []byte `json:"applicationData,omitempty"` -} - -// ParseBlockRecord 解析分块加密的tls记录 -func ParseBlockRecord(blockRecord []byte, ctx *context.Context) (*Record, error) { - // 获取对称解密的IV,获取需要解密的密文 - iv, cipherFragment := blockRecord[5:5+ctx.TLSContext.BlockLength], blockRecord[5+ctx.TLSContext.BlockLength:] - - // 解密密文 - paddingFragment, err := crypt.AESCBCDecrypt(cipherFragment, ctx.TLSContext.ClientKey, iv) - if err != nil { - return nil, err - } - - // 去除填充长度和填充数据 - plainFragment := paddingFragment[:len(paddingFragment)-int(paddingFragment[len(paddingFragment)-1])-1] - - // 分离Fragment和MAC数据 - fragment, mac := plainFragment[:len(plainFragment)-ctx.TLSContext.MACLength], plainFragment[len(plainFragment)-ctx.TLSContext.MACLength:] - - // 生成明文Record - length := make([]byte, 2) - binary.BigEndian.PutUint16(length, uint16(len(fragment))) - plainRecord := append(blockRecord[:3], append(length, fragment...)...) - - // 校验MAC防篡改 - if setting.Config.TLS.VerifyMAC { - seqNum := make([]byte, 8) - binary.BigEndian.PutUint64(seqNum, ctx.TLSContext.ClientSeqNum) - tamplate := fmt.Sprintf("%s [%s]", ctx.Client2MitmLog, colorutils.SetColor(colorutils.YELLOW_COLOR_TYPE, ContentType[plainRecord[0]])) - if plainRecord[0] == ContentTypeHandshake { - tamplate = fmt.Sprintf("%s [%s]", tamplate, colorutils.SetColor(colorutils.RED_COLOR_TYPE, HandshakeType[plainRecord[5]])) - } - - // 服务端生成MAC - verifyMAC := crypt.HmacHash(ctx.TLSContext.ClientMACKey, append(seqNum, plainRecord...), ctx.TLSContext.HashFunc) - - // 校验MAC - if !hmac.Equal(mac, verifyMAC) { - return nil, fmt.Errorf("%s Verify MAC Failed", tamplate) - } - yaklog.Debugf("%s Verify MAC Successfully", tamplate) - } - - ctx.TLSContext.ClientSeqNum++ - record, err := ParseRecord(plainRecord, ctx) - if err != nil { - return nil, err - } - - return record, nil -} - -// ParseRecord 解析明文tls记录 -func ParseRecord(data []byte, ctx *context.Context) (*Record, error) { - if len(data) < 5 { - return nil, fmt.Errorf("TLS Record is invaild") - } - record := &Record{ - ContentType: data[0], - Version: binary.BigEndian.Uint16(data[1:3]), - Length: binary.BigEndian.Uint16(data[3:5]), - } - - if len(data) < 5+int(record.Length) { - return nil, fmt.Errorf("TLS Record Fragment is incomplete") - } - record.Fragment = data[5:] - switch record.ContentType { - case ContentTypeHandshake: - handshake, err := ParseHandshake(record.Fragment, ctx) - if err != nil { - return nil, err - } - record.Handshake = handshake - case ContentTypeChangeCipherSpec: - if len(record.Fragment) != 1 { - return nil, fmt.Errorf("Change Cipher Spec is invaild") - } - record.ChangeCipherSpec = record.Fragment[0] - case ContentTypeAlert: - alert, err := ParseAlert(record.Fragment) - if err != nil { - return nil, err - } - record.Alert = alert - case ContentTypeApplicationData: - record.ApplicationData = record.Fragment - default: - yaklog.Warnf(colorutils.SetColor(colorutils.MAGENTA_COLOR_TYPE, fmt.Sprintf("not support Content Type : %v", record.ContentType))) - } - return record, nil -} - -// NewBlockRecord 创建一个分块加密的tls记录 -func NewBlockRecord(record *Record, ctx *context.Context) ([]byte, error) { - seqNum := make([]byte, 8) - binary.BigEndian.PutUint64(seqNum, ctx.TLSContext.ServerSeqNum) - - // 生成MAC - seqFragment := append(seqNum, record.GetRaw()...) - mac := crypt.HmacHash(ctx.TLSContext.ServerMACKey, seqFragment, ctx.TLSContext.HashFunc) - - // tls record密文序号自增 - ctx.TLSContext.ServerSeqNum++ - - // 拼接Fragment和MAC - plainFragment := append(record.Fragment, mac...) - - // 拼接填充 - paddingLength := ctx.TLSContext.BlockLength - len(plainFragment)%ctx.TLSContext.BlockLength - 1 - padding := bytes.Repeat([]byte{byte(paddingLength)}, paddingLength) - paddingFragment := append(plainFragment, append(padding, byte(paddingLength))...) - - cipherFragment, err := crypt.AESCBCEncrypt(paddingFragment, ctx.TLSContext.ServerKey, ctx.TLSContext.ServerIV) - if err != nil { - return nil, err - } - - fragment := append(ctx.TLSContext.ServerIV, cipherFragment...) - - blockRecord := &Record{ - ContentType: record.ContentType, - Version: record.Version, - Length: uint16(len(fragment)), - Fragment: fragment, - } - return blockRecord.GetRaw(), nil -} - -func (r *Record) GetRaw() []byte { - version := make([]byte, 2) - binary.BigEndian.PutUint16(version, r.Version) - record := append([]byte{r.ContentType}, version...) - length := make([]byte, 2) - binary.BigEndian.PutUint16(length, r.Length) - record = append(record, length...) - if r.Fragment == nil { - switch r.ContentType { - case ContentTypeHandshake: - return append(record, r.Handshake.GetRaw()...) - case ContentTypeChangeCipherSpec: - return append(record, r.ChangeCipherSpec) - case ContentTypeAlert: - return append(record, r.Alert.GetRaw()...) - case ContentTypeApplicationData: - return append(record, r.ApplicationData...) - default: - yaklog.Warnf(colorutils.SetColor(colorutils.MAGENTA_COLOR_TYPE, fmt.Sprintf("not support Content Type : %v", r.ContentType))) - } - } - return append(record, r.Fragment...) -} diff --git a/pkg/tlsutils/tlsutils.go b/pkg/tlsutils/tlsutils.go deleted file mode 100644 index db4be61..0000000 --- a/pkg/tlsutils/tlsutils.go +++ /dev/null @@ -1,50 +0,0 @@ -package tlsutils - -import ( - "bufio" - "encoding/binary" - "fmt" - "io" - "socks2https/pkg/ioutils" -) - -const ( - TLS_FRAGMENT_MAX_SIZE = 16384 - TLS_RECORD_MAX_SIZE = 65535 -) - -// ReadTLSRecord 解决TLS记录分片问题 -func ReadTLSRecord(reader *bufio.Reader) ([]byte, error) { - for offset, fragments := 0, make([]byte, 0); ; { - // 读取TLS记录头部信息 - header, err := ioutils.ReadBytes(reader, 5) - if err != nil { - return nil, fmt.Errorf("read TLS Record Header failed : %v", err) - } - - // 读取TLS有效载荷长度 - length := binary.BigEndian.Uint16(header[3:5]) - - offset = offset + 5 + int(length) - - fragment, err := ioutils.ReadBytes(reader, int(length)) - if err != nil && err != io.EOF { - return nil, fmt.Errorf("read TLS Record Fragment failed : %v", err) - } - - // 拼接有效载荷 - fragments = append(fragments, fragment...) - - if length < TLS_FRAGMENT_MAX_SIZE { - if offset < TLS_FRAGMENT_MAX_SIZE { - return append(header, fragment...), nil - } else if offset >= TLS_FRAGMENT_MAX_SIZE && offset < TLS_RECORD_MAX_SIZE { - fragmentsLength := make([]byte, 2) - binary.BigEndian.PutUint16(fragmentsLength, uint16(offset)) - return append(header[:3], append(fragmentsLength, fragments...)...), nil - } else { - return append(header[:3], append([]byte{0xff, 0xff}, fragments...)...), nil - } - } - } -} diff --git a/pkg/zip/gzip.go b/pkg/zip/gzip.go deleted file mode 100644 index 0335802..0000000 --- a/pkg/zip/gzip.go +++ /dev/null @@ -1,33 +0,0 @@ -package zip - -import ( - "bytes" - "compress/gzip" - "fmt" - "io" -) - -func GzipDecompress(data []byte) ([]byte, error) { - reader, err := gzip.NewReader(bytes.NewBuffer(data)) - if err != nil { - return nil, fmt.Errorf("read compress data failed : %v", err) - } - defer reader.Close() - decompressed, err := io.ReadAll(reader) - if err != nil { - return nil, fmt.Errorf("gzip decompress data failed : %v", err) - } - return decompressed, nil -} - -func GzipCompress(data []byte) ([]byte, error) { - var compressed bytes.Buffer - writer := gzip.NewWriter(&compressed) - if _, err := writer.Write(data); err != nil { - return nil, fmt.Errorf("gzip compress data failed : %v", err) - } - if err := writer.Close(); err != nil { - return nil, fmt.Errorf("gzip compress close failed : %v", err) - } - return compressed.Bytes(), nil -} diff --git a/porxy/handler.go b/porxy/handler.go deleted file mode 100644 index 443df96..0000000 --- a/porxy/handler.go +++ /dev/null @@ -1,94 +0,0 @@ -package porxy - -import ( - "bufio" - "fmt" - yaklog "github.com/yaklang/yaklang/common/log" - "net" - "net/http" - "net/url" - "socks2https/connect" - "socks2https/context" - "socks2https/pkg/colorutils" - "socks2https/pkg/finger" - "socks2https/porxy/https" - "socks2https/porxy/socks" - "socks2https/setting" -) - -func Handler(reader *bufio.Reader, conn net.Conn, ctx *context.Context) { - peek, err := reader.Peek(3) - if err != nil { - yaklog.Errorf("%s Failed to Pre Read Protocol Header : %v", ctx.LogTamplate, err) - return - } - if peek[0] == socks.SOCKS5_VERSION { - yaklog.Infof("%s Connection is SOCKS5 Tunnel.", ctx.LogTamplate) - if err = socks.Handshake(reader, conn, ctx); err != nil { - yaklog.Errorf("%s %v", ctx.LogTamplate, err) - return - } - yaklog.Debugf("%s Finish SOCKS Handshake.", ctx.LogTamplate) - if err = socks.Runcmd(reader, conn, ctx); err != nil { - yaklog.Errorf("%s %v", ctx.LogTamplate, err) - return - } - yaklog.Debugf("%s Finish SOCKS Command.", ctx.LogTamplate) - if ctx.Cmd != socks.CONNECT_CMD { - yaklog.Warnf("%s Not Support Command : %d", ctx.LogTamplate, ctx.Cmd) - return - } - } else if string(peek) == http.MethodConnect[:3] { - yaklog.Infof("%s Connection is HTTP Tunnel.", ctx.LogTamplate) - if err = https.Handshake(reader, conn, ctx); err != nil { - yaklog.Errorf("%s %v", ctx.LogTamplate, err) - return - } - } - - if setting.Config.MITM.Switch { - switch finger.Inspect(reader) { - case finger.TLS: - ctx.Protocol = finger.TLS - if setting.Config.TLS.MITMSwitch { - ctx.Client2MitmLog = fmt.Sprintf("%s [%s]", ctx.Client2MitmLog, colorutils.SetColor(colorutils.YELLOW_COLOR_TYPE, "TLS")) - ctx.Mitm2ClientLog = fmt.Sprintf("%s [%s]", ctx.Mitm2ClientLog, colorutils.SetColor(colorutils.YELLOW_COLOR_TYPE, "TLS")) - yaklog.Infof("%s Connection Protocol is TLS", ctx.LogTamplate) - - // 创建一个默认的 tls context 并加载配置文件配置 - ctx.TLSContext = context.NewTLSContext() - if setting.Config.TLS.DefaultSNI != "" { - ctx.TLSContext.SNI = setting.Config.TLS.DefaultSNI - } - - connect.HandleTLSConnection(reader, conn, ctx) - return - } - case finger.HTTP: - ctx.Protocol = finger.HTTP - if setting.Config.HTTP.MITMSwitch { - ctx.Client2MitmLog = fmt.Sprintf("%s [%s]", ctx.Client2MitmLog, colorutils.SetColor(colorutils.YELLOW_COLOR_TYPE, "HTTP")) - ctx.Mitm2ClientLog = fmt.Sprintf("%s [%s]", ctx.Mitm2ClientLog, colorutils.SetColor(colorutils.YELLOW_COLOR_TYPE, "HTTP")) - yaklog.Infof("%s Connection Protocol is HTTP", ctx.LogTamplate) - - // 创建一个默认的 http context 并加载配置文件配置 - ctx.HTTPContext = context.NewHTTPContext() - if setting.Config.HTTP.Proxy != "" { - proxyURL, err := url.Parse(setting.Config.HTTP.Proxy) - if err != nil { - yaklog.Fatalf("Proxy URL is Invalid : %v", err) - } - ctx.HTTPContext.HttpClient.Transport.(*http.Transport).Proxy = http.ProxyURL(proxyURL) - } - - connect.HandleHTTPConnection(reader, conn, ctx) - return - } - } - } - ctx.Protocol = finger.TCP - ctx.Client2MitmLog = fmt.Sprintf("%s [%s]", ctx.Client2MitmLog, colorutils.SetColor(colorutils.YELLOW_COLOR_TYPE, "TCP")) - ctx.Mitm2ClientLog = fmt.Sprintf("%s [%s]", ctx.Mitm2ClientLog, colorutils.SetColor(colorutils.YELLOW_COLOR_TYPE, "TCP")) - yaklog.Infof("%s Connection Protocol is TCP", ctx.LogTamplate) - connect.Direct(reader, conn, ctx) -} diff --git a/porxy/https/handshake.go b/porxy/https/handshake.go deleted file mode 100644 index 5c0048e..0000000 --- a/porxy/https/handshake.go +++ /dev/null @@ -1,27 +0,0 @@ -package https - -import ( - "bufio" - "fmt" - "net" - "socks2https/context" - "socks2https/pkg/httptools" -) - -func Handshake(reader *bufio.Reader, conn net.Conn, ctx *context.Context) error { - connectReq, err := httptools.ReadRequest(reader, "http") - if err != nil { - return fmt.Errorf("Failed to Read HTTP CONNECT Request : %v", err) - } - - ctx.Host, ctx.Port, err = httptools.ParseHostAndPort(connectReq.Host) - if err != nil { - return err - } - - if err = httptools.NewConnectResponse().Write(conn); err != nil { - return fmt.Errorf("Failed to Write HTTP CONNECT Response : %v", err) - } - - return nil -} diff --git a/porxy/proxy.go b/porxy/proxy.go deleted file mode 100644 index ddbbfca..0000000 --- a/porxy/proxy.go +++ /dev/null @@ -1,82 +0,0 @@ -package porxy - -import ( - "bufio" - "fmt" - yaklog "github.com/yaklang/yaklang/common/log" - "net" - "regexp" - "socks2https/context" - "socks2https/pkg/colorutils" - "socks2https/setting" - "time" -) - -const ( - PROTOCOL_TCP = "tcp" - PROTOCOL_HTTP = "http" -) - -type MITMServer struct { - Host string - Threads int - ClientTimeout time.Duration - TargetTimeout time.Duration -} - -func NewMITMServer() *MITMServer { - return &MITMServer{ - Host: "0.0.0.0:1080", - Threads: 0, - ClientTimeout: time.Second * 30, - TargetTimeout: time.Second * 30, - } -} - -func (m *MITMServer) Run() { - server, err := net.Listen(PROTOCOL_TCP, m.Host) - if err != nil { - yaklog.Fatalf("Start SOCKS Server Failed : %v", err) - } - yaklog.Infof("Start SOCKS Server On [%s]", m.Host) - - var threads chan struct{} - if m.Threads > 0 { - threads = make(chan struct{}, m.Threads) - } - - for { - ctx := context.NewContext() - ctx.LogTamplate = fmt.Sprintf("[contextId:%s]", ctx.ContextId) - - client, err := server.Accept() - if err != nil { - yaklog.Errorf("%s Accept Client Connection Failed : %v", ctx.LogTamplate, err) - continue - } - - ctx.LogTamplate = fmt.Sprintf("%s [clientIp:%s] [%s]", ctx.LogTamplate, client.RemoteAddr().String(), colorutils.SetColor(colorutils.YELLOW_COLOR_TYPE, "TCP")) - reg := regexp.MustCompile(`:\d+$`) - ctx.Client2MitmLog = fmt.Sprintf("[contextId:%s] [%s => %s]", ctx.ContextId, client.RemoteAddr().String(), reg.FindString(client.LocalAddr().String())) - ctx.Mitm2ClientLog = fmt.Sprintf("[contextId:%s] [%s => %s]", ctx.ContextId, reg.FindString(client.LocalAddr().String()), client.RemoteAddr().String()) - - yaklog.Infof("%s New Client Connection Successfully Established", ctx.LogTamplate) - - if setting.Config.MITM.Timeout.Switch { - if err = client.SetDeadline(time.Now().Add(m.ClientTimeout)); err != nil { - yaklog.Warnf("%s Set Client Deadline Failed : %v", ctx.LogTamplate, err) - } - } - - reader := bufio.NewReader(client) - if m.Threads > 0 { - threads <- struct{}{} - go func(client net.Conn, ctx *context.Context) { - defer func() { <-threads }() - Handler(reader, client, ctx) - }(client, ctx) - } else { - go Handler(reader, client, ctx) - } - } -} diff --git a/porxy/socks/handshake.go b/porxy/socks/handshake.go deleted file mode 100644 index 6dac5b4..0000000 --- a/porxy/socks/handshake.go +++ /dev/null @@ -1,132 +0,0 @@ -package socks - -import ( - "bufio" - "fmt" - yaklog "github.com/yaklang/yaklang/common/log" - "net" - "socks2https/context" - "socks2https/pkg/colorutils" -) - -const ( - SOCKS5_VERSION byte = 0x05 - - // method数据包状态码 - NO_AUTHENTICATION_REQUIRED_METHOD byte = 0x00 - GSSAPI_METHOD byte = 0x01 - USERNAME_PASSWORD_METHOD byte = 0x02 - NO_ACCEPTABLE_METHOD byte = 0xff - - // username和password认证数据包状态码 - AUTHENTICATION_VERSION byte = 0x01 - SUCCESS_AUTHENTICATION byte = 0x00 - FAIL_AUTHENTICATION byte = 0xff - - AUTHENTICATION_SWITCH bool = false -) - -// socks握手处理函数 -// 暂时只支持 未授权访问 方法 -func Handshake(reader *bufio.Reader, conn net.Conn, ctx *context.Context) error { - // 客户端请求包 - // +----+----------+----------+ - // |VER | NMETHODS | METHODS | - // +----+----------+----------+ - // | 1 | 1 | 1 to 255 | - // +----+----------+----------+ - buf := make([]byte, 2) - if _, err := reader.Read(buf); err != nil { - return fmt.Errorf("read VER and NMETHODS failed : %v", err) - } - ver, nMethods := buf[0], buf[1] - yaklog.Debugf("%s VER : %v , NMETHODS : %v", ctx.LogTamplate, ver, nMethods) - if ver != SOCKS5_VERSION { - return fmt.Errorf("unsupport SOCKS version : %d", ver) - } - methods := make([]byte, nMethods) - if _, err := reader.Read(methods); err != nil { - return fmt.Errorf("read METHODS failed : %v", err) - } - yaklog.Debugf("%s METHODS : %v", ctx.LogTamplate, methods) - var method byte - for _, method = range methods { - switch method { - case NO_AUTHENTICATION_REQUIRED_METHOD: - break - case USERNAME_PASSWORD_METHOD: - if AUTHENTICATION_SWITCH { - break - } - fallthrough - default: - method = NO_ACCEPTABLE_METHOD - } - } - yaklog.Debugf("%s Receive Client SOCKS Handshake : %s", ctx.LogTamplate, colorutils.SetColor(colorutils.GREEN_COLOR_TYPE, fmt.Sprintf("%v", append(buf, methods...)))) - // 服务端响应包 - // +----+--------+ - // |VER | METHOD | - // +----+--------+ - // | 1 | 1 | - // +----+--------+ - if _, err := conn.Write([]byte{SOCKS5_VERSION, method}); err != nil { - return fmt.Errorf("send handshake data to Client failed : %v", err) - } else if method == NO_ACCEPTABLE_METHOD { - return fmt.Errorf("not supported handshake methods") - } else if AUTHENTICATION_SWITCH { - //todo - } - return nil -} - -// 客户端请求包 -// +----+------+----------+------+----------+ -// |VER | ULEN | UNAME | PLEN | PASSWD | -// +----+------+----------+------+----------+ -// | 1 | 1 | 1 to 255 | 1 | 1 to 255 | -// +----+------+----------+------+----------+ - -func parseUnamePasswd(reader *bufio.Reader, ctx *context.Context) (byte, error) { - buf := make([]byte, 2) - if _, err := reader.Read(buf); err != nil { - return FAIL_AUTHENTICATION, fmt.Errorf("%s read VER and ULEN failed : %v", ctx.LogTamplate, err) - } - ver, uLen := buf[0], buf[1] - yaklog.Debugf("%s VER : %v , ULEN : %v", ctx.LogTamplate, ver, uLen) - if ver != AUTHENTICATION_VERSION { - return FAIL_AUTHENTICATION, fmt.Errorf("%s not support auth version", ctx.LogTamplate) - } - uname := make([]byte, uLen) - if _, err := reader.Read(uname); err != nil { - return FAIL_AUTHENTICATION, fmt.Errorf("%s read UNAME failed : %v", ctx.LogTamplate, err) - } - pLen, err := reader.ReadByte() - if err != nil { - return FAIL_AUTHENTICATION, fmt.Errorf("%s read PLEN failed : %v", ctx.LogTamplate, err) - } - passwd := make([]byte, pLen) - if _, err = reader.Read(passwd); err != nil { - return FAIL_AUTHENTICATION, fmt.Errorf("%s read PASSWD failed : %v", ctx.LogTamplate, err) - } - if string(passwd) == "admin" && string(uname) == "admin" { - return SUCCESS_AUTHENTICATION, nil - } - return FAIL_AUTHENTICATION, nil -} - -// 服务端响应包 -// +----+--------+ -// |VER | STATUS | -// +----+--------+ -// | 1 | 1 | -// +----+--------+ - -func replyUnamePass(status byte, conn net.Conn, ctx *context.Context) error { - buf := []byte{AUTHENTICATION_VERSION, status} - yaklog.Debugf("%s send auth response : %v", ctx.LogTamplate, buf) - if _, err := conn.Write(buf); err != nil { - return fmt.Errorf("%s send auth response to Client failed : %v", ctx.LogTamplate, err) - } - return nil -} diff --git a/porxy/socks/runcmd.go b/porxy/socks/runcmd.go deleted file mode 100644 index ceffa14..0000000 --- a/porxy/socks/runcmd.go +++ /dev/null @@ -1,145 +0,0 @@ -package socks - -import ( - "bufio" - "fmt" - yaklog "github.com/yaklang/yaklang/common/log" - "net" - "regexp" - "socks2https/context" - "socks2https/pkg/colorutils" - "socks2https/setting" -) - -const ( - HTTP_PROTOCOL int = 0 - HTTPS_PROTOCOL int = 1 - TCP_PROTOCOL int = 2 - - CONNECT_CMD byte = 0x01 - BIND_CMD byte = 0x02 - UDP_ASSOCIATE_CMD byte = 0x03 - - RESERVED byte = 0x00 - - IPV4_ATYPE byte = 0x01 - FQDN_ATYPE byte = 0x03 - IPV6_ATYPE byte = 0x04 - - SUCCEEDED_REP byte = 0x00 - GENERAL_SOCKS_SERVER_FAILURE_REP byte = 0x01 - CONNECTION_NOT_ALLOWED_REP byte = 0x02 - NETWORK_UNREACHABLE_REP byte = 0x03 - HOST_UNREACHABLE_REP byte = 0x04 - CONNECTION_REFUSED_REP byte = 0x05 - TTL_EXPIRED_REP byte = 0x06 - COMMAND_NOT_SUPPORTED_REP byte = 0x07 - ADDRESS_TYPE_NOT_SUPPORTED_REP byte = 0x08 -) - -func Runcmd(reader *bufio.Reader, conn net.Conn, ctx *context.Context) error { - // 客户端请求包 - // +-----+-----+-------+------+----------+----------+ - // | VER | CMD | RSV | ATYP | DST.ADDR | DST.PORT | - // +-----+-----+-------+------+----------+----------+ - // | 1 | 1 | X'00' | 1 | Variable | 2 | - // +-----+-----+-------+------+----------+----------+ - buf := make([]byte, 4) - if _, err := reader.Read(buf); err != nil { - return fmt.Errorf("read VER CMD RSV ATYP failed : %v", err) - } - ver, cmd, rsv, aTyp := buf[0], buf[1], buf[2], buf[3] - yaklog.Debugf("%s VER : %v , CMD : %v , RSA : %v , ATYP : %v", ctx.LogTamplate, ver, cmd, rsv, aTyp) - if ver != SOCKS5_VERSION { - if _, err := conn.Write([]byte{SOCKS5_VERSION, GENERAL_SOCKS_SERVER_FAILURE_REP, RESERVED, IPV4_ATYPE, 0, 0, 0, 0, 0, 0}); err != nil { - return fmt.Errorf("write cmd to Client failed : %v", err) - } - return fmt.Errorf("not support socks version : %v", ver) - } else if cmd != CONNECT_CMD { - if _, err := conn.Write([]byte{SOCKS5_VERSION, COMMAND_NOT_SUPPORTED_REP, RESERVED, IPV4_ATYPE, 0, 0, 0, 0, 0, 0}); err != nil { - return fmt.Errorf("write cmd to Client failed : %v", err) - } - return fmt.Errorf("not support command : %v", cmd) - } else if rsv != RESERVED { - if _, err := conn.Write([]byte{SOCKS5_VERSION, CONNECTION_NOT_ALLOWED_REP, RESERVED, IPV4_ATYPE, 0, 0, 0, 0, 0, 0}); err != nil { - return fmt.Errorf("write cmd to Client failed : %v", err) - } - return fmt.Errorf("invail reserved : %v", rsv) - } - ctx.Cmd = cmd - var host string - var aLen byte = 0x00 - switch aTyp { - case IPV6_ATYPE: - buf = make([]byte, net.IPv6len) - fallthrough - case IPV4_ATYPE: - if _, err := reader.Read(buf); err != nil { - if _, err = conn.Write([]byte{SOCKS5_VERSION, GENERAL_SOCKS_SERVER_FAILURE_REP, RESERVED, IPV4_ATYPE, 0, 0, 0, 0, 0, 0}); err != nil { - return fmt.Errorf("write cmd to Client failed : %v", err) - } - return fmt.Errorf("read Target IP failed : %v", err) - } - host = net.IP(buf).String() - case FQDN_ATYPE: - if _, err := reader.Read(buf[:1]); err != nil { - if _, err = conn.Write([]byte{SOCKS5_VERSION, GENERAL_SOCKS_SERVER_FAILURE_REP, RESERVED, IPV4_ATYPE, 0, 0, 0, 0, 0, 0}); err != nil { - return fmt.Errorf("write cmd to Client failed : %v", err) - } - return fmt.Errorf("read ALEN failed : %v", err) - } - aLen = buf[0] - yaklog.Debugf("%s ALEN : %v", ctx.LogTamplate, aLen) - if aLen > net.IPv4len { - buf = make([]byte, aLen) - } - if _, err := reader.Read(buf[:aLen]); err != nil { - if _, err = conn.Write([]byte{SOCKS5_VERSION, GENERAL_SOCKS_SERVER_FAILURE_REP, RESERVED, IPV4_ATYPE, 0, 0, 0, 0, 0, 0}); err != nil { - return fmt.Errorf("write cmd to Client failed : %v", err) - } - return fmt.Errorf("read Target FQDN failed : %v", err) - } - host = string(buf[:aLen]) - default: - if _, err := conn.Write([]byte{SOCKS5_VERSION, ADDRESS_TYPE_NOT_SUPPORTED_REP, RESERVED, IPV4_ATYPE, 0, 0, 0, 0, 0, 0}); err != nil { - return fmt.Errorf("write cmd to Client failed : %v", err) - } - return fmt.Errorf("not support address type : %v", aTyp) - } - ctx.Host = host - if _, err := reader.Read(buf[:2]); err != nil { - if _, err = conn.Write([]byte{SOCKS5_VERSION, ADDRESS_TYPE_NOT_SUPPORTED_REP, RESERVED, IPV4_ATYPE, 0, 0, 0, 0, 0, 0}); err != nil { - return fmt.Errorf("write cmd to Client failed : %v", err) - } - return fmt.Errorf("read Target Port failed : %v", err) - } - port := (uint16(buf[0]) << 8) + uint16(buf[1]) - ctx.Port = port - addr := fmt.Sprintf("%s:%d", host, port) - yaklog.Infof("%s Get Target Address : %s", ctx.LogTamplate, addr) - - reg := regexp.MustCompile(`:\d+$`) - ctx.Mitm2TargetLog = fmt.Sprintf("[clientId:%s] [%s => %s] [%s]", ctx.ContextId, reg.FindString(conn.LocalAddr().String()), addr, colorutils.SetColor(colorutils.YELLOW_COLOR_TYPE, "TCP")) - ctx.Target2MitmLog = fmt.Sprintf("[clientId:%s] [%s => %s] [%s]", ctx.ContextId, addr, reg.FindString(conn.LocalAddr().String()), colorutils.SetColor(colorutils.YELLOW_COLOR_TYPE, "TCP")) - // 服务端响应包 - // +-----+-----+-------+------+----------+----------+ - // | VER | REP | RSV | ATYP | BND.ADDR | BND.PORT | - // +-----+-----+-------+------+----------+----------+ - // | 1 | 1 | 1 | 1 | Variable | 2 | - // +-----+-----+-------+------+----------+----------+ - resp := []byte{SOCKS5_VERSION, SUCCEEDED_REP, RESERVED} - if setting.Config.MITM.Bound { - resp = append(resp, aTyp) - if aLen != 0x00 { - resp = append(resp, aLen) - } - if _, err := conn.Write(append(append(resp, host...), buf[:2]...)); err != nil { - return fmt.Errorf("write cmd to Client failed : %v", err) - } - return nil - } - if _, err := conn.Write(append(resp, IPV4_ATYPE, 0, 0, 0, 0, 0, 0)); err != nil { - return fmt.Errorf("write cmd to Client failed : %v", err) - } - return nil -} diff --git a/proxy.go b/proxy.go new file mode 100644 index 0000000..8c7ab7b --- /dev/null +++ b/proxy.go @@ -0,0 +1,118 @@ +package proxy + +import ( + "crypto/rsa" + "crypto/tls" + "crypto/x509" + "github.com/gobwas/ws" + yaklog "github.com/yaklang/yaklang/common/log" + "golang.org/x/net/proxy" + "net" + "net/http" + "time" +) + +type HandleReq func(req *http.Request, ctx *Context) (*http.Request, *http.Response) + +type HandleResp func(resp *http.Response, ctx *Context) *http.Response + +type HandleWebSocket func(frame ws.Frame, reverse bool, ctx *Context) ws.Frame + +type HandleRaw func(raw []byte, reverse bool, ctx *Context) []byte + +type HttpProxy struct { + Host string + Port string + Threads int + Cert *x509.Certificate + Key *rsa.PrivateKey + DefaultSNI string + HTTPClient *http.Client + Dialer proxy.Dialer + reqHandlers []HandleReq + respHandlers []HandleResp + webSocketHandlers []HandleWebSocket + rawHandlers []HandleRaw +} + +func NewHttpProxy() *HttpProxy { + return &HttpProxy{ + Host: "0.0.0.0", + Port: "1080", + Threads: 100, + HTTPClient: &http.Client{ + Transport: &http.Transport{ + DialContext: (&net.Dialer{ + Timeout: 15 * time.Second, + KeepAlive: 15 * time.Second, + }).DialContext, + TLSClientConfig: &tls.Config{ + InsecureSkipVerify: true, + }, + ForceAttemptHTTP2: false, + //DisableCompression: false, + }, + }, + } +} + +const ( + MODE_ALL = iota + MODE_WITHOUT_HANDLER +) + +func (h *HttpProxy) Copy(mode int) *HttpProxy { + httpProxy := &HttpProxy{ + Host: h.Host, + Port: h.Port, + Threads: h.Threads, + Cert: h.Cert, + Key: h.Key, + DefaultSNI: h.DefaultSNI, + HTTPClient: h.HTTPClient, + Dialer: h.Dialer, + } + switch mode { + case MODE_ALL: + httpProxy.reqHandlers = h.reqHandlers + httpProxy.respHandlers = h.respHandlers + httpProxy.webSocketHandlers = h.webSocketHandlers + httpProxy.rawHandlers = h.rawHandlers + case MODE_WITHOUT_HANDLER: + } + return httpProxy +} + +func (h *HttpProxy) Serve(mode Mode) { + httpProxy, err := net.Listen("tcp", h.Host+":"+h.Port) + if err != nil { + yaklog.Fatalf("listen %s failed", h.Host+":"+h.Port) + } + yaklog.Infof("listen %s success", h.Host+":"+h.Port) + + threads := make(chan struct{}, h.Threads) + + for { + ctx := NewContext() + + client, err := httpProxy.Accept() + if err != nil { + yaklog.Errorf("%s accept client connection failed - %v", ctx.Preffix(), err) + continue + } + + ctx.ClientAddr = client.RemoteAddr().String() + + yaklog.Infof("%s accept %s connection success", ctx.Preffix(), ctx.ClientAddr) + + threads <- struct{}{} + go func(client net.Conn) { + defer func() { + _ = client.Close() + <-threads + }() + + _ = mode.HandleConnect(client, h, ctx) + }(client) + } +} diff --git a/services/cert_service.go b/services/cert_service.go deleted file mode 100644 index b835a43..0000000 --- a/services/cert_service.go +++ /dev/null @@ -1,75 +0,0 @@ -package services - -import ( - "crypto/rsa" - "crypto/x509" - "errors" - "fmt" - "gorm.io/gorm" - "socks2https/database" - "socks2https/models" -) - -// getCertAndKey 获取指定通配符域名的证书和私钥 -func getCertAndKey(db *gorm.DB, wildcardDomain string) ([]byte, []byte, error) { - var certMapping models.CertMapping - result := db.Where("wildcard_domain = ?", wildcardDomain).First(&certMapping) - - if result.Error != nil { - return nil, nil, result.Error - } - - return certMapping.Certificate, certMapping.PrivateKey, nil -} - -func GetCertAndKey(wildcardDomain string) (*x509.Certificate, *rsa.PrivateKey, error) { - certRAW, keyRAW, err := getCertAndKey(database.Cache, wildcardDomain) - if errors.Is(err, gorm.ErrRecordNotFound) { - certRAW, keyRAW, err = getCertAndKey(database.Cache, wildcardDomain) - if err != nil { - return nil, nil, err - } - if err = addCertMapping(database.Cache, wildcardDomain, certRAW, keyRAW); err != nil { - return nil, nil, err - } - } else if err != nil { - return nil, nil, err - } - certDER, err := x509.ParseCertificate(certRAW) - if err != nil { - return nil, nil, fmt.Errorf("Parsing Certificate Failed : %v", err) - } - keyDER, err := x509.ParsePKCS1PrivateKey(keyRAW) - if err != nil { - return nil, nil, fmt.Errorf("Parsing Private Key Failed : %v", err) - } - return certDER, keyDER, nil -} - -// addCertMapping 添加通配符域名到证书和私钥的映射关系 -func addCertMapping(db *gorm.DB, wildcardDomain string, cert, key []byte) error { - certMapping := models.CertMapping{ - WildcardDomain: wildcardDomain, - Certificate: cert, - PrivateKey: key, - } - - result := db.Create(&certMapping) - if result.Error != nil { - return result.Error - } - - return nil -} - -func AddCertMapping(wildcardDomain string, cert *x509.Certificate, key *rsa.PrivateKey) error { - certRAW := cert.Raw - keyRAW := x509.MarshalPKCS1PrivateKey(key) - if err := addCertMapping(database.Cache, wildcardDomain, certRAW, keyRAW); err != nil { - return err - } - if err := addCertMapping(database.DB, wildcardDomain, certRAW, keyRAW); err != nil { - return err - } - return nil -} diff --git a/services/domain_service.go b/services/domain_service.go deleted file mode 100644 index afc7b60..0000000 --- a/services/domain_service.go +++ /dev/null @@ -1,61 +0,0 @@ -package services - -import ( - "errors" - "gorm.io/gorm" - "socks2https/database" - "socks2https/models" -) - -// getWildcardDomain 获取指定域名的通配符域名 -func getWildcardDomain(db *gorm.DB, domain string) (string, error) { - var mapping models.DomainMapping - result := db.Where("domain = ?", domain).First(&mapping) - - if result.Error != nil { - return "", result.Error - } - - return mapping.WildcardDomain, nil -} - -func GetWildcardDomain(domain string) (string, error) { - wildcardDomain, err := getWildcardDomain(database.Cache, domain) - if errors.Is(err, gorm.ErrRecordNotFound) { - wildcardDomain, err = getWildcardDomain(database.DB, domain) - if err != nil { - return "", err - } - if err = addDomainMapping(database.Cache, domain, wildcardDomain); err != nil { - return "", err - } - } else if err != nil { - return "", err - } - return wildcardDomain, nil -} - -// addDomainMapping 添加域名到通配符域名的映射关系 -func addDomainMapping(db *gorm.DB, domain, wildcardDomain string) error { - mapping := models.DomainMapping{ - Domain: domain, - WildcardDomain: wildcardDomain, - } - - result := db.Create(&mapping) - if result.Error != nil { - return result.Error - } - - return nil -} - -func AddDomainMapping(domain, wildcardDomain string) error { - if err := addDomainMapping(database.Cache, domain, wildcardDomain); err != nil { - return err - } - if err := addDomainMapping(database.DB, domain, wildcardDomain); err != nil { - return err - } - return nil -} diff --git a/services/ip_service.go b/services/ip_service.go deleted file mode 100644 index 0227a6a..0000000 --- a/services/ip_service.go +++ /dev/null @@ -1,45 +0,0 @@ -package services - -import ( - "gorm.io/gorm" - "socks2https/models" -) - -// GetDomainByIP 获取指定 IP 对应的域名 -func GetDomainByIP(db *gorm.DB, ip string) (string, error) { - var ipMapping models.IPMapping - result := db.Where("ip = ?", ip).First(&ipMapping) - - if result.Error != nil { - return "", result.Error - } - - return ipMapping.Domain, nil -} - -// GetIPByDomain 获取指定 IP 对应的域名 -func GetIPByDomain(db *gorm.DB, domain string) (string, error) { - var ipMapping models.IPMapping - result := db.Where("domain = ?", domain).First(&ipMapping) - - if result.Error != nil { - return "", result.Error - } - - return ipMapping.IP, nil -} - -// AddIPMapping 添加 IP 到域名的映射关系 -func AddIPMapping(db *gorm.DB, ip, domain string) error { - ipMapping := models.IPMapping{ - IP: ip, - Domain: domain, - } - - result := db.Create(&ipMapping) - if result.Error != nil { - return result.Error - } - - return nil -} diff --git a/setting/setting.go b/setting/setting.go deleted file mode 100644 index 6fe7d6a..0000000 --- a/setting/setting.go +++ /dev/null @@ -1,142 +0,0 @@ -package setting - -import ( - "crypto/rand" - "crypto/rsa" - "crypto/x509" - "github.com/kataras/golog" - yaklog "github.com/yaklang/yaklang/common/log" - "gopkg.in/yaml.v3" - "os" - "socks2https/pkg/certutils" - "socks2https/pkg/osutils" - "time" -) - -const ( - ConfigPath = "config/config.yaml" -) - -var ( - Config Configure - CACert *x509.Certificate - CAKey *rsa.PrivateKey -) - -type Configure struct { - Log Log `yaml:"log"` - MITM MITM `yaml:"mitm"` - TLS TLS `yaml:"tls"` - HTTP HTTP `yaml:"http"` - DNS string `yaml:"dns"` - CA CA `yaml:"ca"` - DB DB `yaml:"db"` -} - -type Log struct { - ColorSwitch bool `yaml:"colorSwitch"` - Level golog.Level `yaml:"level"` -} - -type MITM struct { - Host string `yaml:"host"` - Threads int `yaml:"threads"` - Timeout Timeout `yaml:"timeout"` - Bound bool `yaml:"bound"` - Switch bool `yaml:"switch"` - Dump Dump `yaml:"dump"` -} - -type Timeout struct { - Switch bool `yaml:"switch"` - Client time.Duration `yaml:"client"` - Target time.Duration `yaml:"target"` -} - -type Dump struct { - Switch bool `yaml:"switch"` - Port uint16 `yaml:"port"` -} - -type TLS struct { - MITMSwitch bool `yaml:"mitmSwitch"` - VerifyFinished bool `yaml:"verifyFinished"` - VerifyMAC bool `yaml:"verifyMAC"` - DefaultSNI string `yaml:"defaultSNI"` -} - -type HTTP struct { - MITMSwitch bool `yaml:"mitmSwitch"` - Proxy string `yaml:"proxy"` -} - -type CA struct { - Domain string `yaml:"domain"` - Cert string `yaml:"cert"` - Key string `yaml:"key"` -} - -type DB struct { - Cache Cache `yaml:"cache"` - Main Main `yaml:"main"` -} - -type Cache struct { - LogSwitch bool `yaml:"logSwitch"` -} - -type Main struct { - LogSwitch bool `yaml:"logSwitch"` - Path string `yaml:"path"` -} - -func init() { - file, err := os.ReadFile(ConfigPath) - if err != nil { - yaklog.Fatalf("Read Config Failed : %v", err) - } - - if err = yaml.Unmarshal(file, &Config); err != nil { - yaklog.Fatalf("Unmarshal Config Failed : %v", err) - } - - yaklog.Info("Loading Configure Successfully.") - - CAPathErr, DBPathErr := osutils.MkDir(Config.CA.Cert), osutils.MkDir(Config.DB.Main.Path) - if CAPathErr != nil || DBPathErr != nil { - yaklog.Fatalf("Failed to Create Dir") - } - - CACert, CAKey, err = InitCertificateAndPrivateKey() - if err != nil { - yaklog.Fatal(err) - } - - yaklog.Info("Loading Root CA Certificate and PrivateKey Successfully.") -} - -func InitCertificateAndPrivateKey() (*x509.Certificate, *rsa.PrivateKey, error) { - cert, certErr := certutils.LoadCert(Config.CA.Cert) - key, keyErr := certutils.LoadKey(Config.CA.Key) - if certErr != nil || keyErr != nil { - key, keyErr = rsa.GenerateKey(rand.Reader, 2048) - if keyErr != nil { - return nil, nil, keyErr - } - defer certutils.SaveKey(Config.CA.Key, key) - - realCert, err := certutils.GetRealCertificateWithTCP(Config.CA.Domain) - if err != nil { - return nil, nil, err - } - - cert, certErr = certutils.ForgedRootCACertificate(realCert, key) - if certErr != nil { - return nil, nil, certErr - } - defer certutils.SaveCertificate(Config.CA.Cert, cert) - - return cert, key, nil - } - return cert, key, nil -} diff --git a/tcp.go b/tcp.go new file mode 100644 index 0000000..ff5faba --- /dev/null +++ b/tcp.go @@ -0,0 +1,57 @@ +package proxy + +import ( + yaklog "github.com/yaklang/yaklang/common/log" + "io" + "net" +) + +type hook struct { + w io.Writer + h *HttpProxy + reverse bool + ctx *Context +} + +func (h *hook) Write(p []byte) (n int, err error) { + _, err = h.w.Write(h.h.filterRaw(p, h.reverse, h.ctx)) + return len(p), err +} + +func (h *hook) copy() *hook { + return &hook{ + h: h.h, + reverse: h.reverse, + ctx: h.ctx, + } +} + +func (h *HttpProxy) handleTCP(client net.Conn, ctx *Context) error { + remote, err := net.Dial("tcp", net.JoinHostPort(ctx.RemoteHost, ctx.RemotePort)) + if err != nil { + yaklog.Errorf("%s connect to remote failed - %v", ctx.Preffix(), err) + return err + } + defer remote.Close() + + errChan := make(chan error) + cp := func(dst io.Writer, src io.Reader) { + _, err = io.Copy(dst, src) + errChan <- err + } + + ho := &hook{h: h, ctx: ctx} + + remoteHook := ho.copy() + remoteHook.w, remoteHook.reverse = remote, false + + go cp(remoteHook, client) + + clientHook := ho.copy() + clientHook.w, clientHook.reverse = client, true + + go cp(clientHook, remote) + + <-errChan + return nil +} diff --git a/websocket.go b/websocket.go new file mode 100644 index 0000000..078345f --- /dev/null +++ b/websocket.go @@ -0,0 +1,110 @@ +package proxy + +import ( + "bufio" + "crypto/tls" + "errors" + "github.com/gobwas/ws" + yaklog "github.com/yaklang/yaklang/common/log" + "io" + "net" + "net/http" + "net/http/httputil" +) + +func (h *HttpProxy) handleWebSocket(client net.Conn, ctx *Context) (err error) { + ctx.Protocol = "WebSocket" + + requestRaw, err := httputil.DumpRequest(ctx.Request, true) + if err == nil { + yaklog.Infof("%s [Handshake] [Request]\n%s", ctx.Preffix(false), requestRaw) + } + + ctx.Request.Header.Del("Sec-WebSocket-Extensions") + + var remote net.Conn + if h.Dialer != nil { + h.Dialer.(Dialer).SetTLS(ctx.IsTLS) + + proxyConn, err := h.Dialer.Dial("tcp", net.JoinHostPort(ctx.RemoteHost, ctx.RemotePort)) + if err != nil { + yaklog.Errorf("%s connect to proxy failed - %v", ctx.Preffix(), err) + return err + } + remote = proxyConn + } else { + if ctx.IsTLS { + tlsRemote, err := tls.Dial("tcp", net.JoinHostPort(ctx.RemoteHost, ctx.RemotePort), &tls.Config{InsecureSkipVerify: true}) + if err != nil { + yaklog.Errorf("%s tls connect to remote failed - %v", ctx.Preffix(), err) + return err + } + remote = tlsRemote + } else { + netRemote, err := net.Dial("tcp", net.JoinHostPort(ctx.RemoteHost, ctx.RemotePort)) + if err != nil { + yaklog.Errorf("%s connect to remote failed - %v", ctx.Preffix(), err) + } + remote = netRemote + } + } + + defer func() { + _ = remote.Close() + }() + + if err := ctx.Request.Write(remote); err != nil { + yaklog.Errorf("%s send request to remote failed - %v", ctx.Preffix(), err) + return err + } + + response, err := http.ReadResponse(bufio.NewReader(remote), ctx.Request) + if err != nil { + yaklog.Errorf("%s read response from remote failed - %v", ctx.Preffix(), err) + return err + } + + if err = response.Write(client); err != nil { + yaklog.Errorf("%s send response to client failed - %v", ctx.Preffix(), err) + return err + } + + responseRaw, err := httputil.DumpResponse(response, true) + if err == nil { + yaklog.Infof("%s [Handshake] [Response]\n%s", ctx.Preffix(true), responseRaw) + } + + errChan := make(chan error, 2) + cp := func(dst io.Writer, src io.Reader, reverse bool) { + for { + frame, err := ws.ReadFrame(src) + if err != nil { + if !handleEOF(err) { + yaklog.Errorf("%s read frame failed - %v", ctx.Preffix(reverse), err) + } + errChan <- err + break + } + + frame = h.filterWebSocket(frame, reverse, ctx) + + if err = ws.WriteFrame(dst, frame); err != nil { + if !handleEOF(err) { + yaklog.Errorf("%s send frame failed - %v", ctx.Preffix(reverse), err) + } + errChan <- err + break + } + } + } + + go cp(remote, client, false) + go cp(client, remote, true) + <-errChan + + return nil +} + +func handleEOF(err error) (isEOF bool) { + return err == io.EOF || errors.Is(err, net.ErrClosed) +}