Proxy auth and isolate test
* Don't use Tor info for proxy auth and update docs which fixes #18 * Add new test to confirm functionality of IsolateSOCKSAuth
This commit is contained in:
parent
25e2ee8b21
commit
5c62b5e9f6
|
@ -8,12 +8,13 @@ import (
|
|||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/cretz/bine/tor"
|
||||
"golang.org/x/net/context/ctxhttp"
|
||||
)
|
||||
|
||||
func TestDialerSimpleHTTP(t *testing.T) {
|
||||
ctx := GlobalEnabledNetworkContext(t)
|
||||
httpClient := httpClient(ctx)
|
||||
httpClient := httpClient(ctx, nil)
|
||||
// IsTor check
|
||||
byts := httpGet(ctx, httpClient, "https://check.torproject.org/api/ip")
|
||||
jsn := map[string]interface{}{}
|
||||
|
@ -21,12 +22,12 @@ func TestDialerSimpleHTTP(t *testing.T) {
|
|||
ctx.Require.True(jsn["IsTor"].(bool))
|
||||
}
|
||||
|
||||
func httpClient(ctx *TestContext) *http.Client {
|
||||
func httpClient(ctx *TestContext, conf *tor.DialConf) *http.Client {
|
||||
// 15 seconds max to dial
|
||||
dialCtx, dialCancel := context.WithTimeout(ctx, 15*time.Second)
|
||||
defer dialCancel()
|
||||
// Make connection
|
||||
dialer, err := ctx.Dialer(dialCtx, nil)
|
||||
dialer, err := ctx.Dialer(dialCtx, conf)
|
||||
ctx.Require.NoError(err)
|
||||
return &http.Client{Transport: &http.Transport{DialContext: dialer.DialContext}}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,72 @@
|
|||
package tests
|
||||
|
||||
import (
|
||||
"context"
|
||||
"strconv"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/cretz/bine/tor"
|
||||
"golang.org/x/net/proxy"
|
||||
)
|
||||
|
||||
// TestIsolateSocksAuth simply confirms the functionality of IsolateSOCKSAuth,
|
||||
// namely that it uses a different circuit for different SOCKS credentials.
|
||||
func TestIsolateSocksAuth(t *testing.T) {
|
||||
// Create context w/ no isolate
|
||||
ctx := NewTestContext(t, &tor.StartConf{
|
||||
NoAutoSocksPort: true,
|
||||
ExtraArgs: []string{"--SocksPort", "auto NoIsolateSOCKSAuth"},
|
||||
})
|
||||
// Make sure it reused the circuit (i.e. only has one) for both separate-auth calls
|
||||
uniqueCircuitIDs := doSeparateAuthHttpCalls(ctx)
|
||||
ctx.Debugf("Unique IDs without isolate: %v", uniqueCircuitIDs)
|
||||
ctx.Require.Len(uniqueCircuitIDs, 1)
|
||||
// Create context w/ isolate
|
||||
ctx = NewTestContext(t, nil)
|
||||
// Make sure it made a new circuit (i.e. has two) for each separate-auth call
|
||||
uniqueCircuitIDs = doSeparateAuthHttpCalls(ctx)
|
||||
ctx.Debugf("Unique IDs with isolate: %v", uniqueCircuitIDs)
|
||||
ctx.Require.Len(uniqueCircuitIDs, 2)
|
||||
}
|
||||
|
||||
// Returns the map keyed with unique circuit IDs after second separate-auth HTTP call
|
||||
func doSeparateAuthHttpCalls(ctx *TestContext) map[int]struct{} {
|
||||
defer ctx.Close()
|
||||
enableCtx, enableCancel := context.WithTimeout(ctx, 100*time.Second)
|
||||
defer enableCancel()
|
||||
ctx.Require.NoError(ctx.EnableNetwork(enableCtx, true))
|
||||
// Make HTTP call w/ an auth
|
||||
client := httpClient(ctx, &tor.DialConf{ProxyAuth: &proxy.Auth{"foo", "bar"}})
|
||||
byts := httpGet(ctx, client, "https://check.torproject.org/api/ip")
|
||||
ctx.Debugf("Read bytes: %v", string(byts))
|
||||
// Confirm just size 1
|
||||
ids := uniqueStreamCircuitIDs(ctx)
|
||||
ctx.Require.Len(ids, 1)
|
||||
// Now make call with another auth and just return circuit IDs
|
||||
client = httpClient(ctx, &tor.DialConf{ProxyAuth: &proxy.Auth{"baz", "qux"}})
|
||||
byts = httpGet(ctx, client, "https://check.torproject.org/api/ip")
|
||||
ctx.Debugf("Read bytes: %v", string(byts))
|
||||
return uniqueStreamCircuitIDs(ctx)
|
||||
}
|
||||
|
||||
// Return each stream circuit as a key of an empty-val map
|
||||
func uniqueStreamCircuitIDs(ctx *TestContext) map[int]struct{} {
|
||||
ret := map[int]struct{}{}
|
||||
vals, err := ctx.Control.GetInfo("stream-status")
|
||||
ctx.Require.NoError(err)
|
||||
for _, val := range vals {
|
||||
ctx.Require.Equal("stream-status", val.Key)
|
||||
for _, line := range strings.Split(val.Val, "\n") {
|
||||
pieces := strings.Split(strings.TrimSpace(line), " ")
|
||||
if len(pieces) < 3 {
|
||||
continue
|
||||
}
|
||||
i, err := strconv.Atoi(pieces[2])
|
||||
ctx.Require.NoError(err)
|
||||
ret[i] = struct{}{}
|
||||
}
|
||||
}
|
||||
return ret
|
||||
}
|
|
@ -50,7 +50,7 @@ func startHTTPServer(
|
|||
handlePattern string,
|
||||
handler func(http.ResponseWriter, *http.Request),
|
||||
) (*http.Client, *http.Server, *tor.OnionService) {
|
||||
httpClient := httpClient(ctx)
|
||||
httpClient := httpClient(ctx, nil)
|
||||
// Wait at most a few minutes for the entire test
|
||||
listenCtx, listenCancel := context.WithTimeout(context.Background(), 4*time.Minute)
|
||||
defer listenCancel()
|
||||
|
|
|
@ -25,8 +25,13 @@ type DialConf struct {
|
|||
// is empty and ProxyAddress is not empty, it defaults to "tcp".
|
||||
ProxyNetwork string
|
||||
|
||||
// ProxyAuth is the auth for the proxy. An empty auth means no auth, a nil
|
||||
// auth means it is looked up.
|
||||
// ProxyAuth is the auth for the proxy. Since Tor's SOCKS5 proxy is
|
||||
// unauthenticated, this is rarely needed. It can be used when
|
||||
// IsolateSOCKSAuth is set to ensure separate circuits.
|
||||
//
|
||||
// This should not be confused with downstream SOCKS proxy authentication
|
||||
// which is set via Tor values for Socks5ProxyUsername and
|
||||
// Socks5ProxyPassword when Socks5Proxy is set.
|
||||
ProxyAuth *proxy.Auth
|
||||
|
||||
// SkipEnableNetwork, if true, will skip the enable network step in Dialer.
|
||||
|
@ -72,23 +77,8 @@ func (t *Tor) Dialer(ctx context.Context, conf *DialConf) (*Dialer, error) {
|
|||
} else if proxyNetwork == "" {
|
||||
proxyNetwork = "tcp"
|
||||
}
|
||||
// Lookup proxy auth as needed
|
||||
proxyAuth := conf.ProxyAuth
|
||||
if proxyAuth == nil {
|
||||
info, err := t.Control.GetConf("Socks5ProxyUsername", "Socks5ProxyPassword")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(info) != 2 || info[0].Key != "Socks5ProxyUsername" || info[1].Key != "Socks5ProxyPassword" {
|
||||
return nil, fmt.Errorf("Unable to get proxy auth")
|
||||
}
|
||||
proxyAuth = &proxy.Auth{User: info[0].Val, Password: info[1].Val}
|
||||
}
|
||||
if proxyAuth.User == "" && proxyAuth.Password == "" {
|
||||
proxyAuth = nil
|
||||
}
|
||||
|
||||
dialer, err := proxy.SOCKS5(proxyNetwork, proxyAddress, proxyAuth, conf.Forward)
|
||||
dialer, err := proxy.SOCKS5(proxyNetwork, proxyAddress, conf.ProxyAuth, conf.Forward)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue