Skip to content

Commit

Permalink
加socks上游代理
Browse files Browse the repository at this point in the history
  • Loading branch information
zhaozuodong committed Oct 24, 2023
1 parent 976d44b commit 34dcb04
Show file tree
Hide file tree
Showing 4 changed files with 147 additions and 52 deletions.
70 changes: 70 additions & 0 deletions examples/upstream_proxy/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
package main

import (
"fmt"
"github.com/lqqyt2423/go-mitmproxy/proxy"
log "github.com/sirupsen/logrus"
"github.com/tidwall/gjson"
"strings"
)

var (
urls = []string{
"/api/sns/v6/homefeed",
"/api/sns/v3/user/info",
"/api/sns/v3/user/info",
"/api/sns/v1/user/followers",
"/api/sns/v1/user/followings",
"/api/sns/v1/note/faved",
"/api/sns/v4/note/user/posted",
"/api/sns/v4/note/user/posted",
"/api/sns/v2/note/feed",
"/api/sns/v3/note/videofeed",
"/api/sns/v2/note/widgets",
"/api/sns/v5/note/comment/list",
"/api/sns/v10/search/notes",
}
)

type ListeningRequest struct {
proxy.BaseAddon
}

func (c *ListeningRequest) Response(f *proxy.Flow) {
contentType := f.Response.Header.Get("Content-Type")
if !strings.Contains(contentType, "json") {
return
}

for _, url := range urls {
if strings.Contains(f.Request.URL.String(), url) {
fmt.Println(f.Request.URL.String())
if !gjson.ValidBytes(f.Response.Body) {
log.Info("json is err")
continue
}
data := gjson.ParseBytes(f.Response.Body)
fmt.Println(data.String())
}
}
}

func main() {
opts := &proxy.Options{
Addr: ":9080",
StreamLargeBodies: 1024 * 1024 * 1000,
}

p, err := proxy.NewProxy(opts)
if err != nil {
log.Fatal(err)
}

//p.SetUpstreamProxy(func(req *http.Request) (*url.URL, error) {
// return url.Parse("socks:https://127.0.0.1:8889")
//})

p.AddAddon(&ListeningRequest{})

log.Fatal(p.Start())
}
5 changes: 4 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,14 @@ require (
github.com/samber/lo v1.37.0
github.com/satori/go.uuid v1.2.0
github.com/sirupsen/logrus v1.8.1
github.com/tidwall/gjson v1.17.0
github.com/tidwall/match v1.1.1
golang.org/x/net v0.17.0
)

require (
github.com/tidwall/pretty v1.2.0 // indirect
golang.org/x/exp v0.0.0-20220303212507-bbda1eaf7a17 // indirect
golang.org/x/sys v0.0.0-20220624220833-87e55d714810 // indirect
golang.org/x/sys v0.13.0 // indirect
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect
)
10 changes: 8 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,18 @@ github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE
github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/tidwall/gjson v1.17.0 h1:/Jocvlh98kcTfpN2+JzGQWQcqrPQwDrVEMApx/M5ZwM=
github.com/tidwall/gjson v1.17.0/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA=
github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM=
github.com/tidwall/pretty v1.2.0 h1:RWIZEg2iJ8/g6fDDYzMpobmaoGh5OLl4AXtGUGPcqCs=
github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
golang.org/x/exp v0.0.0-20220303212507-bbda1eaf7a17 h1:3MTrJm4PyNL9NBqvYDSj3DHl46qQakyfqfWo4jgfaEM=
golang.org/x/exp v0.0.0-20220303212507-bbda1eaf7a17/go.mod h1:lgLbSvA5ygNOMpwM/9anMpWVlVJ7Z+cHWq/eFuinpGE=
golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM=
golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE=
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20220624220833-87e55d714810 h1:rHZQSjJdAI4Xf5Qzeh2bBc5YJIkPFVM6oDtMFYmgws0=
golang.org/x/sys v0.0.0-20220624220833-87e55d714810/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE=
golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
114 changes: 65 additions & 49 deletions proxy/connection.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,14 @@ import (
"encoding/base64"
"encoding/json"
"errors"
uuid "github.com/satori/go.uuid"
log "github.com/sirupsen/logrus"
"golang.org/x/net/proxy"
"net"
"net/http"
"net/url"
"strings"
"time"

uuid "github.com/satori/go.uuid"
log "github.com/sirupsen/logrus"
)

