From d6566e5dfbaf4ec7ccf5fdda22d8bb641bcc19db Mon Sep 17 00:00:00 2001 From: 9seconds Date: Thu, 11 Mar 2021 06:08:15 +0300 Subject: [PATCH] Change network to accept DialFunc --- cli/access.go | 24 +++++---------- cli/base.go | 13 ++++---- cli/cli.go | 4 +-- cli/generate_secret.go | 2 +- config/type_bytes.go | 2 +- config/type_duration.go | 2 +- config/type_float.go | 2 +- config/type_hostport.go | 6 ++-- config/type_http_path.go | 4 +-- config/type_ip.go | 2 +- config/type_metric_prefix.go | 2 +- config/type_port.go | 4 +-- config/type_prefer_ip.go | 2 +- config/type_url.go | 2 +- main.go | 2 +- mtglib/network/init.go | 9 +++--- mtglib/network/network.go | 45 +++++++++++++++++++--------- utils.go | 57 ------------------------------------ 18 files changed, 67 insertions(+), 117 deletions(-) delete mode 100644 utils.go diff --git a/cli/access.go b/cli/access.go index b8fdc97..4e13f89 100644 --- a/cli/access.go +++ b/cli/access.go @@ -38,8 +38,8 @@ type Access struct { Hex bool `help:"Print secret in hex encoding."` } -func (c *Access) Run(cli *CLI) error { - if err := c.ReadConfig(cli.Access.ConfigPath); err != nil { +func (c *Access) Run(cli *CLI, version string) error { + if err := c.ReadConfig(cli.Access.ConfigPath, version); err != nil { return fmt.Errorf("cannot init config: %w", err) } @@ -74,21 +74,11 @@ func (c *Access) Run(cli *CLI) error { } func (c *Access) getIP(protocol string) net.IP { - client := c.network.MakeHTTPClient(0) - client.Transport = &http.Transport{ - DialContext: func(ctx context.Context, network, address string) (net.Conn, error) { - return c.network.DialContext(ctx, protocol, address) - }, - } + client := c.network.MakeHTTPClient(func(ctx context.Context, network, address string) (net.Conn, error) { + return c.network.DialContext(ctx, protocol, address) + }) - c.network.PrepareHTTPClient(client) - - req, err := http.NewRequest(http.MethodGet, "https://ifconfig.co", nil) - if err != nil { - panic(err) - } - - resp, err := client.Do(req) + resp, err := client.Get("https://ifconfig.co") // nolint: noctx if err != nil { return nil } @@ -98,7 +88,7 @@ func (c *Access) getIP(protocol string) net.IP { } defer func() { - io.Copy(ioutil.Discard, resp.Body) + io.Copy(ioutil.Discard, resp.Body) // nolint: errcheck resp.Body.Close() }() diff --git a/cli/base.go b/cli/base.go index 7736592..3f508b1 100644 --- a/cli/base.go +++ b/cli/base.go @@ -15,7 +15,7 @@ type base struct { conf *config.Config } -func (b *base) ReadConfig(path string) error { +func (b *base) ReadConfig(path, version string) error { content, err := ioutil.ReadFile(path) if err != nil { return fmt.Errorf("cannot read config file: %w", err) @@ -26,7 +26,7 @@ func (b *base) ReadConfig(path string) error { return fmt.Errorf("cannot parse config: %w", err) } - ntw, err := b.makeNetwork(conf) + ntw, err := b.makeNetwork(conf, version) if err != nil { return fmt.Errorf("cannot build a network: %w", err) } @@ -37,11 +37,12 @@ func (b *base) ReadConfig(path string) error { return nil } -func (b *base) makeNetwork(conf *config.Config) (network.Network, error) { +func (b *base) makeNetwork(conf *config.Config, version string) (network.Network, error) { tcpTimeout := conf.Network.Timeout.TCP.Value(network.DefaultTimeout) idleTimeout := conf.Network.Timeout.Idle.Value(network.DefaultIdleTimeout) dohIP := conf.Network.DOHIP.Value(net.ParseIP(network.DefaultDOHHostname)).String() bufferSize := conf.TCPBuffer.Value(network.DefaultBufferSize) + userAgent := "mtg/" + version baseDialer, err := network.NewDefaultDialer(tcpTimeout, int(bufferSize)) if err != nil { @@ -58,14 +59,14 @@ func (b *base) makeNetwork(conf *config.Config) (network.Network, error) { switch len(proxyURLs) { case 0: - return network.NewNetwork(baseDialer, dohIP, idleTimeout) + return network.NewNetwork(baseDialer, userAgent, dohIP, idleTimeout) case 1: socksDialer, err := network.NewSocks5Dialer(baseDialer, proxyURLs[0]) if err != nil { return nil, fmt.Errorf("cannot build socks5 dialer: %w", err) } - return network.NewNetwork(socksDialer, dohIP, idleTimeout) + return network.NewNetwork(socksDialer, userAgent, dohIP, idleTimeout) } socksDialer, err := network.NewLoadBalancedSocks5Dialer(baseDialer, proxyURLs) @@ -73,5 +74,5 @@ func (b *base) makeNetwork(conf *config.Config) (network.Network, error) { return nil, fmt.Errorf("cannot build socks5 dialer: %w", err) } - return network.NewNetwork(socksDialer, dohIP, idleTimeout) + return network.NewNetwork(socksDialer, userAgent, dohIP, idleTimeout) } diff --git a/cli/cli.go b/cli/cli.go index 9f27d72..9892043 100644 --- a/cli/cli.go +++ b/cli/cli.go @@ -1,8 +1,6 @@ package cli -import ( - "github.com/alecthomas/kong" -) +import "github.com/alecthomas/kong" type CLI struct { GenerateSecret GenerateSecret `cmd help:"Generate new proxy secret"` // nolint: govet diff --git a/cli/generate_secret.go b/cli/generate_secret.go index a92e9cc..f0f8f69 100644 --- a/cli/generate_secret.go +++ b/cli/generate_secret.go @@ -13,7 +13,7 @@ type GenerateSecret struct { Hex bool `help:"Print secret in hex encoding."` } -func (c *GenerateSecret) Run(cli *CLI) error { // nolint: unparam +func (c *GenerateSecret) Run(cli *CLI, _ string) error { secret := mtglib.GenerateSecret(cli.GenerateSecret.HostName) if cli.GenerateSecret.Hex { diff --git a/config/type_bytes.go b/config/type_bytes.go index 585ee86..49d0b06 100644 --- a/config/type_bytes.go +++ b/config/type_bytes.go @@ -30,7 +30,7 @@ func (c *TypeBytes) UnmarshalText(data []byte) error { return nil } -func (c TypeBytes) MarshalText() ([]byte, error) { // nolint: unparam +func (c TypeBytes) MarshalText() ([]byte, error) { return []byte(c.String()), nil } diff --git a/config/type_duration.go b/config/type_duration.go index f5dbbab..8971a25 100644 --- a/config/type_duration.go +++ b/config/type_duration.go @@ -29,7 +29,7 @@ func (c *TypeDuration) UnmarshalText(data []byte) error { return nil } -func (c TypeDuration) MarshalText() ([]byte, error) { // nolint: unparam +func (c TypeDuration) MarshalText() ([]byte, error) { return []byte(c.value.String()), nil } diff --git a/config/type_float.go b/config/type_float.go index bf5aff6..f30ccb4 100644 --- a/config/type_float.go +++ b/config/type_float.go @@ -24,7 +24,7 @@ func (c *TypeFloat) UnmarshalJSON(data []byte) error { return nil } -func (c *TypeFloat) MarshalText() ([]byte, error) { // nolint: unparam +func (c *TypeFloat) MarshalText() ([]byte, error) { return []byte(c.String()), nil } diff --git a/config/type_hostport.go b/config/type_hostport.go index 42a9fc7..e86149d 100644 --- a/config/type_hostport.go +++ b/config/type_hostport.go @@ -32,7 +32,7 @@ func (c *TypeHostPort) UnmarshalText(data []byte) error { return nil } -func (c TypeHostPort) MarshalText() ([]byte, error) { // nolint: unparam +func (c TypeHostPort) MarshalText() ([]byte, error) { return []byte(c.String()), nil } @@ -41,11 +41,11 @@ func (c TypeHostPort) String() string { } func (c TypeHostPort) HostValue(defaultValue net.IP) net.IP { - return c.host.Value(defaultValue) + return c.host.Value(defaultValue) } func (c TypeHostPort) PortValue(defaultValue uint) uint { - return c.port.Value(defaultValue) + return c.port.Value(defaultValue) } func (c TypeHostPort) Value(defaultHostValue net.IP, defaultPortValue uint) string { diff --git a/config/type_http_path.go b/config/type_http_path.go index 79d311a..fea406f 100644 --- a/config/type_http_path.go +++ b/config/type_http_path.go @@ -6,7 +6,7 @@ type TypeHTTPPath struct { value string } -func (c *TypeHTTPPath) UnmarshalText(data []byte) error { // nolint: unparam +func (c *TypeHTTPPath) UnmarshalText(data []byte) error { if len(data) > 0 { c.value = "/" + strings.Trim(string(data), "/") } @@ -14,7 +14,7 @@ func (c *TypeHTTPPath) UnmarshalText(data []byte) error { // nolint: unparam return nil } -func (c TypeHTTPPath) MarshalText() ([]byte, error) { // nolint: unparam +func (c TypeHTTPPath) MarshalText() ([]byte, error) { return []byte(c.String()), nil } diff --git a/config/type_ip.go b/config/type_ip.go index e249a94..76d61b0 100644 --- a/config/type_ip.go +++ b/config/type_ip.go @@ -24,7 +24,7 @@ func (c *TypeIP) UnmarshalText(data []byte) error { return nil } -func (c *TypeIP) MarshalText() ([]byte, error) { // nolint: unparam +func (c *TypeIP) MarshalText() ([]byte, error) { return []byte(c.String()), nil } diff --git a/config/type_metric_prefix.go b/config/type_metric_prefix.go index adc1029..947099e 100644 --- a/config/type_metric_prefix.go +++ b/config/type_metric_prefix.go @@ -25,7 +25,7 @@ func (c *TypeMetricPrefix) UnmarshalText(data []byte) error { return nil } -func (c TypeMetricPrefix) MarshalText() ([]byte, error) { // nolint: unparam +func (c TypeMetricPrefix) MarshalText() ([]byte, error) { return []byte(c.String()), nil } diff --git a/config/type_port.go b/config/type_port.go index 41963e5..3c5ec15 100644 --- a/config/type_port.go +++ b/config/type_port.go @@ -28,8 +28,8 @@ func (c *TypePort) UnmarshalJSON(data []byte) error { return nil } -func (c *TypePort) MarshalJSON() ([]byte, error) { // nolint: unparam - return []byte(c.String()), nil +func (c *TypePort) MarshalJSON() ([]byte, error) { + return []byte(c.String()), nil } func (c TypePort) String() string { diff --git a/config/type_prefer_ip.go b/config/type_prefer_ip.go index fc5e034..b0763db 100644 --- a/config/type_prefer_ip.go +++ b/config/type_prefer_ip.go @@ -26,7 +26,7 @@ func (c *TypePreferIP) UnmarshalText(data []byte) error { return nil } -func (c TypePreferIP) MarshalText() ([]byte, error) { // nolint: unparam +func (c TypePreferIP) MarshalText() ([]byte, error) { return []byte(c.value), nil } diff --git a/config/type_url.go b/config/type_url.go index 38378e2..6452b2c 100644 --- a/config/type_url.go +++ b/config/type_url.go @@ -24,7 +24,7 @@ func (c *TypeURL) UnmarshalText(data []byte) error { return nil } -func (c *TypeURL) MarshalText() ([]byte, error) { // nolint: unparam +func (c *TypeURL) MarshalText() ([]byte, error) { return []byte(c.String()), nil } diff --git a/main.go b/main.go index 622ed5c..fc51371 100644 --- a/main.go +++ b/main.go @@ -19,5 +19,5 @@ func main() { "version": version, }) - ctx.FatalIfErrorf(ctx.Run(cli)) + ctx.FatalIfErrorf(ctx.Run(cli, version)) } diff --git a/mtglib/network/init.go b/mtglib/network/init.go index 9be2dcc..e66ce3b 100644 --- a/mtglib/network/init.go +++ b/mtglib/network/init.go @@ -11,7 +11,6 @@ import ( const ( DefaultTimeout = 10 * time.Second DefaultIdleTimeout = time.Minute - DefaultHTTPTimeout = 5 * time.Second DefaultBufferSize = 4096 ProxyDialerOpenThreshold = 5 @@ -20,7 +19,8 @@ const ( DefaultDOHHostname = "9.9.9.9" - DNSTimeout = 5 * time.Second + DNSTimeout = 5 * time.Second + HTTPTimeout = 10 * time.Second ) var ( @@ -28,6 +28,8 @@ var ( ErrCannotDialWithAllProxies = errors.New("cannot dial with all proxies") ) +type DialFunc func(ctx context.Context, protocol, address string) (net.Conn, error) + type Dialer interface { Dial(network, address string) (net.Conn, error) DialContext(ctx context.Context, network, address string) (net.Conn, error) @@ -37,7 +39,6 @@ type Network interface { Dialer DNSResolve(network, hostname string) (ips []string, err error) - MakeHTTPClient(timeout time.Duration) *http.Client + MakeHTTPClient(DialFunc) *http.Client IdleTimeout() time.Duration - PrepareHTTPClient(*http.Client) } diff --git a/mtglib/network/network.go b/mtglib/network/network.go index d256dd0..853511b 100644 --- a/mtglib/network/network.go +++ b/mtglib/network/network.go @@ -12,10 +12,22 @@ import ( doh "github.com/babolivier/go-doh-client" ) +type networkHTTPTransport struct { + userAgent string + next http.RoundTripper +} + +func (n networkHTTPTransport) RoundTrip(req *http.Request) (*http.Response, error) { + req.Header.Set("User-Agent", n.userAgent) + + return n.next.RoundTrip(req) +} + type network struct { - idleTimeout time.Duration dialer Dialer dns doh.Resolver + idleTimeout time.Duration + userAgent string } func (n *network) Dial(protocol, address string) (net.Conn, error) { @@ -107,23 +119,15 @@ func (n *network) IdleTimeout() time.Duration { return n.idleTimeout } -func (n *network) MakeHTTPClient(timeout time.Duration) *http.Client { - if timeout <= 0 { - timeout = DefaultHTTPTimeout +func (n *network) MakeHTTPClient(dialFunc DialFunc) *http.Client { + if dialFunc == nil { + dialFunc = n.DialContext } - return &http.Client{ - Timeout: timeout, - Transport: &http.Transport{ - DialContext: n.DialContext, - }, - } + return makeHTTPClient(n.userAgent, dialFunc) } -func (n *network) PatchHTTPClient(_ *http.Client) { -} - -func NewNetwork(dialer Dialer, dohHostname string, idleTimeout time.Duration) (Network, error) { +func NewNetwork(dialer Dialer, userAgent, dohHostname string, idleTimeout time.Duration) (Network, error) { switch { case idleTimeout < 0: return nil, fmt.Errorf("timeout should be positive number %s", idleTimeout) @@ -138,6 +142,7 @@ func NewNetwork(dialer Dialer, dohHostname string, idleTimeout time.Duration) (N return &network{ dialer: dialer, idleTimeout: idleTimeout, + userAgent: userAgent, dns: doh.Resolver{ Host: dohHostname, Class: doh.IN, @@ -150,3 +155,15 @@ func NewNetwork(dialer Dialer, dohHostname string, idleTimeout time.Duration) (N }, }, nil } + +func makeHTTPClient(userAgent string, dialFunc DialFunc) *http.Client { + return &http.Client{ + Timeout: HTTPTimeout, + Transport: networkHTTPTransport{ + userAgent: userAgent, + next: &http.Transport{ + DialContext: dialFunc, + }, + }, + } +} diff --git a/utils.go b/utils.go deleted file mode 100644 index 84b008d..0000000 --- a/utils.go +++ /dev/null @@ -1,57 +0,0 @@ -package main - -import ( - "fmt" - "io" - "io/ioutil" - "net" - "net/http" - "net/url" - - "github.com/9seconds/mtg/v2/config" - "github.com/9seconds/mtg/v2/mtglib/network" -) - -func makeNetwork(conf *config.Config) (network.Network, error) { - tcpTimeout := conf.Network.Timeout.TCP.Value(network.DefaultTimeout) - idleTimeout := conf.Network.Timeout.Idle.Value(network.DefaultIdleTimeout) - dohIP := conf.Network.DOHIP.Value(net.ParseIP(network.DefaultDOHHostname)).String() - bufferSize := conf.TCPBuffer.Value(network.DefaultBufferSize) - - baseDialer, err := network.NewDefaultDialer(tcpTimeout, int(bufferSize)) - if err != nil { - return nil, fmt.Errorf("cannot build a default dialer: %w", err) - } - - proxyURLs := make([]*url.URL, 0, len(conf.Network.Proxies)) - - for _, v := range conf.Network.Proxies { - if value := v.Value(nil); value != nil { - proxyURLs = append(proxyURLs, v.Value(nil)) - } - } - - switch len(proxyURLs) { - case 0: - return network.NewNetwork(baseDialer, dohIP, idleTimeout) - case 1: - socksDialer, err := network.NewSocks5Dialer(baseDialer, proxyURLs[0]) - if err != nil { - return nil, fmt.Errorf("cannot build socks5 dialer: %w", err) - } - - return network.NewNetwork(socksDialer, dohIP, idleTimeout) - } - - socksDialer, err := network.NewLoadBalancedSocks5Dialer(baseDialer, proxyURLs) - if err != nil { - return nil, fmt.Errorf("cannot build socks5 dialer: %w", err) - } - - return network.NewNetwork(socksDialer, dohIP, idleTimeout) -} - -func exhaustResponse(response *http.Response) { - io.Copy(ioutil.Discard, response.Body) // nolint: errcheck - response.Body.Close() -}