@@ -2,18 +2,25 @@ package rawhttp
22
33import (
44 "crypto/tls"
5+ "fmt"
56 "io"
67 "net"
8+ "net/url"
9+ "strings"
710 "sync"
811 "time"
912
1013 "github.com/projectdiscovery/rawhttp/client"
14+ "github.com/projectdiscovery/rawhttp/proxy"
1115)
1216
1317// Dialer can dial a remote HTTP server.
1418type Dialer interface {
1519 // Dial dials a remote http server returning a Conn.
1620 Dial (protocol , addr string ) (Conn , error )
21+ DialWithProxy (protocol , addr , proxyURL string , timeout time.Duration ) (Conn , error )
22+ // Dial dials a remote http server with timeout returning a Conn.
23+ DialTimeout (protocol , addr string , timeout time.Duration ) (Conn , error )
1724}
1825
1926type dialer struct {
@@ -22,35 +29,91 @@ type dialer struct {
2229}
2330
2431func (d * dialer ) Dial (protocol , addr string ) (Conn , error ) {
32+ return d .dialTimeout (protocol , addr , 0 )
33+ }
34+
35+ func (d * dialer ) DialTimeout (protocol , addr string , timeout time.Duration ) (Conn , error ) {
36+ return d .dialTimeout (protocol , addr , timeout )
37+ }
38+
39+ func (d * dialer ) dialTimeout (protocol , addr string , timeout time.Duration ) (Conn , error ) {
2540 d .Lock ()
2641 if d .conns == nil {
2742 d .conns = make (map [string ][]Conn )
2843 }
2944 if c , ok := d .conns [addr ]; ok {
3045 if len (c ) > 0 {
3146 conn := c [0 ]
32- c [0 ], c = c [len ( c ) - 1 ], c [: len (c )- 1 ]
47+ c [0 ] = c [len (c )- 1 ]
3348 d .Unlock ()
3449 return conn , nil
3550 }
3651 }
3752 d .Unlock ()
38- c , err := clientDial (protocol , addr )
53+ c , err := clientDial (protocol , addr , timeout )
3954 return & conn {
4055 Client : client .NewClient (c ),
4156 Conn : c ,
4257 dialer : d ,
4358 }, err
4459}
4560
46- func clientDial (protocol , addr string ) (net.Conn , error ) {
47- // http
48- if protocol == "http" {
49- return net .Dial ("tcp" , addr )
61+ func (d * dialer ) DialWithProxy (protocol , addr , proxyURL string , timeout time.Duration ) (Conn , error ) {
62+ var c net.Conn
63+ u , err := url .Parse (proxyURL )
64+ if err != nil {
65+ return nil , fmt .Errorf ("unsupported proxy error: %w" , err )
66+ }
67+ switch u .Scheme {
68+ case "http" :
69+ c , err = proxy .HTTPDialer (proxyURL , timeout )(addr )
70+ case "socks5" , "socks5h" :
71+ c , err = proxy .Socks5Dialer (proxyURL , timeout )(addr )
72+ default :
73+ return nil , fmt .Errorf ("unsupported proxy protocol: %s" , proxyURL )
74+ }
75+ if err != nil {
76+ return nil , fmt .Errorf ("proxy error: %w" , err )
5077 }
78+ if protocol == "https" {
79+ if c , err = TlsHandshake (c , addr ); err != nil {
80+ return nil , fmt .Errorf ("tls handshake error: %w" , err )
81+ }
82+ }
83+ return & conn {
84+ Client : client .NewClient (c ),
85+ Conn : c ,
86+ dialer : d ,
87+ }, err
88+ }
89+
90+ func clientDial (protocol , addr string , timeout time.Duration ) (net.Conn , error ) {
91+ conn , err := net .DialTimeout ("tcp" , addr , timeout )
92+ if protocol == "https" {
93+ if conn , err = TlsHandshake (conn , addr ); err != nil {
94+ return nil , fmt .Errorf ("tls handshake error: %w" , err )
95+ }
96+ }
97+ return conn , err
98+ }
5199
52- // https
53- return tls .Dial ("tcp" , addr , & tls.Config {InsecureSkipVerify : true })
100+ // TlsHandshake tls handshake on a plain connection
101+ func TlsHandshake (conn net.Conn , addr string ) (net.Conn , error ) {
102+ colonPos := strings .LastIndex (addr , ":" )
103+ if colonPos == - 1 {
104+ colonPos = len (addr )
105+ }
106+ hostname := addr [:colonPos ]
107+
108+ tlsConn := tls .Client (conn , & tls.Config {
109+ InsecureSkipVerify : true ,
110+ ServerName : hostname ,
111+ })
112+ if err := tlsConn .Handshake (); err != nil {
113+ conn .Close ()
114+ return nil , err
115+ }
116+ return tlsConn , nil
54117}
55118
56119// Conn is an interface implemented by a connection
0 commit comments