├── vendor └── github.com │ ├── c-pro │ └── go-socks5 │ │ ├── .travis.yml │ │ ├── .gitignore │ │ ├── credentials.go │ │ ├── resolver.go │ │ ├── LICENSE │ │ ├── ruleset.go │ │ ├── README.md │ │ ├── auth.go │ │ ├── socks5.go │ │ └── request.go │ └── kelseyhightower │ └── envconfig │ ├── .travis.yml │ ├── env_os.go │ ├── env_syscall.go │ ├── MAINTAINERS │ ├── doc.go │ ├── LICENSE │ ├── usage.go │ ├── README.md │ └── envconfig.go ├── Dockerfile ├── Gopkg.lock ├── Gopkg.toml ├── README.md ├── LICENSE ├── s5.go └── .gitignore /vendor/github.com/c-pro/go-socks5/.travis.yml: -------------------------------------------------------------------------------- 1 | language: go 2 | go: 3 | - 1.7 4 | - tip 5 | -------------------------------------------------------------------------------- /vendor/github.com/kelseyhightower/envconfig/.travis.yml: -------------------------------------------------------------------------------- 1 | language: go 2 | 3 | go: 4 | - 1.4 5 | - 1.5 6 | - 1.6 7 | - tip 8 | -------------------------------------------------------------------------------- /vendor/github.com/kelseyhightower/envconfig/env_os.go: -------------------------------------------------------------------------------- 1 | // +build appengine 2 | 3 | package envconfig 4 | 5 | import "os" 6 | 7 | var lookupEnv = os.LookupEnv 8 | -------------------------------------------------------------------------------- /vendor/github.com/kelseyhightower/envconfig/env_syscall.go: -------------------------------------------------------------------------------- 1 | // +build !appengine 2 | 3 | package envconfig 4 | 5 | import "syscall" 6 | 7 | var lookupEnv = syscall.Getenv 8 | -------------------------------------------------------------------------------- /vendor/github.com/kelseyhightower/envconfig/MAINTAINERS: -------------------------------------------------------------------------------- 1 | Kelsey Hightower kelsey.hightower@gmail.com github.com/kelseyhightower 2 | Travis Parker travis.parker@gmail.com github.com/teepark 3 | -------------------------------------------------------------------------------- /vendor/github.com/c-pro/go-socks5/.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled Object files, Static and Dynamic libs (Shared Objects) 2 | *.o 3 | *.a 4 | *.so 5 | 6 | # Folders 7 | _obj 8 | _test 9 | 10 | # Architecture specific extensions/prefixes 11 | *.[568vq] 12 | [568vq].out 13 | 14 | *.cgo1.go 15 | *.cgo2.c 16 | _cgo_defun.c 17 | _cgo_gotypes.go 18 | _cgo_export.* 19 | 20 | _testmain.go 21 | 22 | *.exe 23 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM golang as builder 2 | RUN mkdir -p /go/src/github.com/Egregors/socks5-server 3 | WORKDIR /go/src/github.com/Egregors/socks5-server 4 | COPY . . 5 | 6 | RUN CGO_ENABLED=0 GOOS=linux go build -ldflags "-s" -a -installsuffix cgo -o s5 7 | 8 | FROM scratch 9 | COPY --from=builder /go/src/github.com/Egregors/socks5-server/s5 ./ 10 | 11 | ENV HOST=0.0.0.0 12 | ENV PORT=1111 13 | EXPOSE 1111 14 | 15 | CMD ["./s5"] 16 | -------------------------------------------------------------------------------- /vendor/github.com/kelseyhightower/envconfig/doc.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2013 Kelsey Hightower. All rights reserved. 2 | // Use of this source code is governed by the MIT License that can be found in 3 | // the LICENSE file. 4 | 5 | // Package envconfig implements decoding of environment variables based on a user 6 | // defined specification. A typical use is using environment variables for 7 | // configuration settings. 8 | package envconfig 9 | -------------------------------------------------------------------------------- /vendor/github.com/c-pro/go-socks5/credentials.go: -------------------------------------------------------------------------------- 1 | package socks5 2 | 3 | // CredentialStore is used to support user/pass authentication 4 | type CredentialStore interface { 5 | Valid(user, password string) bool 6 | } 7 | 8 | // StaticCredentials enables using a map directly as a credential store 9 | type StaticCredentials map[string]string 10 | 11 | func (s StaticCredentials) Valid(user, password string) bool { 12 | pass, ok := s[user] 13 | if !ok { 14 | return false 15 | } 16 | return password == pass 17 | } 18 | -------------------------------------------------------------------------------- /vendor/github.com/c-pro/go-socks5/resolver.go: -------------------------------------------------------------------------------- 1 | package socks5 2 | 3 | import ( 4 | "context" 5 | "net" 6 | ) 7 | 8 | // NameResolver is used to implement custom name resolution 9 | type NameResolver interface { 10 | Resolve(ctx context.Context, name string) (context.Context, net.IP, error) 11 | } 12 | 13 | // DNSResolver uses the system DNS to resolve host names 14 | type DNSResolver struct{} 15 | 16 | func (d DNSResolver) Resolve(ctx context.Context, name string) (context.Context, net.IP, error) { 17 | addr, err := net.ResolveIPAddr("ip", name) 18 | if err != nil { 19 | return ctx, nil, err 20 | } 21 | return ctx, addr.IP, err 22 | } 23 | -------------------------------------------------------------------------------- /Gopkg.lock: -------------------------------------------------------------------------------- 1 | # This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'. 2 | 3 | 4 | [[projects]] 5 | branch = "master" 6 | name = "github.com/c-pro/go-socks5" 7 | packages = ["."] 8 | revision = "cb19d3d0e00b7495cedefae7afd4385033065b8e" 9 | 10 | [[projects]] 11 | name = "github.com/kelseyhightower/envconfig" 12 | packages = ["."] 13 | revision = "f611eb38b3875cc3bd991ca91c51d06446afa14c" 14 | version = "v1.3.0" 15 | 16 | [solve-meta] 17 | analyzer-name = "dep" 18 | analyzer-version = 1 19 | inputs-digest = "3ca3a8171f5facf453215e856c2a49b1a95582998c26691ef22d5d14dc9ca8de" 20 | solver-name = "gps-cdcl" 21 | solver-version = 1 22 | -------------------------------------------------------------------------------- /Gopkg.toml: -------------------------------------------------------------------------------- 1 | # Gopkg.toml example 2 | # 3 | # Refer to https://github.com/golang/dep/blob/master/docs/Gopkg.toml.md 4 | # for detailed Gopkg.toml documentation. 5 | # 6 | # required = ["github.com/user/thing/cmd/thing"] 7 | # ignored = ["github.com/user/project/pkgX", "bitbucket.org/user/project/pkgA/pkgY"] 8 | # 9 | # [[constraint]] 10 | # name = "github.com/user/project" 11 | # version = "1.0.0" 12 | # 13 | # [[constraint]] 14 | # name = "github.com/user/project2" 15 | # branch = "dev" 16 | # source = "github.com/myfork/project2" 17 | # 18 | # [[override]] 19 | # name = "github.com/x/y" 20 | # version = "2.4.0" 21 | # 22 | # [prune] 23 | # non-go = false 24 | # go-tests = true 25 | # unused-packages = true 26 | 27 | 28 | [prune] 29 | go-tests = true 30 | unused-packages = true 31 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # socks5-server 2 | Simple socks5 server 3 | 4 | ![build status](https://img.shields.io/docker/build/egregors/socks5-server.svg) 5 | [![Go Report Card](https://goreportcard.com/badge/github.com/Egregors/socks5-server)](https://goreportcard.com/report/github.com/Egregors/socks5-server) 6 | 7 | 8 | # Usage 9 | 10 | ``` 11 | docker run --name s5 -d --restart=always -p 1111:1111 -e "USERS=user1:pass1,user2:pass2" egregors/socks5-server 12 | ``` 13 | 14 | Do not forget to replace usernames and passwords with your (secure) values! 15 | 16 | Now you may try to connect to 1111 port of your host. 17 | 18 | ## Build 19 | ``` 20 | go build -o s5 . 21 | USERS="user1:pass1" ./s5 22 | ``` 23 | 24 | # Contributing 25 | Bug reports, bug fixes and new features are always welcome. 26 | Please open issues and submit pull requests for any new code. 27 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Vadim Iskuchekov 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /vendor/github.com/kelseyhightower/envconfig/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2013 Kelsey Hightower 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of 4 | this software and associated documentation files (the "Software"), to deal in 5 | the Software without restriction, including without limitation the rights to 6 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 7 | of the Software, and to permit persons to whom the Software is furnished to do 8 | so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | SOFTWARE. 20 | -------------------------------------------------------------------------------- /vendor/github.com/c-pro/go-socks5/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 Armon Dadgar 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software is furnished to do so, 10 | subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /vendor/github.com/c-pro/go-socks5/ruleset.go: -------------------------------------------------------------------------------- 1 | package socks5 2 | 3 | import ( 4 | "context" 5 | ) 6 | 7 | // RuleSet is used to provide custom rules to allow or prohibit actions 8 | type RuleSet interface { 9 | Allow(ctx context.Context, req *Request) (context.Context, bool) 10 | } 11 | 12 | // PermitAll returns a RuleSet which allows all types of connections 13 | func PermitAll() RuleSet { 14 | return &PermitCommand{true, true, true} 15 | } 16 | 17 | // PermitNone returns a RuleSet which disallows all types of connections 18 | func PermitNone() RuleSet { 19 | return &PermitCommand{false, false, false} 20 | } 21 | 22 | // PermitCommand is an implementation of the RuleSet which 23 | // enables filtering supported commands 24 | type PermitCommand struct { 25 | EnableConnect bool 26 | EnableBind bool 27 | EnableAssociate bool 28 | } 29 | 30 | func (p *PermitCommand) Allow(ctx context.Context, req *Request) (context.Context, bool) { 31 | switch req.Command { 32 | case ConnectCommand: 33 | return ctx, p.EnableConnect 34 | case BindCommand: 35 | return ctx, p.EnableBind 36 | case AssociateCommand: 37 | return ctx, p.EnableAssociate 38 | } 39 | 40 | return ctx, false 41 | } 42 | -------------------------------------------------------------------------------- /vendor/github.com/c-pro/go-socks5/README.md: -------------------------------------------------------------------------------- 1 | go-socks5 [![Build Status](https://travis-ci.org/armon/go-socks5.png)](https://travis-ci.org/armon/go-socks5) 2 | ========= 3 | 4 | Provides the `socks5` package that implements a [SOCKS5 server](http://en.wikipedia.org/wiki/SOCKS). 5 | SOCKS (Secure Sockets) is used to route traffic between a client and server through 6 | an intermediate proxy layer. This can be used to bypass firewalls or NATs. 7 | 8 | Feature 9 | ======= 10 | 11 | The package has the following features: 12 | * "No Auth" mode 13 | * User/Password authentication 14 | * Support for the CONNECT command 15 | * Rules to do granular filtering of commands 16 | * Custom DNS resolution 17 | * Unit tests 18 | 19 | TODO 20 | ==== 21 | 22 | The package still needs the following: 23 | * Support for the BIND command 24 | * Support for the ASSOCIATE command 25 | 26 | 27 | Example 28 | ======= 29 | 30 | Below is a simple example of usage 31 | 32 | ```go 33 | // Create a SOCKS5 server 34 | conf := &socks5.Config{} 35 | server, err := socks5.New(conf) 36 | if err != nil { 37 | panic(err) 38 | } 39 | 40 | // Create SOCKS5 proxy on localhost port 8000 41 | if err := server.ListenAndServe("tcp", "127.0.0.1:8000"); err != nil { 42 | panic(err) 43 | } 44 | ``` 45 | 46 | -------------------------------------------------------------------------------- /s5.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "log" 6 | 7 | socks5 "github.com/c-pro/go-socks5" 8 | "github.com/kelseyhightower/envconfig" 9 | 10 | "os" 11 | ) 12 | 13 | type config struct { 14 | Host string `default:"0.0.0.0"` 15 | Port int `default:"1080"` 16 | Users socks5.StaticCredentials 17 | } 18 | 19 | func main() { 20 | log.Println("SOCKS5 server: https://github.com/Egregors/socks5-server") 21 | 22 | var cfg config 23 | err := envconfig.Process("", &cfg) 24 | if err != nil { 25 | log.Fatalf("Failed to read ENV: %s\n", err.Error()) 26 | } 27 | 28 | if len(cfg.Users) < 1 { 29 | log.Fatal("No user credentials specified in USERS environment variable") 30 | } 31 | 32 | auth := socks5.UserPassAuthenticator{Credentials: cfg.Users} 33 | 34 | log.Println("Configuration..") 35 | srvConfig := &socks5.Config{ 36 | AuthMethods: []socks5.Authenticator{auth}, 37 | Logger: log.New(os.Stdout, "", log.LstdFlags), 38 | } 39 | 40 | srv, err := socks5.New(srvConfig) 41 | if err != nil { 42 | log.Panic(err.Error()) 43 | } 44 | 45 | addr := fmt.Sprintf("%s:%d", cfg.Host, cfg.Port) 46 | log.Printf("Starting server on %s\n", addr) 47 | if err := srv.ListenAndServe("tcp", addr); err != nil { 48 | log.Fatalf("Failed to start socks server on %s: %s\n", addr, err) 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Binaries for programs and plugins 2 | *.exe 3 | *.dll 4 | *.so 5 | *.dylib 6 | 7 | # Test binary, build with `go test -c` 8 | *.test 9 | 10 | # Output of the go coverage tool, specifically when used with LiteIDE 11 | *.out 12 | 13 | # Project-local glide cache, RE: https://github.com/Masterminds/glide/issues/736 14 | .glide/ 15 | 16 | ### JetBrains template 17 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and WebStorm 18 | # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 19 | 20 | # User-specific stuff: 21 | .idea/**/tasks.xml 22 | .idea/dictionaries 23 | 24 | # Sensitive or high-churn files: 25 | .idea/**/dataSources/ 26 | .idea/**/dataSources.ids 27 | .idea/**/dataSources.local.xml 28 | .idea/**/sqlDataSources.xml 29 | .idea/**/dynamic.xml 30 | .idea/**/uiDesigner.xml 31 | 32 | # Gradle: 33 | .idea/**/gradle.xml 34 | .idea/**/libraries 35 | 36 | # CMake 37 | cmake-build-debug/ 38 | cmake-build-release/ 39 | 40 | # Mongo Explorer plugin: 41 | .idea/**/mongoSettings.xml 42 | 43 | ## File-based project format: 44 | *.iws 45 | 46 | ## Plugin-specific files: 47 | 48 | # IntelliJ 49 | out/ 50 | 51 | # mpeltonen/sbt-idea plugin 52 | .idea_modules/ 53 | 54 | # JIRA plugin 55 | atlassian-ide-plugin.xml 56 | 57 | # Cursive Clojure plugin 58 | .idea/replstate.xml 59 | 60 | # Crashlytics plugin (for Android Studio and IntelliJ) 61 | com_crashlytics_export_strings.xml 62 | crashlytics.properties 63 | crashlytics-build.properties 64 | fabric.properties 65 | ### Go template 66 | # Binaries for programs and plugins 67 | *.exe~ 68 | 69 | .idea/ 70 | socks5-server 71 | *.*~ 72 | 73 | -------------------------------------------------------------------------------- /vendor/github.com/c-pro/go-socks5/auth.go: -------------------------------------------------------------------------------- 1 | package socks5 2 | 3 | import ( 4 | "fmt" 5 | "io" 6 | ) 7 | 8 | const ( 9 | NoAuth = uint8(0) 10 | noAcceptable = uint8(255) 11 | UserPassAuth = uint8(2) 12 | userAuthVersion = uint8(1) 13 | authSuccess = uint8(0) 14 | authFailure = uint8(1) 15 | ) 16 | 17 | var ( 18 | UserAuthFailed = fmt.Errorf("User authentication failed") 19 | NoSupportedAuth = fmt.Errorf("No supported authentication mechanism") 20 | ) 21 | 22 | // A Request encapsulates authentication state provided 23 | // during negotiation 24 | type AuthContext struct { 25 | // Provided auth method 26 | Method uint8 27 | // Payload provided during negotiation. 28 | // Keys depend on the used auth method. 29 | // For UserPassauth contains Username 30 | Payload map[string]string 31 | } 32 | 33 | type Authenticator interface { 34 | Authenticate(reader io.Reader, writer io.Writer) (*AuthContext, error) 35 | GetCode() uint8 36 | } 37 | 38 | // NoAuthAuthenticator is used to handle the "No Authentication" mode 39 | type NoAuthAuthenticator struct{} 40 | 41 | func (a NoAuthAuthenticator) GetCode() uint8 { 42 | return NoAuth 43 | } 44 | 45 | func (a NoAuthAuthenticator) Authenticate(reader io.Reader, writer io.Writer) (*AuthContext, error) { 46 | _, err := writer.Write([]byte{socks5Version, NoAuth}) 47 | return &AuthContext{NoAuth, nil}, err 48 | } 49 | 50 | // UserPassAuthenticator is used to handle username/password based 51 | // authentication 52 | type UserPassAuthenticator struct { 53 | Credentials CredentialStore 54 | } 55 | 56 | func (a UserPassAuthenticator) GetCode() uint8 { 57 | return UserPassAuth 58 | } 59 | 60 | func (a UserPassAuthenticator) Authenticate(reader io.Reader, writer io.Writer) (*AuthContext, error) { 61 | // Tell the client to use user/pass auth 62 | if _, err := writer.Write([]byte{socks5Version, UserPassAuth}); err != nil { 63 | return nil, err 64 | } 65 | 66 | // Get the version and username length 67 | header := []byte{0, 0} 68 | if _, err := io.ReadAtLeast(reader, header, 2); err != nil { 69 | return nil, err 70 | } 71 | 72 | // Ensure we are compatible 73 | if header[0] != userAuthVersion { 74 | return nil, fmt.Errorf("Unsupported auth version: %v", header[0]) 75 | } 76 | 77 | // Get the user name 78 | userLen := int(header[1]) 79 | user := make([]byte, userLen) 80 | if _, err := io.ReadAtLeast(reader, user, userLen); err != nil { 81 | return nil, err 82 | } 83 | 84 | // Get the password length 85 | if _, err := reader.Read(header[:1]); err != nil { 86 | return nil, err 87 | } 88 | 89 | // Get the password 90 | passLen := int(header[0]) 91 | pass := make([]byte, passLen) 92 | if _, err := io.ReadAtLeast(reader, pass, passLen); err != nil { 93 | return nil, err 94 | } 95 | 96 | // Verify the password 97 | if a.Credentials.Valid(string(user), string(pass)) { 98 | if _, err := writer.Write([]byte{userAuthVersion, authSuccess}); err != nil { 99 | return nil, err 100 | } 101 | } else { 102 | if _, err := writer.Write([]byte{userAuthVersion, authFailure}); err != nil { 103 | return nil, err 104 | } 105 | return nil, UserAuthFailed 106 | } 107 | 108 | // Done 109 | return &AuthContext{UserPassAuth, map[string]string{"Username": string(user)}}, nil 110 | } 111 | 112 | // authenticate is used to handle connection authentication 113 | func (s *Server) authenticate(conn io.Writer, bufConn io.Reader) (*AuthContext, error) { 114 | // Get the methods 115 | methods, err := readMethods(bufConn) 116 | if err != nil { 117 | return nil, fmt.Errorf("Failed to get auth methods: %v", err) 118 | } 119 | 120 | // Select a usable method 121 | for _, method := range methods { 122 | cator, found := s.authMethods[method] 123 | if found { 124 | return cator.Authenticate(bufConn, conn) 125 | } 126 | } 127 | 128 | // No usable method found 129 | return nil, noAcceptableAuth(conn) 130 | } 131 | 132 | // noAcceptableAuth is used to handle when we have no eligible 133 | // authentication mechanism 134 | func noAcceptableAuth(conn io.Writer) error { 135 | conn.Write([]byte{socks5Version, noAcceptable}) 136 | return NoSupportedAuth 137 | } 138 | 139 | // readMethods is used to read the number of methods 140 | // and proceeding auth methods 141 | func readMethods(r io.Reader) ([]byte, error) { 142 | header := []byte{0} 143 | if _, err := r.Read(header); err != nil { 144 | return nil, err 145 | } 146 | 147 | numMethods := int(header[0]) 148 | methods := make([]byte, numMethods) 149 | _, err := io.ReadAtLeast(r, methods, numMethods) 150 | return methods, err 151 | } 152 | -------------------------------------------------------------------------------- /vendor/github.com/c-pro/go-socks5/socks5.go: -------------------------------------------------------------------------------- 1 | package socks5 2 | 3 | import ( 4 | "bufio" 5 | "context" 6 | "fmt" 7 | "log" 8 | "net" 9 | "os" 10 | ) 11 | 12 | const ( 13 | socks5Version = uint8(5) 14 | ) 15 | 16 | // Config is used to setup and configure a Server 17 | type Config struct { 18 | // AuthMethods can be provided to implement custom authentication 19 | // By default, "auth-less" mode is enabled. 20 | // For password-based auth use UserPassAuthenticator. 21 | AuthMethods []Authenticator 22 | 23 | // If provided, username/password authentication is enabled, 24 | // by appending a UserPassAuthenticator to AuthMethods. If not provided, 25 | // and AUthMethods is nil, then "auth-less" mode is enabled. 26 | Credentials CredentialStore 27 | 28 | // Resolver can be provided to do custom name resolution. 29 | // Defaults to DNSResolver if not provided. 30 | Resolver NameResolver 31 | 32 | // Rules is provided to enable custom logic around permitting 33 | // various commands. If not provided, PermitAll is used. 34 | Rules RuleSet 35 | 36 | // Rewriter can be used to transparently rewrite addresses. 37 | // This is invoked before the RuleSet is invoked. 38 | // Defaults to NoRewrite. 39 | Rewriter AddressRewriter 40 | 41 | // BindIP is used for bind or udp associate 42 | BindIP net.IP 43 | 44 | // Logger can be used to provide a custom log target. 45 | // Defaults to stdout. 46 | Logger *log.Logger 47 | 48 | // Optional function for dialing out 49 | Dial func(ctx context.Context, network, addr string) (net.Conn, error) 50 | } 51 | 52 | // Server is reponsible for accepting connections and handling 53 | // the details of the SOCKS5 protocol 54 | type Server struct { 55 | config *Config 56 | authMethods map[uint8]Authenticator 57 | } 58 | 59 | // New creates a new Server and potentially returns an error 60 | func New(conf *Config) (*Server, error) { 61 | // Ensure we have at least one authentication method enabled 62 | if len(conf.AuthMethods) == 0 { 63 | if conf.Credentials != nil { 64 | conf.AuthMethods = []Authenticator{&UserPassAuthenticator{conf.Credentials}} 65 | } else { 66 | conf.AuthMethods = []Authenticator{&NoAuthAuthenticator{}} 67 | } 68 | } 69 | 70 | // Ensure we have a DNS resolver 71 | if conf.Resolver == nil { 72 | conf.Resolver = DNSResolver{} 73 | } 74 | 75 | // Ensure we have a rule set 76 | if conf.Rules == nil { 77 | conf.Rules = PermitAll() 78 | } 79 | 80 | // Ensure we have a log target 81 | if conf.Logger == nil { 82 | conf.Logger = log.New(os.Stdout, "", log.LstdFlags) 83 | } 84 | 85 | server := &Server{ 86 | config: conf, 87 | } 88 | 89 | server.authMethods = make(map[uint8]Authenticator) 90 | 91 | for _, a := range conf.AuthMethods { 92 | server.authMethods[a.GetCode()] = a 93 | } 94 | 95 | return server, nil 96 | } 97 | 98 | // ListenAndServe is used to create a listener and serve on it 99 | func (s *Server) ListenAndServe(network, addr string) error { 100 | l, err := net.Listen(network, addr) 101 | if err != nil { 102 | return err 103 | } 104 | return s.Serve(l) 105 | } 106 | 107 | // Serve is used to serve connections from a listener 108 | func (s *Server) Serve(l net.Listener) error { 109 | for { 110 | conn, err := l.Accept() 111 | if err != nil { 112 | return err 113 | } 114 | go s.ServeConn(conn) 115 | } 116 | return nil 117 | } 118 | 119 | // ServeConn is used to serve a single connection. 120 | func (s *Server) ServeConn(conn net.Conn) error { 121 | defer conn.Close() 122 | bufConn := bufio.NewReader(conn) 123 | 124 | // Read the version byte 125 | version := []byte{0} 126 | if _, err := bufConn.Read(version); err != nil { 127 | s.config.Logger.Printf("[ERR] socks: Failed to get version byte: %v", err) 128 | return err 129 | } 130 | 131 | // Ensure we are compatible 132 | if version[0] != socks5Version { 133 | err := fmt.Errorf("Unsupported SOCKS version: %v", version) 134 | s.config.Logger.Printf("[ERR] socks: %v", err) 135 | return err 136 | } 137 | 138 | // Authenticate the connection 139 | authContext, err := s.authenticate(conn, bufConn) 140 | if err != nil { 141 | err = fmt.Errorf("Failed to authenticate: %v", err) 142 | s.config.Logger.Printf("[ERR] socks: %v", err) 143 | return err 144 | } 145 | 146 | request, err := NewRequest(bufConn) 147 | if err != nil { 148 | if err == unrecognizedAddrType { 149 | if err := sendReply(conn, addrTypeNotSupported, nil); err != nil { 150 | return fmt.Errorf("Failed to send reply: %v", err) 151 | } 152 | } 153 | return fmt.Errorf("Failed to read destination address: %v", err) 154 | } 155 | request.AuthContext = authContext 156 | if client, ok := conn.RemoteAddr().(*net.TCPAddr); ok { 157 | request.RemoteAddr = &AddrSpec{IP: client.IP, Port: client.Port} 158 | } 159 | 160 | // Process the client request 161 | if err := s.handleRequest(request, conn); err != nil { 162 | err = fmt.Errorf("Failed to handle request: %v", err) 163 | s.config.Logger.Printf("[ERR] socks: %v", err) 164 | return err 165 | } 166 | 167 | return nil 168 | } 169 | -------------------------------------------------------------------------------- /vendor/github.com/kelseyhightower/envconfig/usage.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016 Kelsey Hightower and others. All rights reserved. 2 | // Use of this source code is governed by the MIT License that can be found in 3 | // the LICENSE file. 4 | 5 | package envconfig 6 | 7 | import ( 8 | "encoding" 9 | "fmt" 10 | "io" 11 | "os" 12 | "reflect" 13 | "strconv" 14 | "strings" 15 | "text/tabwriter" 16 | "text/template" 17 | ) 18 | 19 | const ( 20 | // DefaultListFormat constant to use to display usage in a list format 21 | DefaultListFormat = `This application is configured via the environment. The following environment 22 | variables can be used: 23 | {{range .}} 24 | {{usage_key .}} 25 | [description] {{usage_description .}} 26 | [type] {{usage_type .}} 27 | [default] {{usage_default .}} 28 | [required] {{usage_required .}}{{end}} 29 | ` 30 | // DefaultTableFormat constant to use to display usage in a tabluar format 31 | DefaultTableFormat = `This application is configured via the environment. The following environment 32 | variables can be used: 33 | 34 | KEY TYPE DEFAULT REQUIRED DESCRIPTION 35 | {{range .}}{{usage_key .}} {{usage_type .}} {{usage_default .}} {{usage_required .}} {{usage_description .}} 36 | {{end}}` 37 | ) 38 | 39 | var ( 40 | decoderType = reflect.TypeOf((*Decoder)(nil)).Elem() 41 | setterType = reflect.TypeOf((*Setter)(nil)).Elem() 42 | unmarshalerType = reflect.TypeOf((*encoding.TextUnmarshaler)(nil)).Elem() 43 | ) 44 | 45 | func implementsInterface(t reflect.Type) bool { 46 | return t.Implements(decoderType) || 47 | reflect.PtrTo(t).Implements(decoderType) || 48 | t.Implements(setterType) || 49 | reflect.PtrTo(t).Implements(setterType) || 50 | t.Implements(unmarshalerType) || 51 | reflect.PtrTo(t).Implements(unmarshalerType) 52 | } 53 | 54 | // toTypeDescription converts Go types into a human readable description 55 | func toTypeDescription(t reflect.Type) string { 56 | switch t.Kind() { 57 | case reflect.Array, reflect.Slice: 58 | return fmt.Sprintf("Comma-separated list of %s", toTypeDescription(t.Elem())) 59 | case reflect.Map: 60 | return fmt.Sprintf( 61 | "Comma-separated list of %s:%s pairs", 62 | toTypeDescription(t.Key()), 63 | toTypeDescription(t.Elem()), 64 | ) 65 | case reflect.Ptr: 66 | return toTypeDescription(t.Elem()) 67 | case reflect.Struct: 68 | if implementsInterface(t) && t.Name() != "" { 69 | return t.Name() 70 | } 71 | return "" 72 | case reflect.String: 73 | name := t.Name() 74 | if name != "" && name != "string" { 75 | return name 76 | } 77 | return "String" 78 | case reflect.Bool: 79 | name := t.Name() 80 | if name != "" && name != "bool" { 81 | return name 82 | } 83 | return "True or False" 84 | case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: 85 | name := t.Name() 86 | if name != "" && !strings.HasPrefix(name, "int") { 87 | return name 88 | } 89 | return "Integer" 90 | case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: 91 | name := t.Name() 92 | if name != "" && !strings.HasPrefix(name, "uint") { 93 | return name 94 | } 95 | return "Unsigned Integer" 96 | case reflect.Float32, reflect.Float64: 97 | name := t.Name() 98 | if name != "" && !strings.HasPrefix(name, "float") { 99 | return name 100 | } 101 | return "Float" 102 | } 103 | return fmt.Sprintf("%+v", t) 104 | } 105 | 106 | // Usage writes usage information to stderr using the default header and table format 107 | func Usage(prefix string, spec interface{}) error { 108 | // The default is to output the usage information as a table 109 | // Create tabwriter instance to support table output 110 | tabs := tabwriter.NewWriter(os.Stdout, 1, 0, 4, ' ', 0) 111 | 112 | err := Usagef(prefix, spec, tabs, DefaultTableFormat) 113 | tabs.Flush() 114 | return err 115 | } 116 | 117 | // Usagef writes usage information to the specified io.Writer using the specifed template specification 118 | func Usagef(prefix string, spec interface{}, out io.Writer, format string) error { 119 | 120 | // Specify the default usage template functions 121 | functions := template.FuncMap{ 122 | "usage_key": func(v varInfo) string { return v.Key }, 123 | "usage_description": func(v varInfo) string { return v.Tags.Get("desc") }, 124 | "usage_type": func(v varInfo) string { return toTypeDescription(v.Field.Type()) }, 125 | "usage_default": func(v varInfo) string { return v.Tags.Get("default") }, 126 | "usage_required": func(v varInfo) (string, error) { 127 | req := v.Tags.Get("required") 128 | if req != "" { 129 | reqB, err := strconv.ParseBool(req) 130 | if err != nil { 131 | return "", err 132 | } 133 | if reqB { 134 | req = "true" 135 | } 136 | } 137 | return req, nil 138 | }, 139 | } 140 | 141 | tmpl, err := template.New("envconfig").Funcs(functions).Parse(format) 142 | if err != nil { 143 | return err 144 | } 145 | 146 | return Usaget(prefix, spec, out, tmpl) 147 | } 148 | 149 | // Usaget writes usage information to the specified io.Writer using the specified template 150 | func Usaget(prefix string, spec interface{}, out io.Writer, tmpl *template.Template) error { 151 | // gather first 152 | infos, err := gatherInfo(prefix, spec) 153 | if err != nil { 154 | return err 155 | } 156 | 157 | return tmpl.Execute(out, infos) 158 | } 159 | -------------------------------------------------------------------------------- /vendor/github.com/kelseyhightower/envconfig/README.md: -------------------------------------------------------------------------------- 1 | # envconfig 2 | 3 | [![Build Status](https://travis-ci.org/kelseyhightower/envconfig.png)](https://travis-ci.org/kelseyhightower/envconfig) 4 | 5 | ```Go 6 | import "github.com/kelseyhightower/envconfig" 7 | ``` 8 | 9 | ## Documentation 10 | 11 | See [godoc](http://godoc.org/github.com/kelseyhightower/envconfig) 12 | 13 | ## Usage 14 | 15 | Set some environment variables: 16 | 17 | ```Bash 18 | export MYAPP_DEBUG=false 19 | export MYAPP_PORT=8080 20 | export MYAPP_USER=Kelsey 21 | export MYAPP_RATE="0.5" 22 | export MYAPP_TIMEOUT="3m" 23 | export MYAPP_USERS="rob,ken,robert" 24 | export MYAPP_COLORCODES="red:1,green:2,blue:3" 25 | ``` 26 | 27 | Write some code: 28 | 29 | ```Go 30 | package main 31 | 32 | import ( 33 | "fmt" 34 | "log" 35 | "time" 36 | 37 | "github.com/kelseyhightower/envconfig" 38 | ) 39 | 40 | type Specification struct { 41 | Debug bool 42 | Port int 43 | User string 44 | Users []string 45 | Rate float32 46 | Timeout time.Duration 47 | ColorCodes map[string]int 48 | } 49 | 50 | func main() { 51 | var s Specification 52 | err := envconfig.Process("myapp", &s) 53 | if err != nil { 54 | log.Fatal(err.Error()) 55 | } 56 | format := "Debug: %v\nPort: %d\nUser: %s\nRate: %f\nTimeout: %s\n" 57 | _, err = fmt.Printf(format, s.Debug, s.Port, s.User, s.Rate) 58 | if err != nil { 59 | log.Fatal(err.Error()) 60 | } 61 | 62 | fmt.Println("Users:") 63 | for _, u := range s.Users { 64 | fmt.Printf(" %s\n", u) 65 | } 66 | 67 | fmt.Println("Color codes:") 68 | for k, v := range s.ColorCodes { 69 | fmt.Printf(" %s: %d\n", k, v) 70 | } 71 | } 72 | ``` 73 | 74 | Results: 75 | 76 | ```Bash 77 | Debug: false 78 | Port: 8080 79 | User: Kelsey 80 | Rate: 0.500000 81 | Timeout: 3m0s 82 | Users: 83 | rob 84 | ken 85 | robert 86 | Color codes: 87 | red: 1 88 | green: 2 89 | blue: 3 90 | ``` 91 | 92 | ## Struct Tag Support 93 | 94 | Envconfig supports the use of struct tags to specify alternate, default, and required 95 | environment variables. 96 | 97 | For example, consider the following struct: 98 | 99 | ```Go 100 | type Specification struct { 101 | ManualOverride1 string `envconfig:"manual_override_1"` 102 | DefaultVar string `default:"foobar"` 103 | RequiredVar string `required:"true"` 104 | IgnoredVar string `ignored:"true"` 105 | AutoSplitVar string `split_words:"true"` 106 | } 107 | ``` 108 | 109 | Envconfig has automatic support for CamelCased struct elements when the 110 | `split_words:"true"` tag is supplied. Without this tag, `AutoSplitVar` above 111 | would look for an environment variable called `MYAPP_AUTOSPLITVAR`. With the 112 | setting applied it will look for `MYAPP_AUTO_SPLIT_VAR`. Note that numbers 113 | will get globbed into the previous word. If the setting does not do the 114 | right thing, you may use a manual override. 115 | 116 | Envconfig will process value for `ManualOverride1` by populating it with the 117 | value for `MYAPP_MANUAL_OVERRIDE_1`. Without this struct tag, it would have 118 | instead looked up `MYAPP_MANUALOVERRIDE1`. With the `split_words:"true"` tag 119 | it would have looked up `MYAPP_MANUAL_OVERRIDE1`. 120 | 121 | ```Bash 122 | export MYAPP_MANUAL_OVERRIDE_1="this will be the value" 123 | 124 | # export MYAPP_MANUALOVERRIDE1="and this will not" 125 | ``` 126 | 127 | If envconfig can't find an environment variable value for `MYAPP_DEFAULTVAR`, 128 | it will populate it with "foobar" as a default value. 129 | 130 | If envconfig can't find an environment variable value for `MYAPP_REQUIREDVAR`, 131 | it will return an error when asked to process the struct. 132 | 133 | If envconfig can't find an environment variable in the form `PREFIX_MYVAR`, and there 134 | is a struct tag defined, it will try to populate your variable with an environment 135 | variable that directly matches the envconfig tag in your struct definition: 136 | 137 | ```shell 138 | export SERVICE_HOST=127.0.0.1 139 | export MYAPP_DEBUG=true 140 | ``` 141 | ```Go 142 | type Specification struct { 143 | ServiceHost string `envconfig:"SERVICE_HOST"` 144 | Debug bool 145 | } 146 | ``` 147 | 148 | Envconfig won't process a field with the "ignored" tag set to "true", even if a corresponding 149 | environment variable is set. 150 | 151 | ## Supported Struct Field Types 152 | 153 | envconfig supports supports these struct field types: 154 | 155 | * string 156 | * int8, int16, int32, int64 157 | * bool 158 | * float32, float64 159 | * slices of any supported type 160 | * maps (keys and values of any supported type) 161 | * [encoding.TextUnmarshaler](https://golang.org/pkg/encoding/#TextUnmarshaler) 162 | 163 | Embedded structs using these fields are also supported. 164 | 165 | ## Custom Decoders 166 | 167 | Any field whose type (or pointer-to-type) implements `envconfig.Decoder` can 168 | control its own deserialization: 169 | 170 | ```Bash 171 | export DNS_SERVER=8.8.8.8 172 | ``` 173 | 174 | ```Go 175 | type IPDecoder net.IP 176 | 177 | func (ipd *IPDecoder) Decode(value string) error { 178 | *ipd = IPDecoder(net.ParseIP(value)) 179 | return nil 180 | } 181 | 182 | type DNSConfig struct { 183 | Address IPDecoder `envconfig:"DNS_SERVER"` 184 | } 185 | ``` 186 | 187 | Also, envconfig will use a `Set(string) error` method like from the 188 | [flag.Value](https://godoc.org/flag#Value) interface if implemented. 189 | -------------------------------------------------------------------------------- /vendor/github.com/kelseyhightower/envconfig/envconfig.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2013 Kelsey Hightower. All rights reserved. 2 | // Use of this source code is governed by the MIT License that can be found in 3 | // the LICENSE file. 4 | 5 | package envconfig 6 | 7 | import ( 8 | "encoding" 9 | "errors" 10 | "fmt" 11 | "reflect" 12 | "regexp" 13 | "strconv" 14 | "strings" 15 | "time" 16 | ) 17 | 18 | // ErrInvalidSpecification indicates that a specification is of the wrong type. 19 | var ErrInvalidSpecification = errors.New("specification must be a struct pointer") 20 | 21 | // A ParseError occurs when an environment variable cannot be converted to 22 | // the type required by a struct field during assignment. 23 | type ParseError struct { 24 | KeyName string 25 | FieldName string 26 | TypeName string 27 | Value string 28 | Err error 29 | } 30 | 31 | // Decoder has the same semantics as Setter, but takes higher precedence. 32 | // It is provided for historical compatibility. 33 | type Decoder interface { 34 | Decode(value string) error 35 | } 36 | 37 | // Setter is implemented by types can self-deserialize values. 38 | // Any type that implements flag.Value also implements Setter. 39 | type Setter interface { 40 | Set(value string) error 41 | } 42 | 43 | func (e *ParseError) Error() string { 44 | return fmt.Sprintf("envconfig.Process: assigning %[1]s to %[2]s: converting '%[3]s' to type %[4]s. details: %[5]s", e.KeyName, e.FieldName, e.Value, e.TypeName, e.Err) 45 | } 46 | 47 | // varInfo maintains information about the configuration variable 48 | type varInfo struct { 49 | Name string 50 | Alt string 51 | Key string 52 | Field reflect.Value 53 | Tags reflect.StructTag 54 | } 55 | 56 | // GatherInfo gathers information about the specified struct 57 | func gatherInfo(prefix string, spec interface{}) ([]varInfo, error) { 58 | expr := regexp.MustCompile("([^A-Z]+|[A-Z][^A-Z]+|[A-Z]+)") 59 | s := reflect.ValueOf(spec) 60 | 61 | if s.Kind() != reflect.Ptr { 62 | return nil, ErrInvalidSpecification 63 | } 64 | s = s.Elem() 65 | if s.Kind() != reflect.Struct { 66 | return nil, ErrInvalidSpecification 67 | } 68 | typeOfSpec := s.Type() 69 | 70 | // over allocate an info array, we will extend if needed later 71 | infos := make([]varInfo, 0, s.NumField()) 72 | for i := 0; i < s.NumField(); i++ { 73 | f := s.Field(i) 74 | ftype := typeOfSpec.Field(i) 75 | if !f.CanSet() || ftype.Tag.Get("ignored") == "true" { 76 | continue 77 | } 78 | 79 | for f.Kind() == reflect.Ptr { 80 | if f.IsNil() { 81 | if f.Type().Elem().Kind() != reflect.Struct { 82 | // nil pointer to a non-struct: leave it alone 83 | break 84 | } 85 | // nil pointer to struct: create a zero instance 86 | f.Set(reflect.New(f.Type().Elem())) 87 | } 88 | f = f.Elem() 89 | } 90 | 91 | // Capture information about the config variable 92 | info := varInfo{ 93 | Name: ftype.Name, 94 | Field: f, 95 | Tags: ftype.Tag, 96 | Alt: strings.ToUpper(ftype.Tag.Get("envconfig")), 97 | } 98 | 99 | // Default to the field name as the env var name (will be upcased) 100 | info.Key = info.Name 101 | 102 | // Best effort to un-pick camel casing as separate words 103 | if ftype.Tag.Get("split_words") == "true" { 104 | words := expr.FindAllStringSubmatch(ftype.Name, -1) 105 | if len(words) > 0 { 106 | var name []string 107 | for _, words := range words { 108 | name = append(name, words[0]) 109 | } 110 | 111 | info.Key = strings.Join(name, "_") 112 | } 113 | } 114 | if info.Alt != "" { 115 | info.Key = info.Alt 116 | } 117 | if prefix != "" { 118 | info.Key = fmt.Sprintf("%s_%s", prefix, info.Key) 119 | } 120 | info.Key = strings.ToUpper(info.Key) 121 | infos = append(infos, info) 122 | 123 | if f.Kind() == reflect.Struct { 124 | // honor Decode if present 125 | if decoderFrom(f) == nil && setterFrom(f) == nil && textUnmarshaler(f) == nil { 126 | innerPrefix := prefix 127 | if !ftype.Anonymous { 128 | innerPrefix = info.Key 129 | } 130 | 131 | embeddedPtr := f.Addr().Interface() 132 | embeddedInfos, err := gatherInfo(innerPrefix, embeddedPtr) 133 | if err != nil { 134 | return nil, err 135 | } 136 | infos = append(infos[:len(infos)-1], embeddedInfos...) 137 | 138 | continue 139 | } 140 | } 141 | } 142 | return infos, nil 143 | } 144 | 145 | // Process populates the specified struct based on environment variables 146 | func Process(prefix string, spec interface{}) error { 147 | infos, err := gatherInfo(prefix, spec) 148 | 149 | for _, info := range infos { 150 | 151 | // `os.Getenv` cannot differentiate between an explicitly set empty value 152 | // and an unset value. `os.LookupEnv` is preferred to `syscall.Getenv`, 153 | // but it is only available in go1.5 or newer. We're using Go build tags 154 | // here to use os.LookupEnv for >=go1.5 155 | value, ok := lookupEnv(info.Key) 156 | if !ok && info.Alt != "" { 157 | value, ok = lookupEnv(info.Alt) 158 | } 159 | 160 | def := info.Tags.Get("default") 161 | if def != "" && !ok { 162 | value = def 163 | } 164 | 165 | req := info.Tags.Get("required") 166 | if !ok && def == "" { 167 | if req == "true" { 168 | return fmt.Errorf("required key %s missing value", info.Key) 169 | } 170 | continue 171 | } 172 | 173 | err := processField(value, info.Field) 174 | if err != nil { 175 | return &ParseError{ 176 | KeyName: info.Key, 177 | FieldName: info.Name, 178 | TypeName: info.Field.Type().String(), 179 | Value: value, 180 | Err: err, 181 | } 182 | } 183 | } 184 | 185 | return err 186 | } 187 | 188 | // MustProcess is the same as Process but panics if an error occurs 189 | func MustProcess(prefix string, spec interface{}) { 190 | if err := Process(prefix, spec); err != nil { 191 | panic(err) 192 | } 193 | } 194 | 195 | func processField(value string, field reflect.Value) error { 196 | typ := field.Type() 197 | 198 | decoder := decoderFrom(field) 199 | if decoder != nil { 200 | return decoder.Decode(value) 201 | } 202 | // look for Set method if Decode not defined 203 | setter := setterFrom(field) 204 | if setter != nil { 205 | return setter.Set(value) 206 | } 207 | 208 | if t := textUnmarshaler(field); t != nil { 209 | return t.UnmarshalText([]byte(value)) 210 | } 211 | 212 | if typ.Kind() == reflect.Ptr { 213 | typ = typ.Elem() 214 | if field.IsNil() { 215 | field.Set(reflect.New(typ)) 216 | } 217 | field = field.Elem() 218 | } 219 | 220 | switch typ.Kind() { 221 | case reflect.String: 222 | field.SetString(value) 223 | case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: 224 | var ( 225 | val int64 226 | err error 227 | ) 228 | if field.Kind() == reflect.Int64 && typ.PkgPath() == "time" && typ.Name() == "Duration" { 229 | var d time.Duration 230 | d, err = time.ParseDuration(value) 231 | val = int64(d) 232 | } else { 233 | val, err = strconv.ParseInt(value, 0, typ.Bits()) 234 | } 235 | if err != nil { 236 | return err 237 | } 238 | 239 | field.SetInt(val) 240 | case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: 241 | val, err := strconv.ParseUint(value, 0, typ.Bits()) 242 | if err != nil { 243 | return err 244 | } 245 | field.SetUint(val) 246 | case reflect.Bool: 247 | val, err := strconv.ParseBool(value) 248 | if err != nil { 249 | return err 250 | } 251 | field.SetBool(val) 252 | case reflect.Float32, reflect.Float64: 253 | val, err := strconv.ParseFloat(value, typ.Bits()) 254 | if err != nil { 255 | return err 256 | } 257 | field.SetFloat(val) 258 | case reflect.Slice: 259 | vals := strings.Split(value, ",") 260 | sl := reflect.MakeSlice(typ, len(vals), len(vals)) 261 | for i, val := range vals { 262 | err := processField(val, sl.Index(i)) 263 | if err != nil { 264 | return err 265 | } 266 | } 267 | field.Set(sl) 268 | case reflect.Map: 269 | pairs := strings.Split(value, ",") 270 | mp := reflect.MakeMap(typ) 271 | for _, pair := range pairs { 272 | kvpair := strings.Split(pair, ":") 273 | if len(kvpair) != 2 { 274 | return fmt.Errorf("invalid map item: %q", pair) 275 | } 276 | k := reflect.New(typ.Key()).Elem() 277 | err := processField(kvpair[0], k) 278 | if err != nil { 279 | return err 280 | } 281 | v := reflect.New(typ.Elem()).Elem() 282 | err = processField(kvpair[1], v) 283 | if err != nil { 284 | return err 285 | } 286 | mp.SetMapIndex(k, v) 287 | } 288 | field.Set(mp) 289 | } 290 | 291 | return nil 292 | } 293 | 294 | func interfaceFrom(field reflect.Value, fn func(interface{}, *bool)) { 295 | // it may be impossible for a struct field to fail this check 296 | if !field.CanInterface() { 297 | return 298 | } 299 | var ok bool 300 | fn(field.Interface(), &ok) 301 | if !ok && field.CanAddr() { 302 | fn(field.Addr().Interface(), &ok) 303 | } 304 | } 305 | 306 | func decoderFrom(field reflect.Value) (d Decoder) { 307 | interfaceFrom(field, func(v interface{}, ok *bool) { d, *ok = v.(Decoder) }) 308 | return d 309 | } 310 | 311 | func setterFrom(field reflect.Value) (s Setter) { 312 | interfaceFrom(field, func(v interface{}, ok *bool) { s, *ok = v.(Setter) }) 313 | return s 314 | } 315 | 316 | func textUnmarshaler(field reflect.Value) (t encoding.TextUnmarshaler) { 317 | interfaceFrom(field, func(v interface{}, ok *bool) { t, *ok = v.(encoding.TextUnmarshaler) }) 318 | return t 319 | } 320 | -------------------------------------------------------------------------------- /vendor/github.com/c-pro/go-socks5/request.go: -------------------------------------------------------------------------------- 1 | package socks5 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | "io" 7 | "net" 8 | "strconv" 9 | "strings" 10 | ) 11 | 12 | const ( 13 | ConnectCommand = uint8(1) 14 | BindCommand = uint8(2) 15 | AssociateCommand = uint8(3) 16 | ipv4Address = uint8(1) 17 | fqdnAddress = uint8(3) 18 | ipv6Address = uint8(4) 19 | ) 20 | 21 | const ( 22 | successReply uint8 = iota 23 | serverFailure 24 | ruleFailure 25 | networkUnreachable 26 | hostUnreachable 27 | connectionRefused 28 | ttlExpired 29 | commandNotSupported 30 | addrTypeNotSupported 31 | ) 32 | 33 | var ( 34 | unrecognizedAddrType = fmt.Errorf("Unrecognized address type") 35 | ) 36 | 37 | // AddressRewriter is used to rewrite a destination transparently 38 | type AddressRewriter interface { 39 | Rewrite(ctx context.Context, request *Request) (context.Context, *AddrSpec) 40 | } 41 | 42 | // AddrSpec is used to return the target AddrSpec 43 | // which may be specified as IPv4, IPv6, or a FQDN 44 | type AddrSpec struct { 45 | FQDN string 46 | IP net.IP 47 | Port int 48 | } 49 | 50 | func (a *AddrSpec) String() string { 51 | if a.FQDN != "" { 52 | return fmt.Sprintf("%s (%s):%d", a.FQDN, a.IP, a.Port) 53 | } 54 | return fmt.Sprintf("%s:%d", a.IP, a.Port) 55 | } 56 | 57 | // Address returns a string suitable to dial; prefer returning IP-based 58 | // address, fallback to FQDN 59 | func (a AddrSpec) Address() string { 60 | if 0 != len(a.IP) { 61 | return net.JoinHostPort(a.IP.String(), strconv.Itoa(a.Port)) 62 | } 63 | return net.JoinHostPort(a.FQDN, strconv.Itoa(a.Port)) 64 | } 65 | 66 | // A Request represents request received by a server 67 | type Request struct { 68 | // Protocol version 69 | Version uint8 70 | // Requested command 71 | Command uint8 72 | // AuthContext provided during negotiation 73 | AuthContext *AuthContext 74 | // AddrSpec of the the network that sent the request 75 | RemoteAddr *AddrSpec 76 | // AddrSpec of the desired destination 77 | DestAddr *AddrSpec 78 | // AddrSpec of the actual destination (might be affected by rewrite) 79 | realDestAddr *AddrSpec 80 | bufConn io.Reader 81 | } 82 | 83 | type conn interface { 84 | Write([]byte) (int, error) 85 | RemoteAddr() net.Addr 86 | } 87 | 88 | // NewRequest creates a new Request from the tcp connection 89 | func NewRequest(bufConn io.Reader) (*Request, error) { 90 | // Read the version byte 91 | header := []byte{0, 0, 0} 92 | if _, err := io.ReadAtLeast(bufConn, header, 3); err != nil { 93 | return nil, fmt.Errorf("Failed to get command version: %v", err) 94 | } 95 | 96 | // Ensure we are compatible 97 | if header[0] != socks5Version { 98 | return nil, fmt.Errorf("Unsupported command version: %v", header[0]) 99 | } 100 | 101 | // Read in the destination address 102 | dest, err := readAddrSpec(bufConn) 103 | if err != nil { 104 | return nil, err 105 | } 106 | 107 | request := &Request{ 108 | Version: socks5Version, 109 | Command: header[1], 110 | DestAddr: dest, 111 | bufConn: bufConn, 112 | } 113 | 114 | return request, nil 115 | } 116 | 117 | // handleRequest is used for request processing after authentication 118 | func (s *Server) handleRequest(req *Request, conn conn) error { 119 | ctx := context.Background() 120 | 121 | // Resolve the address if we have a FQDN 122 | dest := req.DestAddr 123 | if dest.FQDN != "" { 124 | ctx_, addr, err := s.config.Resolver.Resolve(ctx, dest.FQDN) 125 | if err != nil { 126 | if err := sendReply(conn, hostUnreachable, nil); err != nil { 127 | return fmt.Errorf("Failed to send reply: %v", err) 128 | } 129 | return fmt.Errorf("Failed to resolve destination '%v': %v", dest.FQDN, err) 130 | } 131 | ctx = ctx_ 132 | dest.IP = addr 133 | } 134 | 135 | // Apply any address rewrites 136 | req.realDestAddr = req.DestAddr 137 | if s.config.Rewriter != nil { 138 | ctx, req.realDestAddr = s.config.Rewriter.Rewrite(ctx, req) 139 | } 140 | 141 | // Switch on the command 142 | switch req.Command { 143 | case ConnectCommand: 144 | return s.handleConnect(ctx, conn, req) 145 | case BindCommand: 146 | return s.handleBind(ctx, conn, req) 147 | case AssociateCommand: 148 | return s.handleAssociate(ctx, conn, req) 149 | default: 150 | if err := sendReply(conn, commandNotSupported, nil); err != nil { 151 | return fmt.Errorf("Failed to send reply: %v", err) 152 | } 153 | return fmt.Errorf("Unsupported command: %v", req.Command) 154 | } 155 | } 156 | 157 | // handleConnect is used to handle a connect command 158 | func (s *Server) handleConnect(ctx context.Context, conn conn, req *Request) error { 159 | // Check if this is allowed 160 | if ctx_, ok := s.config.Rules.Allow(ctx, req); !ok { 161 | if err := sendReply(conn, ruleFailure, nil); err != nil { 162 | return fmt.Errorf("Failed to send reply: %v", err) 163 | } 164 | return fmt.Errorf("Connect to %v blocked by rules", req.DestAddr) 165 | } else { 166 | ctx = ctx_ 167 | } 168 | 169 | // Attempt to connect 170 | dial := s.config.Dial 171 | if dial == nil { 172 | dial = func(ctx context.Context, net_, addr string) (net.Conn, error) { 173 | return net.Dial(net_, addr) 174 | } 175 | } 176 | target, err := dial(ctx, "tcp", req.realDestAddr.Address()) 177 | if err != nil { 178 | msg := err.Error() 179 | resp := hostUnreachable 180 | if strings.Contains(msg, "refused") { 181 | resp = connectionRefused 182 | } else if strings.Contains(msg, "network is unreachable") { 183 | resp = networkUnreachable 184 | } 185 | if err := sendReply(conn, resp, nil); err != nil { 186 | return fmt.Errorf("Failed to send reply: %v", err) 187 | } 188 | return fmt.Errorf("Connect to %v failed: %v", req.DestAddr, err) 189 | } 190 | defer target.Close() 191 | 192 | // Send success 193 | local := target.LocalAddr().(*net.TCPAddr) 194 | bind := AddrSpec{IP: local.IP, Port: local.Port} 195 | if err := sendReply(conn, successReply, &bind); err != nil { 196 | return fmt.Errorf("Failed to send reply: %v", err) 197 | } 198 | 199 | // Start proxying 200 | errCh := make(chan error, 2) 201 | go proxy(target, req.bufConn, errCh) 202 | go proxy(conn, target, errCh) 203 | 204 | // Wait 205 | for i := 0; i < 2; i++ { 206 | e := <-errCh 207 | if e != nil { 208 | // return from this function closes target (and conn). 209 | return e 210 | } 211 | } 212 | return nil 213 | } 214 | 215 | // handleBind is used to handle a connect command 216 | func (s *Server) handleBind(ctx context.Context, conn conn, req *Request) error { 217 | // Check if this is allowed 218 | if ctx_, ok := s.config.Rules.Allow(ctx, req); !ok { 219 | if err := sendReply(conn, ruleFailure, nil); err != nil { 220 | return fmt.Errorf("Failed to send reply: %v", err) 221 | } 222 | return fmt.Errorf("Bind to %v blocked by rules", req.DestAddr) 223 | } else { 224 | ctx = ctx_ 225 | } 226 | 227 | // TODO: Support bind 228 | if err := sendReply(conn, commandNotSupported, nil); err != nil { 229 | return fmt.Errorf("Failed to send reply: %v", err) 230 | } 231 | return nil 232 | } 233 | 234 | // handleAssociate is used to handle a connect command 235 | func (s *Server) handleAssociate(ctx context.Context, conn conn, req *Request) error { 236 | // Check if this is allowed 237 | if ctx_, ok := s.config.Rules.Allow(ctx, req); !ok { 238 | if err := sendReply(conn, ruleFailure, nil); err != nil { 239 | return fmt.Errorf("Failed to send reply: %v", err) 240 | } 241 | return fmt.Errorf("Associate to %v blocked by rules", req.DestAddr) 242 | } else { 243 | ctx = ctx_ 244 | } 245 | 246 | // TODO: Support associate 247 | if err := sendReply(conn, commandNotSupported, nil); err != nil { 248 | return fmt.Errorf("Failed to send reply: %v", err) 249 | } 250 | return nil 251 | } 252 | 253 | // readAddrSpec is used to read AddrSpec. 254 | // Expects an address type byte, follwed by the address and port 255 | func readAddrSpec(r io.Reader) (*AddrSpec, error) { 256 | d := &AddrSpec{} 257 | 258 | // Get the address type 259 | addrType := []byte{0} 260 | if _, err := r.Read(addrType); err != nil { 261 | return nil, err 262 | } 263 | 264 | // Handle on a per type basis 265 | switch addrType[0] { 266 | case ipv4Address: 267 | addr := make([]byte, 4) 268 | if _, err := io.ReadAtLeast(r, addr, len(addr)); err != nil { 269 | return nil, err 270 | } 271 | d.IP = net.IP(addr) 272 | 273 | case ipv6Address: 274 | addr := make([]byte, 16) 275 | if _, err := io.ReadAtLeast(r, addr, len(addr)); err != nil { 276 | return nil, err 277 | } 278 | d.IP = net.IP(addr) 279 | 280 | case fqdnAddress: 281 | if _, err := r.Read(addrType); err != nil { 282 | return nil, err 283 | } 284 | addrLen := int(addrType[0]) 285 | fqdn := make([]byte, addrLen) 286 | if _, err := io.ReadAtLeast(r, fqdn, addrLen); err != nil { 287 | return nil, err 288 | } 289 | d.FQDN = string(fqdn) 290 | 291 | default: 292 | return nil, unrecognizedAddrType 293 | } 294 | 295 | // Read the port 296 | port := []byte{0, 0} 297 | if _, err := io.ReadAtLeast(r, port, 2); err != nil { 298 | return nil, err 299 | } 300 | d.Port = (int(port[0]) << 8) | int(port[1]) 301 | 302 | return d, nil 303 | } 304 | 305 | // sendReply is used to send a reply message 306 | func sendReply(w io.Writer, resp uint8, addr *AddrSpec) error { 307 | // Format the address 308 | var addrType uint8 309 | var addrBody []byte 310 | var addrPort uint16 311 | switch { 312 | case addr == nil: 313 | addrType = ipv4Address 314 | addrBody = []byte{0, 0, 0, 0} 315 | addrPort = 0 316 | 317 | case addr.FQDN != "": 318 | addrType = fqdnAddress 319 | addrBody = append([]byte{byte(len(addr.FQDN))}, addr.FQDN...) 320 | addrPort = uint16(addr.Port) 321 | 322 | case addr.IP.To4() != nil: 323 | addrType = ipv4Address 324 | addrBody = []byte(addr.IP.To4()) 325 | addrPort = uint16(addr.Port) 326 | 327 | case addr.IP.To16() != nil: 328 | addrType = ipv6Address 329 | addrBody = []byte(addr.IP.To16()) 330 | addrPort = uint16(addr.Port) 331 | 332 | default: 333 | return fmt.Errorf("Failed to format address: %v", addr) 334 | } 335 | 336 | // Format the message 337 | msg := make([]byte, 6+len(addrBody)) 338 | msg[0] = socks5Version 339 | msg[1] = resp 340 | msg[2] = 0 // Reserved 341 | msg[3] = addrType 342 | copy(msg[4:], addrBody) 343 | msg[4+len(addrBody)] = byte(addrPort >> 8) 344 | msg[4+len(addrBody)+1] = byte(addrPort & 0xff) 345 | 346 | // Send the message 347 | _, err := w.Write(msg) 348 | return err 349 | } 350 | 351 | type closeWriter interface { 352 | CloseWrite() error 353 | } 354 | 355 | // proxy is used to suffle data from src to destination, and sends errors 356 | // down a dedicated channel 357 | func proxy(dst io.Writer, src io.Reader, errCh chan error) { 358 | _, err := io.Copy(dst, src) 359 | if tcpConn, ok := dst.(closeWriter); ok { 360 | tcpConn.CloseWrite() 361 | } 362 | errCh <- err 363 | } 364 | --------------------------------------------------------------------------------