Skip to content

Commit d0a17f4

Browse files
committed
Support proxy
1 parent afc88a9 commit d0a17f4

File tree

4 files changed

+104
-19
lines changed

4 files changed

+104
-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: 80 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,70 @@
11
package http
22

33
import (
4+
"bufio"
45
"crypto/tls"
56
"fmt"
67
"net"
8+
"net/url"
79
"regexp"
810
"time"
11+
12+
"golang.org/x/net/proxy"
913
)
1014

11-
func Connect(addr string, isHttps bool, timeout int) *net.Conn {
12-
var n net.Conn
13-
var err error
15+
func dialProxy(addr, proxyString string, dialer *net.Dialer) (conn net.Conn, err error) {
16+
17+
proxyUrl, err := url.Parse(proxyString)
18+
if err != nil {
19+
return nil, err
20+
}
21+
if proxyUrl.Scheme == "socks5" {
22+
dialer, err := proxy.SOCKS5("tcp", proxyUrl.Host, nil, dialer)
23+
if err != nil {
24+
return nil, err
25+
}
26+
conn, err = dialer.Dial("tcp", addr)
27+
if err != nil {
28+
return nil, err
29+
}
30+
} else if proxyUrl.Scheme == "http" {
31+
conn, err = dialer.Dial("tcp", proxyUrl.Host)
32+
if err != nil {
33+
return nil, err
34+
}
35+
fmt.Fprintf(conn, "CONNECT %s HTTP/1.1\r\nHost: %s\r\n\r\n", addr, addr)
36+
37+
reader := bufio.NewReader(conn)
38+
39+
line, err := reader.ReadString('\n')
40+
if err != nil {
41+
return nil, err
42+
}
43+
if m, err := regexp.MatchString("HTTP/[\\d\\.]+ 200 Connection established", line); !m {
44+
conn.Close()
45+
return nil, fmt.Errorf("CONNECT请求失败: %s %s", line, err)
46+
}
47+
48+
for {
49+
line, err := reader.ReadString('\n')
50+
if err != nil {
51+
conn.Close()
52+
return nil, fmt.Errorf("读取CONNECT响应头失败: %v", err)
53+
}
54+
if line == "\r\n" {
55+
break
56+
}
57+
}
58+
} else {
59+
return nil, fmt.Errorf("不支持的代理类型: " + proxyUrl.Scheme)
60+
}
61+
if err != nil {
62+
return nil, fmt.Errorf("连接失败: %v", err)
63+
}
64+
return conn, nil
65+
}
66+
67+
func Connect(addr string, proxyString string, isHttps bool, timeout int) (conn net.Conn, err error) {
1468
if m, _ := regexp.MatchString(`.*(]:)|(:)[0-9]+$`, addr); !m {
1569
if isHttps {
1670
addr = fmt.Sprintf("%s:443", addr)
@@ -20,25 +74,40 @@ func Connect(addr string, isHttps bool, timeout int) *net.Conn {
2074
}
2175
retryCnt := 0
2276
retry:
23-
if isHttps {
24-
n, err = tls.Dial("tcp", addr, &tls.Config{InsecureSkipVerify: true})
77+
dialer := net.Dialer{
78+
Timeout: time.Duration(timeout) * time.Millisecond * 2,
79+
}
80+
if proxyString != "" {
81+
conn, err = dialProxy(addr, proxyString, &dialer)
2582
} else {
26-
n, err = net.Dial("tcp", addr)
83+
conn, err = dialer.Dial("tcp", addr)
2784
}
2885
if err != nil {
2986
retryCnt++
3087
if retryCnt < 4 {
3188
goto retry
3289
} else {
33-
return nil
90+
return nil, err
91+
}
92+
}
93+
if isHttps {
94+
tlsConn := tls.Client(conn, &tls.Config{InsecureSkipVerify: true})
95+
if err := tlsConn.Handshake(); err != nil {
96+
retryCnt++
97+
if retryCnt < 4 {
98+
goto retry
99+
} else {
100+
return nil, err
101+
}
34102
}
103+
conn = tlsConn
35104
}
36105
wDeadline := time.Now().Add(time.Duration(timeout) * time.Millisecond)
37106
rDeadline := time.Now().Add(time.Duration(timeout*2) * time.Millisecond)
38107
deadline := time.Now().Add(time.Duration(timeout*2) * time.Millisecond)
39-
_ = n.SetDeadline(deadline)
40-
_ = n.SetReadDeadline(rDeadline)
41-
_ = n.SetWriteDeadline(wDeadline)
108+
_ = conn.SetDeadline(deadline)
109+
_ = conn.SetReadDeadline(rDeadline)
110+
_ = conn.SetWriteDeadline(wDeadline)
42111

43-
return &n
112+
return conn, nil
44113
}

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)