Skip to content

Commit 4b946c9

Browse files
authored
Merge pull request #157 from SenseUnit/force-resolve
Compound dialers
2 parents 0108057 + f4f228a commit 4b946c9

File tree

4 files changed

+43
-3
lines changed

4 files changed

+43
-3
lines changed

README.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -412,6 +412,9 @@ Supported proxy schemes are:
412412
* `cached` - pseudo-dialer which caches construction of another dialer specified by URL passed in `url` parameter of query string. Useful for dialers which are constructed dynamically from JS router script and which load certificate files. Example: `cache://?url=https%3A%2F%2Fexample.org%3Fcert%3Dcert.pem%26key%3Dkey.pem&ttl=5m`. Query string parameters are:
413413
* `url` - actual proxy URL. Note that just like any query string parameter this one has to be URL-encoded to be passed as query string value.
414414
* `ttl` - time to live for cache record. Examples: `15s`, `2m`, `1h`.
415+
* `force-resolve` - pseudo-proxy forcing domain name resolve before it will be passed to the next proxy in the chain. Must wrap actual proxy dialer in the chain (i.e. be specified in last `-proxy` argument). Example: `force-resolve://`
416+
* `chain` - pseudo-proxy assembling a chain from other proxy specifications. Query string parameters are:
417+
* `next` - specification of the next proxy in chain. This query string parameter can be specified more than once. Example: `chain://?next=http%3A%2F%2F127.0.0.1%3A57800&next=force-resolve%3A%2F%2F`.
415418

416419
## Configuration files
417420

dialer/chain.go

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
package dialer
2+
3+
import (
4+
"fmt"
5+
"net/url"
6+
7+
xproxy "golang.org/x/net/proxy"
8+
)
9+
10+
func ChainFromURL(u *url.URL, base xproxy.Dialer) (xproxy.Dialer, error) {
11+
var d Dialer = MaybeWrapWithContextDialer(base)
12+
params, err := url.ParseQuery(u.RawQuery)
13+
if err != nil {
14+
return nil, err
15+
}
16+
for i, proxySpec := range params["next"] {
17+
newDialer, err := ProxyDialerFromURL(proxySpec, d)
18+
if err != nil {
19+
return nil, fmt.Errorf("unable to construct proxy chain: proxy spec #%d %q construction failed: %w", i+1, proxySpec, err)
20+
}
21+
d = newDialer
22+
}
23+
return d, nil
24+
}

dialer/dialer.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,10 @@ func init() {
2424
xproxy.RegisterDialerType("cached", GetCachedDialer)
2525
xproxy.RegisterDialerType("socks5s", SOCKS5SDialerFromURL)
2626
xproxy.RegisterDialerType("socks5hs", SOCKS5SDialerFromURL)
27+
xproxy.RegisterDialerType("force-resolve", func(_ *url.URL, d xproxy.Dialer) (xproxy.Dialer, error) {
28+
return NeverRequireHostname(MaybeWrapWithContextDialer(d)), nil
29+
})
30+
xproxy.RegisterDialerType("chain", ChainFromURL)
2731
}
2832

2933
type LegacyDialer interface {

dialer/protect.go

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,21 @@ type HostnameWanter interface {
1010
}
1111

1212
type WrappedHostnameDialer struct {
13-
Dialer Dialer
13+
Dialer Dialer
14+
WantsHostnameValue bool
1415
}
1516

1617
func AlwaysRequireHostname(d Dialer) Dialer {
1718
return WrappedHostnameDialer{
18-
Dialer: d,
19+
Dialer: d,
20+
WantsHostnameValue: true,
21+
}
22+
}
23+
24+
func NeverRequireHostname(d Dialer) Dialer {
25+
return WrappedHostnameDialer{
26+
Dialer: d,
27+
WantsHostnameValue: false,
1928
}
2029
}
2130

@@ -28,7 +37,7 @@ func (w WrappedHostnameDialer) Dial(network, address string) (net.Conn, error) {
2837
}
2938

3039
func (w WrappedHostnameDialer) WantsHostname(_ context.Context, _, _ string) bool {
31-
return true
40+
return w.WantsHostnameValue
3241
}
3342

3443
var _ Dialer = WrappedHostnameDialer{}

0 commit comments

Comments
 (0)