├── .gitignore ├── LICENSE ├── README.md ├── go.mod ├── go.sum ├── net.go ├── parse.go ├── parse_test.go ├── socks.go ├── socks4.go ├── socks5.go ├── socks5_test.go └── spec ├── SOCKS4.protocol.txt ├── rfc1928.txt ├── rfc1929.txt └── socks4A.protocol.txt /.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 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2012, Hailiang Wang. All rights reserved. 2 | 3 | Redistribution and use in source and binary forms, with or without modification, 4 | are permitted provided that the following conditions are met: 5 | 6 | * Redistributions of source code must retain the above copyright notice, this 7 | list of conditions and the following disclaimer. 8 | 9 | * Redistributions in binary form must reproduce the above copyright notice, 10 | this list of conditions and the following disclaimer in the documentation 11 | and/or other materials provided with the distribution. 12 | 13 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 14 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 15 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 16 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 17 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 18 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 19 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 20 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 21 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 22 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | SOCKS 2 | ===== 3 | 4 | [![GoDoc](https://godoc.org/h12.io/socks?status.svg)](https://godoc.org/h12.io/socks) 5 | 6 | A SOCKS is a SOCKS4, SOCKS4A and SOCKS5 proxy package for Go. 7 | 8 | The package provides `socks.Dial` which returns a TCP dialing function from a socks proxy connection string. The returned dialing function can then be used to establish a TCP connection via the socks proxy or be used to initialize `http.Transport` for an HTTP connection. 9 | 10 | ## Quick Start 11 | ### Get the package 12 | 13 | go get -u "h12.io/socks" 14 | 15 | ### Import the package 16 | 17 | import "h12.io/socks" 18 | 19 | ### Create a SOCKS proxy dialing function 20 | 21 | dialSocksProxy := socks.Dial("socks5://127.0.0.1:1080?timeout=5s") 22 | tr := &http.Transport{Dial: dialSocksProxy} 23 | httpClient := &http.Client{Transport: tr} 24 | 25 | ### User/password authentication 26 | 27 | dialSocksProxy := socks.Dial("socks5://user:password@127.0.0.1:1080?timeout=5s") 28 | 29 | ## Example 30 | 31 | ```go 32 | package main 33 | 34 | import ( 35 | "fmt" 36 | "io/ioutil" 37 | "log" 38 | "net/http" 39 | 40 | "h12.io/socks" 41 | ) 42 | 43 | func main() { 44 | dialSocksProxy := socks.Dial("socks5://127.0.0.1:1080?timeout=5s") 45 | tr := &http.Transport{Dial: dialSocksProxy} 46 | httpClient := &http.Client{Transport: tr} 47 | resp, err := httpClient.Get("http://www.google.com") 48 | if err != nil { 49 | log.Fatal(err) 50 | } 51 | defer resp.Body.Close() 52 | if resp.StatusCode != http.StatusOK { 53 | log.Fatal(resp.StatusCode) 54 | } 55 | buf, err := ioutil.ReadAll(resp.Body) 56 | if err != nil { 57 | log.Fatal(err) 58 | } 59 | fmt.Println(string(buf)) 60 | } 61 | ``` 62 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module h12.io/socks 2 | 3 | go 1.9 4 | 5 | require ( 6 | github.com/h12w/go-socks5 v0.0.0-20200522160539-76189e178364 7 | github.com/phayes/freeport v0.0.0-20180830031419-95f893ade6f2 8 | ) 9 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | github.com/h12w/go-socks5 v0.0.0-20200522160539-76189e178364 h1:5XxdakFhqd9dnXoAZy1Mb2R/DZ6D1e+0bGC/JhucGYI= 2 | github.com/h12w/go-socks5 v0.0.0-20200522160539-76189e178364/go.mod h1:eDJQioIyy4Yn3MVivT7rv/39gAJTrA7lgmYr8EW950c= 3 | github.com/phayes/freeport v0.0.0-20180830031419-95f893ade6f2 h1:JhzVVoYvbOACxoUmOs6V/G4D5nPVUW73rKvXxP4XUJc= 4 | github.com/phayes/freeport v0.0.0-20180830031419-95f893ade6f2/go.mod h1:iIss55rKnNBTvrwdmkUpLnDpZoAHvWaiq5+iMmen4AE= 5 | -------------------------------------------------------------------------------- /net.go: -------------------------------------------------------------------------------- 1 | package socks 2 | 3 | import ( 4 | "bytes" 5 | "fmt" 6 | "net" 7 | "strconv" 8 | "time" 9 | ) 10 | 11 | type requestBuilder struct { 12 | bytes.Buffer 13 | } 14 | 15 | func (b *requestBuilder) add(data ...byte) { 16 | _, _ = b.Write(data) 17 | } 18 | 19 | func (c *config) sendReceive(conn net.Conn, req []byte) (resp []byte, err error) { 20 | if c.Timeout > 0 { 21 | if err := conn.SetWriteDeadline(time.Now().Add(c.Timeout)); err != nil { 22 | return nil, err 23 | } 24 | } 25 | _, err = conn.Write(req) 26 | if err != nil { 27 | return 28 | } 29 | resp, err = c.readAll(conn) 30 | return 31 | } 32 | 33 | func (c *config) readAll(conn net.Conn) (resp []byte, err error) { 34 | resp = make([]byte, 1024) 35 | if c.Timeout > 0 { 36 | if err := conn.SetReadDeadline(time.Now().Add(c.Timeout)); err != nil { 37 | return nil, err 38 | } 39 | } 40 | n, err := conn.Read(resp) 41 | resp = resp[:n] 42 | return 43 | } 44 | 45 | func lookupIPv4(host string) (net.IP, error) { 46 | ips, err := net.LookupIP(host) 47 | if err != nil { 48 | return nil, err 49 | } 50 | for _, ip := range ips { 51 | ipv4 := ip.To4() 52 | if ipv4 == nil { 53 | continue 54 | } 55 | return ipv4, nil 56 | } 57 | return nil, fmt.Errorf("no IPv4 address found for host: %s", host) 58 | } 59 | 60 | func splitHostPort(addr string) (host string, port uint16, err error) { 61 | host, portStr, err := net.SplitHostPort(addr) 62 | if err != nil { 63 | return "", 0, err 64 | } 65 | portInt, err := strconv.ParseUint(portStr, 10, 16) 66 | if err != nil { 67 | return "", 0, err 68 | } 69 | port = uint16(portInt) 70 | return 71 | } 72 | -------------------------------------------------------------------------------- /parse.go: -------------------------------------------------------------------------------- 1 | package socks 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | "net/url" 7 | "time" 8 | ) 9 | 10 | type ( 11 | config struct { 12 | Proto int 13 | Host string 14 | Auth *auth 15 | Timeout time.Duration 16 | } 17 | auth struct { 18 | Username string 19 | Password string 20 | } 21 | ) 22 | 23 | func parse(proxyURI string) (*config, error) { 24 | uri, err := url.Parse(proxyURI) 25 | if err != nil { 26 | return nil, err 27 | } 28 | cfg := &config{} 29 | switch uri.Scheme { 30 | case "socks4": 31 | cfg.Proto = SOCKS4 32 | case "socks4a": 33 | cfg.Proto = SOCKS4A 34 | case "socks5": 35 | cfg.Proto = SOCKS5 36 | default: 37 | return nil, fmt.Errorf("unknown SOCKS protocol %s", uri.Scheme) 38 | } 39 | cfg.Host = uri.Host 40 | user := uri.User.Username() 41 | password, _ := uri.User.Password() 42 | if user != "" || password != "" { 43 | if user == "" || password == "" || len(user) > 255 || len(password) > 255 { 44 | return nil, errors.New("invalid user name or password") 45 | } 46 | cfg.Auth = &auth{ 47 | Username: user, 48 | Password: password, 49 | } 50 | } 51 | query := uri.Query() 52 | timeout := query.Get("timeout") 53 | if timeout != "" { 54 | var err error 55 | cfg.Timeout, err = time.ParseDuration(timeout) 56 | if err != nil { 57 | return nil, err 58 | } 59 | } 60 | return cfg, nil 61 | } 62 | -------------------------------------------------------------------------------- /parse_test.go: -------------------------------------------------------------------------------- 1 | package socks 2 | 3 | import ( 4 | "reflect" 5 | "testing" 6 | "time" 7 | ) 8 | 9 | func TestParse(t *testing.T) { 10 | t.Parallel() 11 | testcases := []struct { 12 | name string 13 | uri string 14 | cfg config 15 | }{ 16 | { 17 | name: "full config", 18 | uri: "socks5://u1:p1@127.0.0.1:8080?timeout=2s", 19 | cfg: config{ 20 | Proto: SOCKS5, 21 | Auth: &auth{ 22 | Username: "u1", 23 | Password: "p1", 24 | }, 25 | Host: "127.0.0.1:8080", 26 | Timeout: 2 * time.Second, 27 | }, 28 | }, 29 | { 30 | name: "simple socks5", 31 | uri: "socks5://127.0.0.1:8080", 32 | cfg: config{ 33 | Proto: SOCKS5, 34 | Host: "127.0.0.1:8080", 35 | }, 36 | }, 37 | } 38 | for _, tc := range testcases { 39 | tc := tc 40 | t.Run(tc.name, func(t *testing.T) { 41 | t.Parallel() 42 | cfg, err := parse(tc.uri) 43 | if err != nil { 44 | t.Fatal(err) 45 | } 46 | if !reflect.DeepEqual(cfg, &tc.cfg) { 47 | t.Fatalf("expect %v got %v", tc.cfg, cfg) 48 | } 49 | }) 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /socks.go: -------------------------------------------------------------------------------- 1 | // Copyright 2012, Hailiang Wang. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | /* 6 | Package socks implements a SOCKS (SOCKS4, SOCKS4A and SOCKS5) proxy client. 7 | 8 | A complete example using this package: 9 | package main 10 | 11 | import ( 12 | "h12.io/socks" 13 | "fmt" 14 | "net/http" 15 | "io/ioutil" 16 | ) 17 | 18 | func main() { 19 | dialSocksProxy := socks.Dial("socks5://127.0.0.1:1080?timeout=5s") 20 | tr := &http.Transport{Dial: dialSocksProxy} 21 | httpClient := &http.Client{Transport: tr} 22 | 23 | bodyText, err := TestHttpsGet(httpClient, "https://h12.io/about") 24 | if err != nil { 25 | fmt.Println(err.Error()) 26 | } 27 | fmt.Print(bodyText) 28 | } 29 | 30 | func TestHttpsGet(c *http.Client, url string) (bodyText string, err error) { 31 | resp, err := c.Get(url) 32 | if err != nil { return } 33 | defer resp.Body.Close() 34 | 35 | body, err := ioutil.ReadAll(resp.Body) 36 | if err != nil { return } 37 | bodyText = string(body) 38 | return 39 | } 40 | */ 41 | package socks // import "h12.io/socks" 42 | 43 | import ( 44 | "fmt" 45 | "net" 46 | ) 47 | 48 | // Constants to choose which version of SOCKS protocol to use. 49 | const ( 50 | SOCKS4 = iota 51 | SOCKS4A 52 | SOCKS5 53 | ) 54 | 55 | // Dial returns the dial function to be used in http.Transport object. 56 | // Argument proxyURI should be in the format: "socks5://user:password@127.0.0.1:1080?timeout=5s". 57 | // The protocol could be socks5, socks4 and socks4a. 58 | func Dial(proxyURI string) func(string, string) (net.Conn, error) { 59 | cfg, err := parse(proxyURI) 60 | if err != nil { 61 | return dialError(err) 62 | } 63 | return cfg.dialFunc() 64 | } 65 | 66 | // DialSocksProxy returns the dial function to be used in http.Transport object. 67 | // Argument socksType should be one of SOCKS4, SOCKS4A and SOCKS5. 68 | // Argument proxy should be in this format "127.0.0.1:1080". 69 | func DialSocksProxy(socksType int, proxy string) func(string, string) (net.Conn, error) { 70 | return (&config{Proto: socksType, Host: proxy}).dialFunc() 71 | } 72 | 73 | func (c *config) dialFunc() func(string, string) (net.Conn, error) { 74 | switch c.Proto { 75 | case SOCKS5: 76 | return func(_, targetAddr string) (conn net.Conn, err error) { 77 | return c.dialSocks5(targetAddr) 78 | } 79 | case SOCKS4, SOCKS4A: 80 | return func(_, targetAddr string) (conn net.Conn, err error) { 81 | return c.dialSocks4(targetAddr) 82 | } 83 | } 84 | return dialError(fmt.Errorf("unknown SOCKS protocol %v", c.Proto)) 85 | } 86 | 87 | func dialError(err error) func(string, string) (net.Conn, error) { 88 | return func(_, _ string) (net.Conn, error) { 89 | return nil, err 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /socks4.go: -------------------------------------------------------------------------------- 1 | package socks 2 | 3 | import ( 4 | "errors" 5 | "net" 6 | "time" 7 | ) 8 | 9 | func (cfg *config) dialSocks4(targetAddr string) (_ net.Conn, err error) { 10 | socksType := cfg.Proto 11 | proxy := cfg.Host 12 | 13 | // dial TCP 14 | conn, err := net.DialTimeout("tcp", proxy, cfg.Timeout) 15 | if err != nil { 16 | return nil, err 17 | } 18 | defer func() { 19 | if err != nil { 20 | conn.Close() 21 | } 22 | }() 23 | 24 | // connection request 25 | host, port, err := splitHostPort(targetAddr) 26 | if err != nil { 27 | return nil, err 28 | } 29 | ip := net.IPv4(0, 0, 0, 1).To4() 30 | if socksType == SOCKS4 { 31 | ip, err = lookupIPv4(host) 32 | if err != nil { 33 | return nil, err 34 | } 35 | } 36 | req := []byte{ 37 | 4, // version number 38 | 1, // command CONNECT 39 | byte(port >> 8), // higher byte of destination port 40 | byte(port), // lower byte of destination port (big endian) 41 | ip[0], ip[1], ip[2], ip[3], // special invalid IP address to indicate the host name is provided 42 | 0, // user id is empty, anonymous proxy only 43 | } 44 | if socksType == SOCKS4A { 45 | req = append(req, []byte(host+"\x00")...) 46 | } 47 | 48 | resp, err := cfg.sendReceive(conn, req) 49 | if err != nil { 50 | return nil, err 51 | } else if len(resp) != 8 { 52 | return nil, errors.New("server does not respond properly") 53 | } 54 | switch resp[1] { 55 | case 90: 56 | // request granted 57 | case 91: 58 | return nil, errors.New("socks connection request rejected or failed") 59 | case 92: 60 | return nil, errors.New("socks connection request rejected because SOCKS server cannot connect to identd on the client") 61 | case 93: 62 | return nil, errors.New("socks connection request rejected because the client program and identd report different user-ids") 63 | default: 64 | return nil, errors.New("socks connection request failed, unknown error") 65 | } 66 | // clear the deadline before returning 67 | if err := conn.SetDeadline(time.Time{}); err != nil { 68 | return nil, err 69 | } 70 | return conn, nil 71 | } 72 | -------------------------------------------------------------------------------- /socks5.go: -------------------------------------------------------------------------------- 1 | package socks 2 | 3 | import ( 4 | "errors" 5 | "net" 6 | ) 7 | 8 | func (cfg *config) dialSocks5(targetAddr string) (_ net.Conn, err error) { 9 | proxy := cfg.Host 10 | 11 | // dial TCP 12 | conn, err := net.DialTimeout("tcp", proxy, cfg.Timeout) 13 | if err != nil { 14 | return nil, err 15 | } 16 | defer func() { 17 | if err != nil { 18 | conn.Close() 19 | } 20 | }() 21 | 22 | var req requestBuilder 23 | 24 | version := byte(5) // socks version 5 25 | method := byte(0) // method 0: no authentication (only anonymous access supported for now) 26 | if cfg.Auth != nil { 27 | method = 2 // method 2: username/password 28 | } 29 | 30 | // version identifier/method selection request 31 | req.add( 32 | version, // socks version 33 | 1, // number of methods 34 | method, 35 | ) 36 | 37 | resp, err := cfg.sendReceive(conn, req.Bytes()) 38 | if err != nil { 39 | return nil, err 40 | } else if len(resp) != 2 { 41 | return nil, errors.New("server does not respond properly") 42 | } else if resp[0] != 5 { 43 | return nil, errors.New("server does not support Socks 5") 44 | } else if resp[1] != method { 45 | return nil, errors.New("socks method negotiation failed") 46 | } 47 | if cfg.Auth != nil { 48 | version := byte(1) // user/password version 1 49 | req.Reset() 50 | req.add( 51 | version, // user/password version 52 | byte(len(cfg.Auth.Username)), // length of username 53 | ) 54 | req.add([]byte(cfg.Auth.Username)...) 55 | req.add(byte(len(cfg.Auth.Password))) 56 | req.add([]byte(cfg.Auth.Password)...) 57 | resp, err := cfg.sendReceive(conn, req.Bytes()) 58 | if err != nil { 59 | return nil, err 60 | } else if len(resp) != 2 { 61 | return nil, errors.New("server does not respond properly") 62 | } else if resp[0] != version { 63 | return nil, errors.New("server does not support user/password version 1") 64 | } else if resp[1] != 0 { // not success 65 | return nil, errors.New("user/password login failed") 66 | } 67 | } 68 | 69 | // detail request 70 | host, port, err := splitHostPort(targetAddr) 71 | if err != nil { 72 | return nil, err 73 | } 74 | req.Reset() 75 | req.add( 76 | 5, // version number 77 | 1, // connect command 78 | 0, // reserved, must be zero 79 | 3, // address type, 3 means domain name 80 | byte(len(host)), // address length 81 | ) 82 | req.add([]byte(host)...) 83 | req.add( 84 | byte(port>>8), // higher byte of destination port 85 | byte(port), // lower byte of destination port (big endian) 86 | ) 87 | resp, err = cfg.sendReceive(conn, req.Bytes()) 88 | if err != nil { 89 | return 90 | } else if len(resp) != 10 { 91 | return nil, errors.New("server does not respond properly") 92 | } else if resp[1] != 0 { 93 | return nil, errors.New("can't complete SOCKS5 connection") 94 | } 95 | 96 | return conn, nil 97 | } 98 | -------------------------------------------------------------------------------- /socks5_test.go: -------------------------------------------------------------------------------- 1 | package socks 2 | 3 | import ( 4 | "fmt" 5 | "io/ioutil" 6 | "log" 7 | "net" 8 | "net/http" 9 | "runtime" 10 | "strconv" 11 | "testing" 12 | "time" 13 | 14 | socks5 "github.com/h12w/go-socks5" 15 | "github.com/phayes/freeport" 16 | ) 17 | 18 | var httpTestServer = func() *http.Server { 19 | var err error 20 | httpTestPort, err := freeport.GetFreePort() 21 | if err != nil { 22 | panic(err) 23 | } 24 | s := &http.Server{ 25 | Addr: ":" + strconv.Itoa(httpTestPort), 26 | Handler: http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { 27 | w.Write([]byte("hello")) 28 | }), 29 | ReadTimeout: 10 * time.Second, 30 | WriteTimeout: 10 * time.Second, 31 | MaxHeaderBytes: 1 << 20, 32 | } 33 | go s.ListenAndServe() 34 | runtime.Gosched() 35 | tcpReady(httpTestPort, 2*time.Second) 36 | return s 37 | }() 38 | 39 | func newTestSocksServer(withAuth bool) (port int) { 40 | authenticator := socks5.Authenticator(socks5.NoAuthAuthenticator{}) 41 | if withAuth { 42 | authenticator = socks5.UserPassAuthenticator{ 43 | Credentials: socks5.StaticCredentials{ 44 | "test_user": "test_pass", 45 | }, 46 | } 47 | } 48 | conf := &socks5.Config{ 49 | Logger: log.New(ioutil.Discard, "", log.LstdFlags), 50 | AuthMethods: []socks5.Authenticator{ 51 | authenticator, 52 | }, 53 | } 54 | 55 | srv, err := socks5.New(conf) 56 | if err != nil { 57 | panic(err) 58 | } 59 | 60 | socksTestPort, err := freeport.GetFreePort() 61 | if err != nil { 62 | panic(err) 63 | } 64 | 65 | go func() { 66 | if err := srv.ListenAndServe("tcp", "0.0.0.0:"+strconv.Itoa(socksTestPort)); err != nil { 67 | panic(err) 68 | } 69 | }() 70 | runtime.Gosched() 71 | tcpReady(socksTestPort, 2*time.Second) 72 | return socksTestPort 73 | } 74 | 75 | func TestSocks5Anonymous(t *testing.T) { 76 | socksTestPort := newTestSocksServer(false) 77 | dialSocksProxy := Dial(fmt.Sprintf("socks5://127.0.0.1:%d?timeout=5s", socksTestPort)) 78 | tr := &http.Transport{Dial: dialSocksProxy} 79 | httpClient := &http.Client{Transport: tr} 80 | resp, err := httpClient.Get(fmt.Sprintf("http://localhost" + httpTestServer.Addr)) 81 | if err != nil { 82 | panic(err) 83 | } 84 | defer resp.Body.Close() 85 | respBody, err := ioutil.ReadAll(resp.Body) 86 | if err != nil { 87 | panic(err) 88 | } 89 | if string(respBody) != "hello" { 90 | t.Fatalf("expect response hello but got %s", respBody) 91 | } 92 | } 93 | 94 | func TestSocks5Auth(t *testing.T) { 95 | socksTestPort := newTestSocksServer(true) 96 | dialSocksProxy := Dial(fmt.Sprintf("socks5://test_user:test_pass@127.0.0.1:%d?timeout=5s", socksTestPort)) 97 | tr := &http.Transport{Dial: dialSocksProxy} 98 | httpClient := &http.Client{Transport: tr} 99 | resp, err := httpClient.Get(fmt.Sprintf("http://localhost" + httpTestServer.Addr)) 100 | if err != nil { 101 | panic(err) 102 | } 103 | defer resp.Body.Close() 104 | respBody, err := ioutil.ReadAll(resp.Body) 105 | if err != nil { 106 | panic(err) 107 | } 108 | if string(respBody) != "hello" { 109 | t.Fatalf("expect response hello but got %s", respBody) 110 | } 111 | } 112 | 113 | func tcpReady(port int, timeout time.Duration) { 114 | conn, err := net.DialTimeout("tcp", "127.0.0.1:"+strconv.Itoa(port), timeout) 115 | if err != nil { 116 | panic(err) 117 | } 118 | conn.Close() 119 | } 120 | -------------------------------------------------------------------------------- /spec/SOCKS4.protocol.txt: -------------------------------------------------------------------------------- 1 | SOCKS: A protocol for TCP proxy across firewalls 2 | 3 | Ying-Da Lee 4 | yingda@best.com or yingda@esd.sgi.com 5 | 6 | SOCKS was originally developed by David Koblas and subsequently modified 7 | and extended by me to its current running version -- version 4. It is a 8 | protocol that relays TCP sessions at a firewall host to allow application 9 | users transparent access across the firewall. Because the protocol is 10 | independent of application protocols, it can be (and has been) used for 11 | many different services, such as telnet, ftp, finger, whois, gopher, WWW, 12 | etc. Access control can be applied at the beginning of each TCP session; 13 | thereafter the server simply relays the data between the client and the 14 | application server, incurring minimum processing overhead. Since SOCKS 15 | never has to know anything about the application protocol, it should also 16 | be easy for it to accommodate applications which use encryption to protect 17 | their traffic from nosey snoopers. 18 | 19 | Two operations are defined: CONNECT and BIND. 20 | 21 | 1) CONNECT 22 | 23 | The client connects to the SOCKS server and sends a CONNECT request when 24 | it wants to establish a connection to an application server. The client 25 | includes in the request packet the IP address and the port number of the 26 | destination host, and userid, in the following format. 27 | 28 | +----+----+----+----+----+----+----+----+----+----+....+----+ 29 | | VN | CD | DSTPORT | DSTIP | USERID |NULL| 30 | +----+----+----+----+----+----+----+----+----+----+....+----+ 31 | # of bytes: 1 1 2 4 variable 1 32 | 33 | VN is the SOCKS protocol version number and should be 4. CD is the 34 | SOCKS command code and should be 1 for CONNECT request. NULL is a byte 35 | of all zero bits. 36 | 37 | The SOCKS server checks to see whether such a request should be granted 38 | based on any combination of source IP address, destination IP address, 39 | destination port number, the userid, and information it may obtain by 40 | consulting IDENT, cf. RFC 1413. If the request is granted, the SOCKS 41 | server makes a connection to the specified port of the destination host. 42 | A reply packet is sent to the client when this connection is established, 43 | or when the request is rejected or the operation fails. 44 | 45 | +----+----+----+----+----+----+----+----+ 46 | | VN | CD | DSTPORT | DSTIP | 47 | +----+----+----+----+----+----+----+----+ 48 | # of bytes: 1 1 2 4 49 | 50 | VN is the version of the reply code and should be 0. CD is the result 51 | code with one of the following values: 52 | 53 | 90: request granted 54 | 91: request rejected or failed 55 | 92: request rejected becasue SOCKS server cannot connect to 56 | identd on the client 57 | 93: request rejected because the client program and identd 58 | report different user-ids 59 | 60 | The remaining fields are ignored. 61 | 62 | The SOCKS server closes its connection immediately after notifying 63 | the client of a failed or rejected request. For a successful request, 64 | the SOCKS server gets ready to relay traffic on both directions. This 65 | enables the client to do I/O on its connection as if it were directly 66 | connected to the application server. 67 | 68 | 69 | 2) BIND 70 | 71 | The client connects to the SOCKS server and sends a BIND request when 72 | it wants to prepare for an inbound connection from an application server. 73 | This should only happen after a primary connection to the application 74 | server has been established with a CONNECT. Typically, this is part of 75 | the sequence of actions: 76 | 77 | -bind(): obtain a socket 78 | -getsockname(): get the IP address and port number of the socket 79 | -listen(): ready to accept call from the application server 80 | -use the primary connection to inform the application server of 81 | the IP address and the port number that it should connect to. 82 | -accept(): accept a connection from the application server 83 | 84 | The purpose of SOCKS BIND operation is to support such a sequence 85 | but using a socket on the SOCKS server rather than on the client. 86 | 87 | The client includes in the request packet the IP address of the 88 | application server, the destination port used in the primary connection, 89 | and the userid. 90 | 91 | +----+----+----+----+----+----+----+----+----+----+....+----+ 92 | | VN | CD | DSTPORT | DSTIP | USERID |NULL| 93 | +----+----+----+----+----+----+----+----+----+----+....+----+ 94 | # of bytes: 1 1 2 4 variable 1 95 | 96 | VN is again 4 for the SOCKS protocol version number. CD must be 2 to 97 | indicate BIND request. 98 | 99 | The SOCKS server uses the client information to decide whether the 100 | request is to be granted. The reply it sends back to the client has 101 | the same format as the reply for CONNECT request, i.e., 102 | 103 | +----+----+----+----+----+----+----+----+ 104 | | VN | CD | DSTPORT | DSTIP | 105 | +----+----+----+----+----+----+----+----+ 106 | # of bytes: 1 1 2 4 107 | 108 | VN is the version of the reply code and should be 0. CD is the result 109 | code with one of the following values: 110 | 111 | 90: request granted 112 | 91: request rejected or failed 113 | 92: request rejected becasue SOCKS server cannot connect to 114 | identd on the client 115 | 93: request rejected because the client program and identd 116 | report different user-ids. 117 | 118 | However, for a granted request (CD is 90), the DSTPORT and DSTIP fields 119 | are meaningful. In that case, the SOCKS server obtains a socket to wait 120 | for an incoming connection and sends the port number and the IP address 121 | of that socket to the client in DSTPORT and DSTIP, respectively. If the 122 | DSTIP in the reply is 0 (the value of constant INADDR_ANY), then the 123 | client should replace it with the IP address of the SOCKS server to which 124 | the cleint is connected. (This happens if the SOCKS server is not a 125 | multi-homed host.) In the typical scenario, these two numbers are 126 | made available to the application client prgram via the result of the 127 | subsequent getsockname() call. The application protocol must provide a 128 | way for these two pieces of information to be sent from the client to 129 | the application server so that it can initiate the connection, which 130 | connects it to the SOCKS server rather than directly to the application 131 | client as it normally would. 132 | 133 | The SOCKS server sends a second reply packet to the client when the 134 | anticipated connection from the application server is established. 135 | The SOCKS server checks the IP address of the originating host against 136 | the value of DSTIP specified in the client's BIND request. If a mismatch 137 | is found, the CD field in the second reply is set to 91 and the SOCKS 138 | server closes both connections. If the two match, CD in the second 139 | reply is set to 90 and the SOCKS server gets ready to relay the traffic 140 | on its two connections. From then on the client does I/O on its connection 141 | to the SOCKS server as if it were directly connected to the application 142 | server. 143 | 144 | 145 | 146 | For both CONNECT and BIND operations, the server sets a time limit 147 | (2 minutes in current CSTC implementation) for the establishment of its 148 | connection with the application server. If the connection is still not 149 | establiched when the time limit expires, the server closes its connection 150 | to the client and gives up. 151 | -------------------------------------------------------------------------------- /spec/rfc1928.txt: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Network Working Group M. Leech 8 | Request for Comments: 1928 Bell-Northern Research Ltd 9 | Category: Standards Track M. Ganis 10 | International Business Machines 11 | Y. Lee 12 | NEC Systems Laboratory 13 | R. Kuris 14 | Unify Corporation 15 | D. Koblas 16 | Independent Consultant 17 | L. Jones 18 | Hewlett-Packard Company 19 | March 1996 20 | 21 | 22 | SOCKS Protocol Version 5 23 | 24 | Status of this Memo 25 | 26 | This document specifies an Internet standards track protocol for the 27 | Internet community, and requests discussion and suggestions for 28 | improvements. Please refer to the current edition of the "Internet 29 | Official Protocol Standards" (STD 1) for the standardization state 30 | and status of this protocol. Distribution of this memo is unlimited. 31 | 32 | Acknowledgments 33 | 34 | This memo describes a protocol that is an evolution of the previous 35 | version of the protocol, version 4 [1]. This new protocol stems from 36 | active discussions and prototype implementations. The key 37 | contributors are: Marcus Leech: Bell-Northern Research, David Koblas: 38 | Independent Consultant, Ying-Da Lee: NEC Systems Laboratory, LaMont 39 | Jones: Hewlett-Packard Company, Ron Kuris: Unify Corporation, Matt 40 | Ganis: International Business Machines. 41 | 42 | 1. Introduction 43 | 44 | The use of network firewalls, systems that effectively isolate an 45 | organizations internal network structure from an exterior network, 46 | such as the INTERNET is becoming increasingly popular. These 47 | firewall systems typically act as application-layer gateways between 48 | networks, usually offering controlled TELNET, FTP, and SMTP access. 49 | With the emergence of more sophisticated application layer protocols 50 | designed to facilitate global information discovery, there exists a 51 | need to provide a general framework for these protocols to 52 | transparently and securely traverse a firewall. 53 | 54 | 55 | 56 | 57 | 58 | Leech, et al Standards Track [Page 1] 59 | 60 | RFC 1928 SOCKS Protocol Version 5 March 1996 61 | 62 | 63 | There exists, also, a need for strong authentication of such 64 | traversal in as fine-grained a manner as is practical. This 65 | requirement stems from the realization that client-server 66 | relationships emerge between the networks of various organizations, 67 | and that such relationships need to be controlled and often strongly 68 | authenticated. 69 | 70 | The protocol described here is designed to provide a framework for 71 | client-server applications in both the TCP and UDP domains to 72 | conveniently and securely use the services of a network firewall. 73 | The protocol is conceptually a "shim-layer" between the application 74 | layer and the transport layer, and as such does not provide network- 75 | layer gateway services, such as forwarding of ICMP messages. 76 | 77 | 2. Existing practice 78 | 79 | There currently exists a protocol, SOCKS Version 4, that provides for 80 | unsecured firewall traversal for TCP-based client-server 81 | applications, including TELNET, FTP and the popular information- 82 | discovery protocols such as HTTP, WAIS and GOPHER. 83 | 84 | This new protocol extends the SOCKS Version 4 model to include UDP, 85 | and extends the framework to include provisions for generalized 86 | strong authentication schemes, and extends the addressing scheme to 87 | encompass domain-name and V6 IP addresses. 88 | 89 | The implementation of the SOCKS protocol typically involves the 90 | recompilation or relinking of TCP-based client applications to use 91 | the appropriate encapsulation routines in the SOCKS library. 92 | 93 | Note: 94 | 95 | Unless otherwise noted, the decimal numbers appearing in packet- 96 | format diagrams represent the length of the corresponding field, in 97 | octets. Where a given octet must take on a specific value, the 98 | syntax X'hh' is used to denote the value of the single octet in that 99 | field. When the word 'Variable' is used, it indicates that the 100 | corresponding field has a variable length defined either by an 101 | associated (one or two octet) length field, or by a data type field. 102 | 103 | 3. Procedure for TCP-based clients 104 | 105 | When a TCP-based client wishes to establish a connection to an object 106 | that is reachable only via a firewall (such determination is left up 107 | to the implementation), it must open a TCP connection to the 108 | appropriate SOCKS port on the SOCKS server system. The SOCKS service 109 | is conventionally located on TCP port 1080. If the connection 110 | request succeeds, the client enters a negotiation for the 111 | 112 | 113 | 114 | Leech, et al Standards Track [Page 2] 115 | 116 | RFC 1928 SOCKS Protocol Version 5 March 1996 117 | 118 | 119 | authentication method to be used, authenticates with the chosen 120 | method, then sends a relay request. The SOCKS server evaluates the 121 | request, and either establishes the appropriate connection or denies 122 | it. 123 | 124 | Unless otherwise noted, the decimal numbers appearing in packet- 125 | format diagrams represent the length of the corresponding field, in 126 | octets. Where a given octet must take on a specific value, the 127 | syntax X'hh' is used to denote the value of the single octet in that 128 | field. When the word 'Variable' is used, it indicates that the 129 | corresponding field has a variable length defined either by an 130 | associated (one or two octet) length field, or by a data type field. 131 | 132 | The client connects to the server, and sends a version 133 | identifier/method selection message: 134 | 135 | +----+----------+----------+ 136 | |VER | NMETHODS | METHODS | 137 | +----+----------+----------+ 138 | | 1 | 1 | 1 to 255 | 139 | +----+----------+----------+ 140 | 141 | The VER field is set to X'05' for this version of the protocol. The 142 | NMETHODS field contains the number of method identifier octets that 143 | appear in the METHODS field. 144 | 145 | The server selects from one of the methods given in METHODS, and 146 | sends a METHOD selection message: 147 | 148 | +----+--------+ 149 | |VER | METHOD | 150 | +----+--------+ 151 | | 1 | 1 | 152 | +----+--------+ 153 | 154 | If the selected METHOD is X'FF', none of the methods listed by the 155 | client are acceptable, and the client MUST close the connection. 156 | 157 | The values currently defined for METHOD are: 158 | 159 | o X'00' NO AUTHENTICATION REQUIRED 160 | o X'01' GSSAPI 161 | o X'02' USERNAME/PASSWORD 162 | o X'03' to X'7F' IANA ASSIGNED 163 | o X'80' to X'FE' RESERVED FOR PRIVATE METHODS 164 | o X'FF' NO ACCEPTABLE METHODS 165 | 166 | The client and server then enter a method-specific sub-negotiation. 167 | 168 | 169 | 170 | Leech, et al Standards Track [Page 3] 171 | 172 | RFC 1928 SOCKS Protocol Version 5 March 1996 173 | 174 | 175 | Descriptions of the method-dependent sub-negotiations appear in 176 | separate memos. 177 | 178 | Developers of new METHOD support for this protocol should contact 179 | IANA for a METHOD number. The ASSIGNED NUMBERS document should be 180 | referred to for a current list of METHOD numbers and their 181 | corresponding protocols. 182 | 183 | Compliant implementations MUST support GSSAPI and SHOULD support 184 | USERNAME/PASSWORD authentication methods. 185 | 186 | 4. Requests 187 | 188 | Once the method-dependent subnegotiation has completed, the client 189 | sends the request details. If the negotiated method includes 190 | encapsulation for purposes of integrity checking and/or 191 | confidentiality, these requests MUST be encapsulated in the method- 192 | dependent encapsulation. 193 | 194 | The SOCKS request is formed as follows: 195 | 196 | +----+-----+-------+------+----------+----------+ 197 | |VER | CMD | RSV | ATYP | DST.ADDR | DST.PORT | 198 | +----+-----+-------+------+----------+----------+ 199 | | 1 | 1 | X'00' | 1 | Variable | 2 | 200 | +----+-----+-------+------+----------+----------+ 201 | 202 | Where: 203 | 204 | o VER protocol version: X'05' 205 | o CMD 206 | o CONNECT X'01' 207 | o BIND X'02' 208 | o UDP ASSOCIATE X'03' 209 | o RSV RESERVED 210 | o ATYP address type of following address 211 | o IP V4 address: X'01' 212 | o DOMAINNAME: X'03' 213 | o IP V6 address: X'04' 214 | o DST.ADDR desired destination address 215 | o DST.PORT desired destination port in network octet 216 | order 217 | 218 | The SOCKS server will typically evaluate the request based on source 219 | and destination addresses, and return one or more reply messages, as 220 | appropriate for the request type. 221 | 222 | 223 | 224 | 225 | 226 | Leech, et al Standards Track [Page 4] 227 | 228 | RFC 1928 SOCKS Protocol Version 5 March 1996 229 | 230 | 231 | 5. Addressing 232 | 233 | In an address field (DST.ADDR, BND.ADDR), the ATYP field specifies 234 | the type of address contained within the field: 235 | 236 | o X'01' 237 | 238 | the address is a version-4 IP address, with a length of 4 octets 239 | 240 | o X'03' 241 | 242 | the address field contains a fully-qualified domain name. The first 243 | octet of the address field contains the number of octets of name that 244 | follow, there is no terminating NUL octet. 245 | 246 | o X'04' 247 | 248 | the address is a version-6 IP address, with a length of 16 octets. 249 | 250 | 6. Replies 251 | 252 | The SOCKS request information is sent by the client as soon as it has 253 | established a connection to the SOCKS server, and completed the 254 | authentication negotiations. The server evaluates the request, and 255 | returns a reply formed as follows: 256 | 257 | +----+-----+-------+------+----------+----------+ 258 | |VER | REP | RSV | ATYP | BND.ADDR | BND.PORT | 259 | +----+-----+-------+------+----------+----------+ 260 | | 1 | 1 | X'00' | 1 | Variable | 2 | 261 | +----+-----+-------+------+----------+----------+ 262 | 263 | Where: 264 | 265 | o VER protocol version: X'05' 266 | o REP Reply field: 267 | o X'00' succeeded 268 | o X'01' general SOCKS server failure 269 | o X'02' connection not allowed by ruleset 270 | o X'03' Network unreachable 271 | o X'04' Host unreachable 272 | o X'05' Connection refused 273 | o X'06' TTL expired 274 | o X'07' Command not supported 275 | o X'08' Address type not supported 276 | o X'09' to X'FF' unassigned 277 | o RSV RESERVED 278 | o ATYP address type of following address 279 | 280 | 281 | 282 | Leech, et al Standards Track [Page 5] 283 | 284 | RFC 1928 SOCKS Protocol Version 5 March 1996 285 | 286 | 287 | o IP V4 address: X'01' 288 | o DOMAINNAME: X'03' 289 | o IP V6 address: X'04' 290 | o BND.ADDR server bound address 291 | o BND.PORT server bound port in network octet order 292 | 293 | Fields marked RESERVED (RSV) must be set to X'00'. 294 | 295 | If the chosen method includes encapsulation for purposes of 296 | authentication, integrity and/or confidentiality, the replies are 297 | encapsulated in the method-dependent encapsulation. 298 | 299 | CONNECT 300 | 301 | In the reply to a CONNECT, BND.PORT contains the port number that the 302 | server assigned to connect to the target host, while BND.ADDR 303 | contains the associated IP address. The supplied BND.ADDR is often 304 | different from the IP address that the client uses to reach the SOCKS 305 | server, since such servers are often multi-homed. It is expected 306 | that the SOCKS server will use DST.ADDR and DST.PORT, and the 307 | client-side source address and port in evaluating the CONNECT 308 | request. 309 | 310 | BIND 311 | 312 | The BIND request is used in protocols which require the client to 313 | accept connections from the server. FTP is a well-known example, 314 | which uses the primary client-to-server connection for commands and 315 | status reports, but may use a server-to-client connection for 316 | transferring data on demand (e.g. LS, GET, PUT). 317 | 318 | It is expected that the client side of an application protocol will 319 | use the BIND request only to establish secondary connections after a 320 | primary connection is established using CONNECT. In is expected that 321 | a SOCKS server will use DST.ADDR and DST.PORT in evaluating the BIND 322 | request. 323 | 324 | Two replies are sent from the SOCKS server to the client during a 325 | BIND operation. The first is sent after the server creates and binds 326 | a new socket. The BND.PORT field contains the port number that the 327 | SOCKS server assigned to listen for an incoming connection. The 328 | BND.ADDR field contains the associated IP address. The client will 329 | typically use these pieces of information to notify (via the primary 330 | or control connection) the application server of the rendezvous 331 | address. The second reply occurs only after the anticipated incoming 332 | connection succeeds or fails. 333 | 334 | 335 | 336 | 337 | 338 | Leech, et al Standards Track [Page 6] 339 | 340 | RFC 1928 SOCKS Protocol Version 5 March 1996 341 | 342 | 343 | In the second reply, the BND.PORT and BND.ADDR fields contain the 344 | address and port number of the connecting host. 345 | 346 | UDP ASSOCIATE 347 | 348 | The UDP ASSOCIATE request is used to establish an association within 349 | the UDP relay process to handle UDP datagrams. The DST.ADDR and 350 | DST.PORT fields contain the address and port that the client expects 351 | to use to send UDP datagrams on for the association. The server MAY 352 | use this information to limit access to the association. If the 353 | client is not in possesion of the information at the time of the UDP 354 | ASSOCIATE, the client MUST use a port number and address of all 355 | zeros. 356 | 357 | A UDP association terminates when the TCP connection that the UDP 358 | ASSOCIATE request arrived on terminates. 359 | 360 | In the reply to a UDP ASSOCIATE request, the BND.PORT and BND.ADDR 361 | fields indicate the port number/address where the client MUST send 362 | UDP request messages to be relayed. 363 | 364 | Reply Processing 365 | 366 | When a reply (REP value other than X'00') indicates a failure, the 367 | SOCKS server MUST terminate the TCP connection shortly after sending 368 | the reply. This must be no more than 10 seconds after detecting the 369 | condition that caused a failure. 370 | 371 | If the reply code (REP value of X'00') indicates a success, and the 372 | request was either a BIND or a CONNECT, the client may now start 373 | passing data. If the selected authentication method supports 374 | encapsulation for the purposes of integrity, authentication and/or 375 | confidentiality, the data are encapsulated using the method-dependent 376 | encapsulation. Similarly, when data arrives at the SOCKS server for 377 | the client, the server MUST encapsulate the data as appropriate for 378 | the authentication method in use. 379 | 380 | 7. Procedure for UDP-based clients 381 | 382 | A UDP-based client MUST send its datagrams to the UDP relay server at 383 | the UDP port indicated by BND.PORT in the reply to the UDP ASSOCIATE 384 | request. If the selected authentication method provides 385 | encapsulation for the purposes of authenticity, integrity, and/or 386 | confidentiality, the datagram MUST be encapsulated using the 387 | appropriate encapsulation. Each UDP datagram carries a UDP request 388 | header with it: 389 | 390 | 391 | 392 | 393 | 394 | Leech, et al Standards Track [Page 7] 395 | 396 | RFC 1928 SOCKS Protocol Version 5 March 1996 397 | 398 | 399 | +----+------+------+----------+----------+----------+ 400 | |RSV | FRAG | ATYP | DST.ADDR | DST.PORT | DATA | 401 | +----+------+------+----------+----------+----------+ 402 | | 2 | 1 | 1 | Variable | 2 | Variable | 403 | +----+------+------+----------+----------+----------+ 404 | 405 | The fields in the UDP request header are: 406 | 407 | o RSV Reserved X'0000' 408 | o FRAG Current fragment number 409 | o ATYP address type of following addresses: 410 | o IP V4 address: X'01' 411 | o DOMAINNAME: X'03' 412 | o IP V6 address: X'04' 413 | o DST.ADDR desired destination address 414 | o DST.PORT desired destination port 415 | o DATA user data 416 | 417 | When a UDP relay server decides to relay a UDP datagram, it does so 418 | silently, without any notification to the requesting client. 419 | Similarly, it will drop datagrams it cannot or will not relay. When 420 | a UDP relay server receives a reply datagram from a remote host, it 421 | MUST encapsulate that datagram using the above UDP request header, 422 | and any authentication-method-dependent encapsulation. 423 | 424 | The UDP relay server MUST acquire from the SOCKS server the expected 425 | IP address of the client that will send datagrams to the BND.PORT 426 | given in the reply to UDP ASSOCIATE. It MUST drop any datagrams 427 | arriving from any source IP address other than the one recorded for 428 | the particular association. 429 | 430 | The FRAG field indicates whether or not this datagram is one of a 431 | number of fragments. If implemented, the high-order bit indicates 432 | end-of-fragment sequence, while a value of X'00' indicates that this 433 | datagram is standalone. Values between 1 and 127 indicate the 434 | fragment position within a fragment sequence. Each receiver will 435 | have a REASSEMBLY QUEUE and a REASSEMBLY TIMER associated with these 436 | fragments. The reassembly queue must be reinitialized and the 437 | associated fragments abandoned whenever the REASSEMBLY TIMER expires, 438 | or a new datagram arrives carrying a FRAG field whose value is less 439 | than the highest FRAG value processed for this fragment sequence. 440 | The reassembly timer MUST be no less than 5 seconds. It is 441 | recommended that fragmentation be avoided by applications wherever 442 | possible. 443 | 444 | Implementation of fragmentation is optional; an implementation that 445 | does not support fragmentation MUST drop any datagram whose FRAG 446 | field is other than X'00'. 447 | 448 | 449 | 450 | Leech, et al Standards Track [Page 8] 451 | 452 | RFC 1928 SOCKS Protocol Version 5 March 1996 453 | 454 | 455 | The programming interface for a SOCKS-aware UDP MUST report an 456 | available buffer space for UDP datagrams that is smaller than the 457 | actual space provided by the operating system: 458 | 459 | o if ATYP is X'01' - 10+method_dependent octets smaller 460 | o if ATYP is X'03' - 262+method_dependent octets smaller 461 | o if ATYP is X'04' - 20+method_dependent octets smaller 462 | 463 | 8. Security Considerations 464 | 465 | This document describes a protocol for the application-layer 466 | traversal of IP network firewalls. The security of such traversal is 467 | highly dependent on the particular authentication and encapsulation 468 | methods provided in a particular implementation, and selected during 469 | negotiation between SOCKS client and SOCKS server. 470 | 471 | Careful consideration should be given by the administrator to the 472 | selection of authentication methods. 473 | 474 | 9. References 475 | 476 | [1] Koblas, D., "SOCKS", Proceedings: 1992 Usenix Security Symposium. 477 | 478 | Author's Address 479 | 480 | Marcus Leech 481 | Bell-Northern Research Ltd 482 | P.O. Box 3511, Stn. C, 483 | Ottawa, ON 484 | CANADA K1Y 4H7 485 | 486 | Phone: (613) 763-9145 487 | EMail: mleech@bnr.ca 488 | 489 | 490 | 491 | 492 | 493 | 494 | 495 | 496 | 497 | 498 | 499 | 500 | 501 | 502 | 503 | 504 | 505 | 506 | Leech, et al Standards Track [Page 9] 507 | 508 | -------------------------------------------------------------------------------- /spec/rfc1929.txt: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Network Working Group M. Leech 8 | Request for Comments: 1929 Bell-Northern Research Ltd 9 | Category: Standards Track March 1996 10 | 11 | 12 | Username/Password Authentication for SOCKS V5 13 | 14 | Status of this Memo 15 | 16 | This document specifies an Internet standards track protocol for the 17 | Internet community, and requests discussion and suggestions for 18 | improvements. Please refer to the current edition of the "Internet 19 | Official Protocol Standards" (STD 1) for the standardization state 20 | and status of this protocol. Distribution of this memo is unlimited. 21 | 22 | 1. Introduction 23 | 24 | The protocol specification for SOCKS Version 5 specifies a 25 | generalized framework for the use of arbitrary authentication 26 | protocols in the initial socks connection setup. This document 27 | describes one of those protocols, as it fits into the SOCKS Version 5 28 | authentication "subnegotiation". 29 | 30 | Note: 31 | 32 | Unless otherwise noted, the decimal numbers appearing in packet- 33 | format diagrams represent the length of the corresponding field, in 34 | octets. Where a given octet must take on a specific value, the 35 | syntax X'hh' is used to denote the value of the single octet in that 36 | field. When the word 'Variable' is used, it indicates that the 37 | corresponding field has a variable length defined either by an 38 | associated (one or two octet) length field, or by a data type field. 39 | 40 | 2. Initial negotiation 41 | 42 | Once the SOCKS V5 server has started, and the client has selected the 43 | Username/Password Authentication protocol, the Username/Password 44 | subnegotiation begins. This begins with the client producing a 45 | Username/Password request: 46 | 47 | +----+------+----------+------+----------+ 48 | |VER | ULEN | UNAME | PLEN | PASSWD | 49 | +----+------+----------+------+----------+ 50 | | 1 | 1 | 1 to 255 | 1 | 1 to 255 | 51 | +----+------+----------+------+----------+ 52 | 53 | 54 | 55 | 56 | 57 | 58 | Leech Standards Track [Page 1] 59 | 60 | RFC 1929 Username Authentication for SOCKS V5 March 1996 61 | 62 | 63 | The VER field contains the current version of the subnegotiation, 64 | which is X'01'. The ULEN field contains the length of the UNAME field 65 | that follows. The UNAME field contains the username as known to the 66 | source operating system. The PLEN field contains the length of the 67 | PASSWD field that follows. The PASSWD field contains the password 68 | association with the given UNAME. 69 | 70 | The server verifies the supplied UNAME and PASSWD, and sends the 71 | following response: 72 | 73 | +----+--------+ 74 | |VER | STATUS | 75 | +----+--------+ 76 | | 1 | 1 | 77 | +----+--------+ 78 | 79 | A STATUS field of X'00' indicates success. If the server returns a 80 | `failure' (STATUS value other than X'00') status, it MUST close the 81 | connection. 82 | 83 | 3. Security Considerations 84 | 85 | This document describes a subnegotiation that provides authentication 86 | services to the SOCKS protocol. Since the request carries the 87 | password in cleartext, this subnegotiation is not recommended for 88 | environments where "sniffing" is possible and practical. 89 | 90 | 4. Author's Address 91 | 92 | Marcus Leech 93 | Bell-Northern Research Ltd 94 | P.O. Box 3511, Station C 95 | Ottawa, ON 96 | CANADA K1Y 4H7 97 | 98 | Phone: +1 613 763 9145 99 | EMail: mleech@bnr.ca 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | Leech Standards Track [Page 2] 115 | 116 | -------------------------------------------------------------------------------- /spec/socks4A.protocol.txt: -------------------------------------------------------------------------------- 1 | SOCKS 4A: A Simple Extension to SOCKS 4 Protocol 2 | 3 | Ying-Da Lee 4 | yingda@best.com or yingda@esd.sgi.com 5 | 6 | Please read SOCKS4.protocol first for an description of the version 4 7 | protocol. This extension is intended to allow the use of SOCKS on hosts 8 | which are not capable of resolving all domain names. 9 | 10 | In version 4, the client sends the following packet to the SOCKS server 11 | to request a CONNECT or a BIND operation: 12 | 13 | +----+----+----+----+----+----+----+----+----+----+....+----+ 14 | | VN | CD | DSTPORT | DSTIP | USERID |NULL| 15 | +----+----+----+----+----+----+----+----+----+----+....+----+ 16 | # of bytes: 1 1 2 4 variable 1 17 | 18 | VN is the SOCKS protocol version number and should be 4. CD is the 19 | SOCKS command code and should be 1 for CONNECT or 2 for BIND. NULL 20 | is a byte of all zero bits. 21 | 22 | For version 4A, if the client cannot resolve the destination host's 23 | domain name to find its IP address, it should set the first three bytes 24 | of DSTIP to NULL and the last byte to a non-zero value. (This corresponds 25 | to IP address 0.0.0.x, with x nonzero. As decreed by IANA -- The 26 | Internet Assigned Numbers Authority -- such an address is inadmissible 27 | as a destination IP address and thus should never occur if the client 28 | can resolve the domain name.) Following the NULL byte terminating 29 | USERID, the client must sends the destination domain name and termiantes 30 | it with another NULL byte. This is used for both CONNECT and BIND requests. 31 | 32 | A server using protocol 4A must check the DSTIP in the request packet. 33 | If it represent address 0.0.0.x with nonzero x, the server must read 34 | in the domain name that the client sends in the packet. The server 35 | should resolve the domain name and make connection to the destination 36 | host if it can. 37 | 38 | SOCKSified sockd may pass domain names that it cannot resolve to 39 | the next-hop SOCKS server. 40 | 41 | --------------------------------------------------------------------------------