-
Notifications
You must be signed in to change notification settings - Fork 15
/
psiphon.go
90 lines (80 loc) · 2.18 KB
/
psiphon.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
package tunnel
import (
"context"
"fmt"
"net"
"net/url"
"path/filepath"
"time"
"github.com/ooni/probe-engine/pkg/feature/psiphonfeat"
)
// mockableStartPsiphon allows us to test for psiphon startup failures.
var mockableStartPsiphon = func(
ctx context.Context, config []byte, workdir string) (psiphonfeat.Tunnel, error) {
return psiphonfeat.Start(ctx, config, workdir)
}
// psiphonTunnel is a psiphon tunnel
type psiphonTunnel struct {
// bootstrapTime is the bootstrapTime of the bootstrap
bootstrapTime time.Duration
// tunnel is the underlying psiphon tunnel
tunnel psiphonfeat.Tunnel
}
// psiphonMakeWorkingDir creates the working directory
func psiphonMakeWorkingDir(config *Config) (string, error) {
workdir := filepath.Join(config.TunnelDir, config.Name)
if err := config.mkdirAll(workdir, 0700); err != nil {
return "", err
}
return workdir, nil
}
// psiphonStart starts the psiphon tunnel.
func psiphonStart(ctx context.Context, config *Config) (Tunnel, DebugInfo, error) {
debugInfo := DebugInfo{
LogFilePath: "",
Name: "psiphon",
Version: "",
}
select {
case <-ctx.Done():
return nil, debugInfo, ctx.Err() // simplifies unit testing this code
default:
}
if config.TunnelDir == "" {
return nil, debugInfo, ErrEmptyTunnelDir
}
configJSON, err := config.Session.FetchPsiphonConfig(ctx)
if err != nil {
return nil, debugInfo, err
}
workdir, err := psiphonMakeWorkingDir(config)
if err != nil {
return nil, debugInfo, err
}
start := time.Now()
tunnel, err := mockableStartPsiphon(ctx, configJSON, workdir)
if err != nil {
return nil, debugInfo, err
}
stop := time.Now()
return &psiphonTunnel{
tunnel: tunnel,
bootstrapTime: stop.Sub(start),
}, debugInfo, nil
}
// Stop is an idempotent method that shuts down the tunnel
func (t *psiphonTunnel) Stop() {
t.tunnel.Stop()
}
// SOCKS5ProxyURL returns the SOCKS5 proxy URL.
func (t *psiphonTunnel) SOCKS5ProxyURL() *url.URL {
return &url.URL{
Scheme: "socks5",
Host: net.JoinHostPort(
"127.0.0.1", fmt.Sprintf("%d", t.tunnel.GetSOCKSProxyPort())),
}
}
// BootstrapTime returns the bootstrap time
func (t *psiphonTunnel) BootstrapTime() time.Duration {
return t.bootstrapTime
}