forked from bogdanfinn/tls-client
-
Notifications
You must be signed in to change notification settings - Fork 0
/
client_options.go
270 lines (232 loc) · 8.83 KB
/
client_options.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
package tls_client
import (
"crypto/x509"
"fmt"
"io"
"net"
"time"
http "github.com/bogdanfinn/fhttp"
"github.com/bogdanfinn/tls-client/profiles"
)
type HttpClientOption func(config *httpClientConfig)
type TransportOptions struct {
// KeyLogWriter is an io.Writer that the TLS client will use to write the
// TLS master secrets to. This can be used to decrypt TLS connections in
// Wireshark and other applications.
KeyLogWriter io.Writer
// IdleConnTimeout is the maximum amount of time an idle (keep-alive)
// connection will remain idle before closing itself. Zero means no limit.
IdleConnTimeout *time.Duration
// RootCAs is the set of root certificate authorities used to verify
// the remote server's certificate.
RootCAs *x509.CertPool
MaxIdleConns int
MaxIdleConnsPerHost int
MaxConnsPerHost int
MaxResponseHeaderBytes int64 // Zero means to use a default limit.
WriteBufferSize int // If zero, a default (currently 4KB) is used.
ReadBufferSize int // If zero, a default (currently 4KB) is used.
DisableKeepAlives bool
DisableCompression bool
}
type BadPinHandlerFunc func(req *http.Request)
type httpClientConfig struct {
cookieJar http.CookieJar
customRedirectFunc func(req *http.Request, via []*http.Request) error
certificatePins map[string][]string
defaultHeaders http.Header
connectHeaders http.Header
badPinHandler BadPinHandlerFunc
transportOptions *TransportOptions
localAddr *net.TCPAddr
dialer net.Dialer
proxyUrl string
serverNameOverwrite string
clientProfile profiles.ClientProfile
timeout time.Duration
catchPanics bool
debug bool
followRedirects bool
insecureSkipVerify bool
withRandomTlsExtensionOrder bool
forceHttp1 bool
// Establish a connection to origin server via ipv4 only
disableIPV6 bool
// Establish a connection to origin server via ipv6 only
disableIPV4 bool
enabledBandwidthTracker bool
}
// WithProxyUrl configures a HTTP client to use the specified proxy URL.
//
// proxyUrl should be formatted as:
//
// "http://user:pass@host:port"
func WithProxyUrl(proxyUrl string) HttpClientOption {
return func(config *httpClientConfig) {
config.proxyUrl = proxyUrl
}
}
// WithCharlesProxy configures the HTTP client to use a local running charles as proxy.
//
// host and port can be empty, then default 127.0.0.1 and port 8888 will be used
func WithCharlesProxy(host string, port string) HttpClientOption {
h := "127.0.0.1"
p := "8888"
if host != "" {
h = host
}
if port != "" {
p = port
}
proxyUrl := fmt.Sprintf("http://%s:%s", h, p)
return WithProxyUrl(proxyUrl)
}
// WithCookieJar configures a HTTP client to use the specified cookie jar.
func WithCookieJar(jar http.CookieJar) HttpClientOption {
return func(config *httpClientConfig) {
config.cookieJar = jar
}
}
// WithTimeoutMilliseconds configures an HTTP client to use the specified request timeout.
//
// timeout is the request timeout in milliseconds.
func WithTimeoutMilliseconds(timeout int) HttpClientOption {
return func(config *httpClientConfig) {
config.timeout = time.Millisecond * time.Duration(timeout)
}
}
// WithDialer configures an HTTP client to use the specified dialer. This allows the use of a custom DNS resolver
func WithDialer(dialer net.Dialer) HttpClientOption {
return func(config *httpClientConfig) {
config.dialer = dialer
}
}
// WithTimeoutSeconds configures an HTTP client to use the specified request timeout.
//
// timeout is the request timeout in seconds.
func WithTimeoutSeconds(timeout int) HttpClientOption {
return func(config *httpClientConfig) {
config.timeout = time.Second * time.Duration(timeout)
}
}
// WithTimeout configures an HTTP client to use the specified request timeout.
//
// timeout is the request timeout in seconds.
// Deprecated: use either WithTimeoutSeconds or WithTimeoutMilliseconds
func WithTimeout(timeout int) HttpClientOption {
return func(config *httpClientConfig) {
config.timeout = time.Second * time.Duration(timeout)
}
}
// WithNotFollowRedirects configures an HTTP client to not follow HTTP redirects.
func WithNotFollowRedirects() HttpClientOption {
return func(config *httpClientConfig) {
config.followRedirects = false
}
}
// WithLocalAddr configures an HTTP client to use the specified local address.
func WithLocalAddr(localAddr net.TCPAddr) HttpClientOption {
return func(config *httpClientConfig) {
config.localAddr = &localAddr
}
}
// WithCustomRedirectFunc configures an HTTP client to use a custom redirect func.
// The redirect func have to look like that: func(req *http.Request, via []*http.Request) error
// Please only provide a custom redirect function if you know what you are doing.
// Check docs on net/http.Client CheckRedirect
func WithCustomRedirectFunc(redirectFunc func(req *http.Request, via []*http.Request) error) HttpClientOption {
return func(config *httpClientConfig) {
config.customRedirectFunc = redirectFunc
}
}
// WithRandomTLSExtensionOrder configures a TLS client to randomize the order of TLS extensions being sent in the ClientHello.
//
// Placement of GREASE and padding is fixed and will not be affected by this.
func WithRandomTLSExtensionOrder() HttpClientOption {
return func(config *httpClientConfig) {
config.withRandomTlsExtensionOrder = true
}
}
// WithCertificatePinning enables SSL Pinning for the client and will throw an error if the SSL Pin is not matched.
// Please refer to https://github.com/tam7t/hpkp/#examples in order to see how to generate pins. The certificatePins are a map with the host as key.
// You can provide a BadPinHandlerFunc or nil as second argument. This function will be executed once a bad ssl pin is detected.
// BadPinHandlerFunc has to be defined like this: func(req *http.Request){}
func WithCertificatePinning(certificatePins map[string][]string, handlerFunc BadPinHandlerFunc) HttpClientOption {
return func(config *httpClientConfig) {
config.certificatePins = certificatePins
config.badPinHandler = handlerFunc
}
}
// WithDebug configures a client to log debugging information.
func WithDebug() HttpClientOption {
return func(config *httpClientConfig) {
config.debug = true
}
}
// WithCatchPanics configures a client to catch all go panics happening during a request and not print the stacktrace.
func WithCatchPanics() HttpClientOption {
return func(config *httpClientConfig) {
config.catchPanics = true
}
}
// WithTransportOptions configures a client to use the specified transport options.
func WithTransportOptions(transportOptions *TransportOptions) HttpClientOption {
return func(config *httpClientConfig) {
config.transportOptions = transportOptions
}
}
// WithInsecureSkipVerify configures a client to skip SSL certificate verification.
func WithInsecureSkipVerify() HttpClientOption {
return func(config *httpClientConfig) {
config.insecureSkipVerify = true
}
}
// WithForceHttp1 configures a client to force HTTP/1.1 as the used protocol.
func WithForceHttp1() HttpClientOption {
return func(config *httpClientConfig) {
config.forceHttp1 = true
}
}
// WithClientProfile configures a TLS client to use the specified client profile.
func WithClientProfile(clientProfile profiles.ClientProfile) HttpClientOption {
return func(config *httpClientConfig) {
config.clientProfile = clientProfile
}
}
// WithDefaultHeaders configures a TLS client to use a set of default headers if none are specified on the request.
func WithDefaultHeaders(defaultHeaders http.Header) HttpClientOption {
return func(config *httpClientConfig) {
config.defaultHeaders = defaultHeaders
}
}
// WithServerNameOverwrite configures a TLS client to overwrite the server name being used for certificate verification and in the client hello.
// This option does only work properly if WithInsecureSkipVerify is set to true in addition
func WithServerNameOverwrite(serverName string) HttpClientOption {
return func(config *httpClientConfig) {
config.serverNameOverwrite = serverName
}
}
// WithDisableIPV6 configures a dialer to use tcp4 network argument
func WithDisableIPV6() HttpClientOption {
return func(config *httpClientConfig) {
config.disableIPV6 = true
}
}
// WithDisableIPV4 configures a dialer to use tcp6 network argument
func WithDisableIPV4() HttpClientOption {
return func(config *httpClientConfig) {
config.disableIPV4 = true
}
}
// WithBandwidthTracker configures a client to track the bandwidth used by the client.
func WithBandwidthTracker() HttpClientOption {
return func(config *httpClientConfig) {
config.enabledBandwidthTracker = true
}
}
// WithConnectHeaders configures a client to use the specified headers for the CONNECT request.
func WithConnectHeaders(headers http.Header) HttpClientOption {
return func(config *httpClientConfig) {
config.connectHeaders = headers
}
}