// client connection
Expand Down Expand Up @@ -367,55 +367,71 @@ func (c *wrapServerConn) Close() error {

// connect proxy when set https_proxy env
// ref: http/transport.go dialConn func
func getProxyConn(proxyUrl *url.URL, address string) (net.Conn, error) {
conn, err := (&net.Dialer{}).DialContext(context.Background(), "tcp", proxyUrl.Host)
if err != nil {
return nil, err
}
connectReq := &http.Request{
Method: "CONNECT",
URL: &url.URL{Opaque: address},
Host: address,
Header: http.Header{},
}
if proxyUrl.User != nil {
connectReq.Header.Set("Proxy-Authorization", "Basic "+base64.StdEncoding.EncodeToString([]byte(proxyUrl.User.String())))
}
connectCtx, cancel := context.WithTimeout(context.Background(), 1*time.Minute)
defer cancel()
didReadResponse := make(chan struct{}) // closed after CONNECT write+read is done or fails
var resp *http.Response
// Write the CONNECT request & read the response.
go func() {
defer close(didReadResponse)
err = connectReq.Write(conn)
func getProxyConn(proxyUrl *url.URL, address string) (conn net.Conn, err error) {
if strings.Contains(proxyUrl.Scheme, "socks") {
auth := &proxy.Auth{}
if password, b := proxyUrl.User.Password(); b {
auth.User = proxyUrl.User.Username()
auth.Password = password
}
dialer, err := proxy.SOCKS5("tcp", proxyUrl.Host, auth, proxy.Direct)
if err != nil {
return
return nil, err
}
// Okay to use and discard buffered reader here, because
// TLS server will not speak until spoken to.
br := bufio.NewReader(conn)
resp, err = http.ReadResponse(br, connectReq)
}()
select {
case <-connectCtx.Done():
conn.Close()
<-didReadResponse
return nil, connectCtx.Err()
case <-didReadResponse:
// resp or err now set
}
if err != nil {
conn.Close()
return nil, err
}
if resp.StatusCode != 200 {
_, text, ok := strings.Cut(resp.Status, " ")
conn.Close()
if !ok {
return nil, errors.New("unknown status code")
conn, err = dialer.Dial("tcp", address)
if err != nil {
return nil, err
}
} else {
conn, err = (&net.Dialer{}).DialContext(context.Background(), "tcp", proxyUrl.Host)
if err != nil {
return nil, err
}
connectReq := &http.Request{
Method: "CONNECT",
URL: &url.URL{Opaque: address},
Host: address,
Header: http.Header{},
}
if proxyUrl.User != nil {
connectReq.Header.Set("Proxy-Authorization", "Basic "+base64.StdEncoding.EncodeToString([]byte(proxyUrl.User.String())))
}
connectCtx, cancel := context.WithTimeout(context.Background(), 1*time.Minute)
defer cancel()
didReadResponse := make(chan struct{}) // closed after CONNECT write+read is done or fails
var resp *http.Response
// Write the CONNECT request & read the response.
go func() {
defer close(didReadResponse)
err = connectReq.Write(conn)
if err != nil {
return
}
// Okay to use and discard buffered reader here, because
// TLS server will not speak until spoken to.
br := bufio.NewReader(conn)
resp, err = http.ReadResponse(br, connectReq)
}()
select {
case <-connectCtx.Done():
conn.Close()
<-didReadResponse
return nil, connectCtx.Err()
case <-didReadResponse:
// resp or err now set
}
if err != nil {
conn.Close()
return nil, err
}
if resp.StatusCode != 200 {
_, text, ok := strings.Cut(resp.Status, " ")
conn.Close()
if !ok {
return nil, errors.New("unknown status code")
}
return nil, errors.New(text)
}
return nil, errors.New(text)
}
return conn, nil
}

0 comments on commit 34dcb04

Please sign in to comment.