ソースを参照

Make network as a separae interface

tags/v2.0.0-rc1
9seconds 5年前
コミット
24add0dce4
8個のファイルの変更89行の追加62行の削除
  1. 1
    1
      cli.go
  2. 4
    6
      cli_access.go
  3. 1
    1
      cli_generate_secret.go
  4. 2
    2
      config.go
  5. 9
    3
      example.config.toml
  6. 13
    2
      mtglib/network/init.go
  7. 54
    42
      mtglib/network/network.go
  8. 5
    5
      utils.go

+ 1
- 1
cli.go ファイルの表示

@@ -8,8 +8,8 @@ import (
8 8
 )
9 9
 
10 10
 type cli struct {
11
+	network network.Network
11 12
 	conf    *config
12
-	network *network.Network
13 13
 }
14 14
 
15 15
 func (c *cli) ReadConfig(path string) error {

+ 4
- 6
cli_access.go ファイルの表示

@@ -73,12 +73,10 @@ func (c *cliCommandAccess) Run(cli *CLI) error {
73 73
 }
74 74
 
75 75
 func (c *cliCommandAccess) getIP(protocol string) net.IP {
76
-	client := &http.Client{
77
-		Timeout: c.network.HTTP.Timeout,
78
-		Transport: &http.Transport{
79
-			DialContext: func(ctx context.Context, network, address string) (net.Conn, error) {
80
-				return c.network.DialContext(ctx, protocol, address)
81
-			},
76
+	client := c.network.MakeHTTPClient(0)
77
+	client.Transport = &http.Transport{
78
+		DialContext: func(ctx context.Context, network, address string) (net.Conn, error) {
79
+			return c.network.DialContext(ctx, protocol, address)
82 80
 		},
83 81
 	}
84 82
 

+ 1
- 1
cli_generate_secret.go ファイルの表示

@@ -7,7 +7,7 @@ import (
7 7
 )
8 8
 
9 9
 type cliCommandGenerateSecret struct {
10
-    cli
10
+	cli
11 11
 
12 12
 	HostName string `arg optional help:"Hostname to use for domain fronting. Default is '${domain_front}'." name:"hostname" default:"${domain_front}"` // nolint: lll, govet
13 13
 	Hex      bool   `help:"Print secret in hex encoding."`

+ 2
- 2
config.go ファイルの表示

@@ -412,7 +412,7 @@ type config struct {
412 412
 		} `json:"public-ip"`
413 413
 		Timeout struct {
414 414
 			TCP  configTypeDuration `json:"tcp"`
415
-			HTTP configTypeDuration `json:"http"`
415
+			Idle configTypeDuration `json:"idle"`
416 416
 		} `json:"timeout"`
417 417
 		DOHIP   configTypeIP    `json:"doh-ip"`
418 418
 		Proxies []configTypeURL `json:"proxies"`
@@ -478,7 +478,7 @@ type configRaw struct {
478 478
 		} `toml:"public-ip" json:"public-ip"`
479 479
 		Timeout struct {
480 480
 			TCP  string `toml:"tcp" json:"tcp"`
481
-			HTTP string `toml:"http" json:"http"`
481
+			Idle string `toml:"idle" json:"idle"`
482 482
 		} `toml:"timeout" json:"timeout"`
483 483
 		DOHIP   string   `toml:"doh-ip" json:"doh-ip"`
484 484
 		Proxies []string `toml:"proxies" json:"proxies"`

+ 9
- 3
example.config.toml ファイルの表示

@@ -101,11 +101,17 @@ proxies = [
101 101
 ipv4 = ""
102 102
 ipv6 = ""
103 103
 
104
-# network timeouts define different settings for timeouts. HTTP timeout
105
-# is required only for DOH.
104
+# network timeouts define different settings for timeouts. tcp timeout
105
+# define a global timeout on establishing of network connections. idle
106
+# means a timeout on pumping data between sockset when nothing is
107
+# happening.
108
+#
109
+# please be noticed that handshakes have no timeouts intentionally. You can
110
+# find a reasoning here:
111
+# https://www.ndss-symposium.org/wp-content/uploads/2020/02/23087-paper.pdf
106 112
 [network.timeout]
107 113
 tcp = "5s"
108
-http = "10s"
114
+idle = "1m"
109 115
 
110 116
 # FakeTLS can compare timestamps to prevent probes. Each message has
111 117
 # encrypted timestamp. So, mtg can compare this timestamp and decide if

+ 13
- 2
mtglib/network/init.go ファイルの表示

@@ -4,13 +4,14 @@ import (
4 4
 	"context"
5 5
 	"errors"
6 6
 	"net"
7
+	"net/http"
7 8
 	"time"
8 9
 )
9 10
 
10 11
 const (
11 12
 	DefaultTimeout     = 10 * time.Second
12
-	DefaultDNSTimeout  = time.Second
13
-	DefaultHTTPTimeout = DefaultTimeout
13
+	DefaultIdleTimeout = time.Minute
14
+	DefaultHTTPTimeout = 5 * time.Second
14 15
 	DefaultBufferSize  = 4096
15 16
 
16 17
 	ProxyDialerOpenThreshold        = 5
@@ -18,6 +19,8 @@ const (
18 19
 	ProxyDialerResetFailuresTimeout = 10 * time.Second
19 20
 
20 21
 	DefaultDOHHostname = "9.9.9.9"
22
+
23
+	DNSTimeout = 5 * time.Second
21 24
 )
22 25
 
23 26
 var (
@@ -29,3 +32,11 @@ type Dialer interface {
29 32
 	Dial(network, address string) (net.Conn, error)
30 33
 	DialContext(ctx context.Context, network, address string) (net.Conn, error)
31 34
 }
35
+
36
+type Network interface {
37
+	Dialer
38
+
39
+	DNSResolve(network, hostname string) (ips []string, err error)
40
+	MakeHTTPClient(timeout time.Duration) *http.Client
41
+	IdleTimeout() time.Duration
42
+}

+ 54
- 42
mtglib/network/network.go ファイルの表示

@@ -12,21 +12,20 @@ import (
12 12
 	doh "github.com/babolivier/go-doh-client"
13 13
 )
14 14
 
15
-type Network struct {
16
-	HTTP http.Client
17
-	DNS  doh.Resolver
18
-
19
-	dialer Dialer
15
+type network struct {
16
+	idleTimeout time.Duration
17
+	dialer      Dialer
18
+	dns         doh.Resolver
20 19
 }
21 20
 
22
-func (d *Network) Dial(network, address string) (net.Conn, error) {
23
-	return d.DialContext(context.Background(), network, address)
21
+func (n *network) Dial(protocol, address string) (net.Conn, error) {
22
+	return n.DialContext(context.Background(), protocol, address)
24 23
 }
25 24
 
26
-func (d *Network) DialContext(ctx context.Context, network, address string) (net.Conn, error) {
25
+func (n *network) DialContext(ctx context.Context, protocol, address string) (net.Conn, error) {
27 26
 	host, port, _ := net.SplitHostPort(address)
28 27
 
29
-	ips, err := d.resolveIPs(network, host)
28
+	ips, err := n.DNSResolve(protocol, host)
30 29
 	if err != nil {
31 30
 		return nil, fmt.Errorf("cannot resolve dns names: %w", err)
32 31
 	}
@@ -37,16 +36,20 @@ func (d *Network) DialContext(ctx context.Context, network, address string) (net
37 36
 		})
38 37
 	}
39 38
 
39
+	var conn net.Conn
40
+
40 41
 	for _, v := range ips {
41
-		if conn, err := d.dialer.DialContext(ctx, network, net.JoinHostPort(v, port)); err == nil {
42
+		conn, err = n.dialer.DialContext(ctx, protocol, net.JoinHostPort(v, port))
43
+
44
+		if err == nil {
42 45
 			return conn, nil
43 46
 		}
44 47
 	}
45 48
 
46
-	return nil, fmt.Errorf("cannot dial to %s:%s", network, address)
49
+	return nil, fmt.Errorf("cannot dial to %s:%s: %w", protocol, address, err)
47 50
 }
48 51
 
49
-func (d *Network) resolveIPs(network, address string) ([]string, error) {
52
+func (n *network) DNSResolve(protocol, address string) ([]string, error) {
50 53
 	if net.ParseIP(address) != nil {
51 54
 		return []string{address}, nil
52 55
 	}
@@ -55,14 +58,14 @@ func (d *Network) resolveIPs(network, address string) ([]string, error) {
55 58
 	wg := &sync.WaitGroup{}
56 59
 	mutex := &sync.Mutex{}
57 60
 
58
-	switch network {
61
+	switch protocol {
59 62
 	case "tcp", "tcp4":
60 63
 		wg.Add(1)
61 64
 
62 65
 		go func() {
63 66
 			defer wg.Done()
64 67
 
65
-			if recs, _, err := d.DNS.LookupA(address); err == nil {
68
+			if recs, _, err := n.dns.LookupA(address); err == nil {
66 69
 				mutex.Lock()
67 70
 				defer mutex.Unlock()
68 71
 
@@ -73,14 +76,14 @@ func (d *Network) resolveIPs(network, address string) ([]string, error) {
73 76
 		}()
74 77
 	}
75 78
 
76
-	switch network {
79
+	switch protocol {
77 80
 	case "tcp", "tcp6":
78 81
 		wg.Add(1)
79 82
 
80 83
 		go func() {
81 84
 			defer wg.Done()
82 85
 
83
-			if recs, _, err := d.DNS.LookupAAAA(address); err == nil {
86
+			if recs, _, err := n.dns.LookupAAAA(address); err == nil {
84 87
 				mutex.Lock()
85 88
 				defer mutex.Unlock()
86 89
 
@@ -94,44 +97,53 @@ func (d *Network) resolveIPs(network, address string) ([]string, error) {
94 97
 	wg.Wait()
95 98
 
96 99
 	if len(ips) == 0 {
97
-		return nil, fmt.Errorf("cannot find any ips for %s:%s", network, address)
100
+		return nil, fmt.Errorf("cannot find any ips for %s:%s", protocol, address)
98 101
 	}
99 102
 
100 103
 	return ips, nil
101 104
 }
102 105
 
103
-func NewNetwork(dialer Dialer, dohHostname string, httpTimeout time.Duration) (*Network, error) {
104
-	switch {
105
-	case httpTimeout < 0:
106
-		return nil, fmt.Errorf("timeout should be positive number %v", httpTimeout)
107
-	case httpTimeout == 0:
108
-		httpTimeout = DefaultHTTPTimeout
109
-	}
106
+func (n *network) IdleTimeout() time.Duration {
107
+	return n.idleTimeout
108
+}
110 109
 
111
-	if net.ParseIP(dohHostname) == nil {
112
-		return nil, fmt.Errorf("hostname %s should be IP address", dohHostname)
110
+func (n *network) MakeHTTPClient(timeout time.Duration) *http.Client {
111
+	if timeout <= 0 {
112
+		timeout = DefaultHTTPTimeout
113 113
 	}
114 114
 
115
-	dohHTTPClient := &http.Client{
116
-		Timeout: DefaultDNSTimeout,
115
+	return &http.Client{
116
+		Timeout: timeout,
117 117
 		Transport: &http.Transport{
118
-			DialContext: dialer.DialContext,
118
+			DialContext: n.DialContext,
119 119
 		},
120 120
 	}
121
-	network := &Network{
122
-		dialer: dialer,
123
-		DNS: doh.Resolver{
124
-			Host:       dohHostname,
125
-			Class:      doh.IN,
126
-			HTTPClient: dohHTTPClient,
127
-		},
121
+}
122
+
123
+func NewNetwork(dialer Dialer, dohHostname string, idleTimeout time.Duration) (Network, error) {
124
+	switch {
125
+	case idleTimeout < 0:
126
+		return nil, fmt.Errorf("timeout should be positive number %s", idleTimeout)
127
+	case idleTimeout == 0:
128
+		idleTimeout = DefaultIdleTimeout
128 129
 	}
129
-	network.HTTP = http.Client{
130
-		Timeout: httpTimeout,
131
-		Transport: &http.Transport{
132
-			DialContext: network.DialContext,
133
-		},
130
+
131
+	if net.ParseIP(dohHostname) == nil {
132
+		return nil, fmt.Errorf("hostname %s should be IP address", dohHostname)
134 133
 	}
135 134
 
136
-	return network, nil
135
+	return &network{
136
+		dialer:      dialer,
137
+		idleTimeout: idleTimeout,
138
+		dns: doh.Resolver{
139
+			Host:  dohHostname,
140
+			Class: doh.IN,
141
+			HTTPClient: &http.Client{
142
+				Timeout: DNSTimeout,
143
+				Transport: &http.Transport{
144
+					DialContext: dialer.DialContext,
145
+				},
146
+			},
147
+		},
148
+	}, nil
137 149
 }

+ 5
- 5
utils.go ファイルの表示

@@ -11,9 +11,9 @@ import (
11 11
 	"github.com/9seconds/mtg/v2/mtglib/network"
12 12
 )
13 13
 
14
-func makeNetwork(conf *config) (*network.Network, error) {
14
+func makeNetwork(conf *config) (network.Network, error) {
15 15
 	tcpTimeout := conf.Network.Timeout.TCP.Value(network.DefaultTimeout)
16
-	httpTimeout := conf.Network.Timeout.TCP.Value(network.DefaultHTTPTimeout)
16
+	idleTimeout := conf.Network.Timeout.Idle.Value(network.DefaultIdleTimeout)
17 17
 	dohIP := conf.Network.DOHIP.Value(net.ParseIP(network.DefaultDOHHostname)).String()
18 18
 	bufferSize := conf.TCPBuffer.Value(network.DefaultBufferSize)
19 19
 
@@ -32,14 +32,14 @@ func makeNetwork(conf *config) (*network.Network, error) {
32 32
 
33 33
 	switch len(proxyURLs) {
34 34
 	case 0:
35
-		return network.NewNetwork(baseDialer, dohIP, httpTimeout)
35
+		return network.NewNetwork(baseDialer, dohIP, idleTimeout)
36 36
 	case 1:
37 37
 		socksDialer, err := network.NewSocks5Dialer(baseDialer, proxyURLs[0])
38 38
 		if err != nil {
39 39
 			return nil, fmt.Errorf("cannot build socks5 dialer: %w", err)
40 40
 		}
41 41
 
42
-		return network.NewNetwork(socksDialer, dohIP, httpTimeout)
42
+		return network.NewNetwork(socksDialer, dohIP, idleTimeout)
43 43
 	}
44 44
 
45 45
 	socksDialer, err := network.NewLoadBalancedSocks5Dialer(baseDialer, proxyURLs)
@@ -47,7 +47,7 @@ func makeNetwork(conf *config) (*network.Network, error) {
47 47
 		return nil, fmt.Errorf("cannot build socks5 dialer: %w", err)
48 48
 	}
49 49
 
50
-	return network.NewNetwork(socksDialer, dohIP, httpTimeout)
50
+	return network.NewNetwork(socksDialer, dohIP, idleTimeout)
51 51
 }
52 52
 
53 53
 func exhaustResponse(response *http.Response) {

読み込み中…
キャンセル
保存