Skip to content

Commit cf94a52

Browse files
committed
Support proxy
1 parent afc88a9 commit cf94a52

File tree

4 files changed

+126
-19
lines changed

4 files changed

+126
-19
lines changed

cmd/blazehttp/main.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ var (
2727
timeout = 1000 // default 1000 ms
2828
c = 10 // default 10 concurrent workers
2929
mHost string // modify host header
30+
proxy string // proxy address, example: http://127.0.0.1:8083
3031
requestPerSession bool // send request per session
3132
)
3233

@@ -40,6 +41,7 @@ func init() {
4041
flag.StringVar(&glob, "g", "", "glob expression, example: *.http")
4142
flag.IntVar(&timeout, "timeout", 1000, "connection timeout, default 1000 ms")
4243
flag.StringVar(&mHost, "H", "", "modify host header")
44+
flag.StringVar(&proxy, "proxy", "", "proxy address, example: http://127.0.0.1:8083")
4345
flag.BoolVar(&requestPerSession, "rps", true, "send request per session")
4446
flag.Parse()
4547
if url, err := url.Parse(target); err != nil || url.Scheme == "" || url.Host == "" {
@@ -122,6 +124,7 @@ func main() {
122124
worker.WithReqPerSession(requestPerSession),
123125
worker.WithTimeout(timeout),
124126
worker.WithUseEmbedFS(glob == ""), // use embed test case fs when glob is empty
127+
worker.WithProxy(proxy),
125128
worker.WithProgressBar(progressBar),
126129
)
127130
c := make(chan os.Signal, 1)

gui/main.go

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -254,11 +254,15 @@ func MakeRunForm(w fyne.Window, outputCh chan string, resultCh chan *worker.Resu
254254
statusCode.SetText("403")
255255
statusCode.Validator = validation.NewRegexp(`^\d+$`, "StatusCode必须是数字")
256256

257+
// 代理地址
258+
proxy := widget.NewEntry()
259+
257260
advanceForm := &widget.Form{
258261
Items: []*widget.FormItem{
259262
{Text: "修改请求(Host)", Widget: reqHost, HintText: ""},
260263
{Text: "请求超时", Widget: timeout, HintText: ""},
261264
{Text: "拦截状态码(respCode)", Widget: statusCode, HintText: "一般情况下WAF拦截状态码为403"},
265+
{Text: "代理地址", Widget: proxy, HintText: "例如: http://127.0.0.1:8080"},
262266
},
263267
}
264268

@@ -307,7 +311,7 @@ func MakeRunForm(w fyne.Window, outputCh chan string, resultCh chan *worker.Resu
307311
statusCode := strings.TrimSpace(statusCode.Text)
308312
statusCodeI, _ := strconv.Atoi(statusCode)
309313

310-
err := run(target.Text, reqHost.Text, worksNum, statusCodeI, resultCh, stopCh)
314+
err := run(target.Text, reqHost.Text, proxy.Text, worksNum, statusCodeI, resultCh, stopCh)
311315
if err != nil {
312316
outputCh <- err.Error()
313317
}
@@ -460,7 +464,7 @@ func MakeTestCaseTab(w fyne.Window) fyne.CanvasObject {
460464
return container.NewBorder(tableFilterForm, nil, nil, exportBtn, table)
461465
}
462466

463-
func run(target, mHost string, c, statusCode int, resultCh chan *worker.Result, stopCh chan struct{}) error {
467+
func run(target, mHost, proxy string, c, statusCode int, resultCh chan *worker.Result, stopCh chan struct{}) error {
464468
var addr string
465469
var isHttps bool
466470

@@ -491,6 +495,7 @@ func run(target, mHost string, c, statusCode int, resultCh chan *worker.Result,
491495
worker.WithConcurrence(c),
492496
worker.WithReqHost(mHost),
493497
worker.WithUseEmbedFS(true), // use embed test case fs when glob is empty
498+
worker.WithProxy(proxy),
494499
worker.WithResultCh(resultCh),
495500
)
496501
go func() {

http/connect.go

Lines changed: 102 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,92 @@
11
package http
22

33
import (
4+
"bufio"
45
"crypto/tls"
6+
"encoding/base64"
57
"fmt"
68
"net"
9+
"net/url"
710
"regexp"
811
"time"
12+
13+
"golang.org/x/net/proxy"
914
)
1015

11-
func Connect(addr string, isHttps bool, timeout int) *net.Conn {
12-
var n net.Conn
13-
var err error
16+
func dialProxy(addr, proxyString string, dialer *net.Dialer) (conn net.Conn, err error) {
17+
18+
proxyUrl, err := url.Parse(proxyString)
19+
if err != nil {
20+
return nil, err
21+
}
22+
if proxyUrl.Scheme == "socks5" {
23+
var auth *proxy.Auth = nil;
24+
if proxyUrl.User != nil {
25+
username := proxyUrl.User.Username()
26+
password, _ := proxyUrl.User.Password()
27+
auth = &proxy.Auth{
28+
User: username,
29+
Password: password,
30+
}
31+
}
32+
dialer, err := proxy.SOCKS5("tcp", proxyUrl.Host, auth, dialer)
33+
if err != nil {
34+
return nil, err
35+
}
36+
conn, err = dialer.Dial("tcp", addr)
37+
if err != nil {
38+
return nil, err
39+
}
40+
} else if proxyUrl.Scheme == "http" {
41+
conn, err = dialer.Dial("tcp", proxyUrl.Host)
42+
if err != nil {
43+
return nil, err
44+
}
45+
request := fmt.Sprintf("CONNECT %s HTTP/1.1\r\nHost: %s\r\n", addr, addr)
46+
if proxyUrl.User != nil {
47+
username := proxyUrl.User.Username()
48+
password, _ := proxyUrl.User.Password()
49+
auth := base64.StdEncoding.EncodeToString([]byte(username + ":" + password))
50+
request += "Proxy-Authorization: Basic " + auth + "\r\n"
51+
}
52+
request += "\r\n"
53+
_, err = fmt.Fprint(conn, request)
54+
if err != nil {
55+
conn.Close()
56+
return nil, err
57+
}
58+
59+
reader := bufio.NewReader(conn)
60+
61+
line, err := reader.ReadString('\n')
62+
if err != nil {
63+
return nil, err
64+
}
65+
if m, err := regexp.MatchString("HTTP/[\\d\\.]+ 200 Connection established", line); !m {
66+
conn.Close()
67+
return nil, fmt.Errorf("CONNECT请求失败: %s %s", line, err)
68+
}
69+
70+
for {
71+
line, err := reader.ReadString('\n')
72+
if err != nil {
73+
conn.Close()
74+
return nil, fmt.Errorf("读取CONNECT响应头失败: %v", err)
75+
}
76+
if line == "\r\n" {
77+
break
78+
}
79+
}
80+
} else {
81+
return nil, fmt.Errorf("不支持的代理类型: " + proxyUrl.Scheme)
82+
}
83+
if err != nil {
84+
return nil, fmt.Errorf("连接失败: %v", err)
85+
}
86+
return conn, nil
87+
}
88+
89+
func Connect(addr string, proxyString string, isHttps bool, timeout int) (conn net.Conn, err error) {
1490
if m, _ := regexp.MatchString(`.*(]:)|(:)[0-9]+$`, addr); !m {
1591
if isHttps {
1692
addr = fmt.Sprintf("%s:443", addr)
@@ -20,25 +96,40 @@ func Connect(addr string, isHttps bool, timeout int) *net.Conn {
2096
}
2197
retryCnt := 0
2298
retry:
23-
if isHttps {
24-
n, err = tls.Dial("tcp", addr, &tls.Config{InsecureSkipVerify: true})
99+
dialer := net.Dialer{
100+
Timeout: time.Duration(timeout) * time.Millisecond * 2,
101+
}
102+
if proxyString != "" {
103+
conn, err = dialProxy(addr, proxyString, &dialer)
25104
} else {
26-
n, err = net.Dial("tcp", addr)
105+
conn, err = dialer.Dial("tcp", addr)
27106
}
28107
if err != nil {
29108
retryCnt++
30109
if retryCnt < 4 {
31110
goto retry
32111
} else {
33-
return nil
112+
return nil, err
113+
}
114+
}
115+
if isHttps {
116+
tlsConn := tls.Client(conn, &tls.Config{InsecureSkipVerify: true})
117+
if err := tlsConn.Handshake(); err != nil {
118+
retryCnt++
119+
if retryCnt < 4 {
120+
goto retry
121+
} else {
122+
return nil, err
123+
}
34124
}
125+
conn = tlsConn
35126
}
36127
wDeadline := time.Now().Add(time.Duration(timeout) * time.Millisecond)
37128
rDeadline := time.Now().Add(time.Duration(timeout*2) * time.Millisecond)
38129
deadline := time.Now().Add(time.Duration(timeout*2) * time.Millisecond)
39-
_ = n.SetDeadline(deadline)
40-
_ = n.SetReadDeadline(rDeadline)
41-
_ = n.SetWriteDeadline(wDeadline)
130+
_ = conn.SetDeadline(deadline)
131+
_ = conn.SetReadDeadline(rDeadline)
132+
_ = conn.SetWriteDeadline(wDeadline)
42133

43-
return &n
134+
return conn, nil
44135
}

worker/worker.go

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -35,12 +35,20 @@ type Worker struct {
3535
reqHost string // request host of header
3636
reqPerSession bool // request per session
3737
useEmbedFS bool
38+
proxy string
3839
resultCh chan *Result
3940
}
4041

4142
type WorkerOption func(*Worker)
4243

44+
func WithProxy(proxy string) WorkerOption {
45+
return func(w *Worker) {
46+
w.proxy = proxy
47+
}
48+
}
49+
4350
func WithTimeout(timeout int) WorkerOption {
51+
4452
return func(w *Worker) {
4553
w.timeout = timeout
4654
}
@@ -213,24 +221,24 @@ func (w *Worker) runWorker() {
213221
req.CalculateContentLength()
214222

215223
start := time.Now()
216-
conn := blazehttp.Connect(w.addr, w.isHttps, w.timeout)
217-
if conn == nil {
218-
job.Result.Err = fmt.Sprintf("connect to %s failed!\n", w.addr)
224+
conn, err := blazehttp.Connect(w.addr, w.proxy, w.isHttps, w.timeout)
225+
if err != nil {
226+
job.Result.Err = fmt.Sprintf("connect to %s failed!\n", err)
219227
return
220228
}
221-
nWrite, err := req.WriteTo(*conn)
229+
defer conn.Close()
230+
nWrite, err := req.WriteTo(conn)
222231
if err != nil {
223232
job.Result.Err = fmt.Sprintf("send request poc: %s length: %d error: %s", filePath, nWrite, err)
224233
return
225234
}
226235

227236
rsp := new(blazehttp.Response)
228-
if err = rsp.ReadConn(*conn); err != nil {
237+
if err = rsp.ReadConn(conn); err != nil {
229238
job.Result.Err = fmt.Sprintf("read poc file: %s response, error: %s", filePath, err)
230239
return
231240
}
232241
elap := time.Since(start).Nanoseconds()
233-
(*conn).Close()
234242
job.Result.Success = true
235243
if strings.HasSuffix(job.FilePath, "white") {
236244
job.Result.IsWhite = true // white case

0 commit comments

Comments
 (0)