pax_global_header00006660000000000000000000000064137641274440014526gustar00rootroot0000000000000052 comment=303a970fb1d1a8dbb0392e0ca1a8afc03c3b2c6a socks-1.0.2/000077500000000000000000000000001376412744400126505ustar00rootroot00000000000000socks-1.0.2/.gitignore000066400000000000000000000003741376412744400146440ustar00rootroot00000000000000# Compiled Object files, Static and Dynamic libs (Shared Objects) *.o *.a *.so # Folders _obj _test # Architecture specific extensions/prefixes *.[568vq] [568vq].out *.cgo1.go *.cgo2.c _cgo_defun.c _cgo_gotypes.go _cgo_export.* _testmain.go *.exe socks-1.0.2/LICENSE000066400000000000000000000024361376412744400136620ustar00rootroot00000000000000Copyright (c) 2012, Hailiang Wang. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. socks-1.0.2/README.md000066400000000000000000000022251376412744400141300ustar00rootroot00000000000000SOCKS ===== [![GoDoc](https://godoc.org/h12.io/socks?status.svg)](https://godoc.org/h12.io/socks) SOCKS is a SOCKS4, SOCKS4A and SOCKS5 proxy package for Go. ## Quick Start ### Get the package go get -u "h12.io/socks" ### Import the package import "h12.io/socks" ### Create a SOCKS proxy dialling function dialSocksProxy := socks.Dial("socks5://127.0.0.1:1080?timeout=5s") tr := &http.Transport{Dial: dialSocksProxy} httpClient := &http.Client{Transport: tr} ### User/password authentication dialSocksProxy := socks.Dial("socks5://user:password@127.0.0.1:1080?timeout=5s") ## Example ```go package main import ( "fmt" "io/ioutil" "log" "net/http" "h12.io/socks" ) func main() { dialSocksProxy := socks.Dial("socks5://127.0.0.1:1080?timeout=5s") tr := &http.Transport{Dial: dialSocksProxy} httpClient := &http.Client{Transport: tr} resp, err := httpClient.Get("http://www.google.com") if err != nil { log.Fatal(err) } defer resp.Body.Close() if resp.StatusCode != http.StatusOK { log.Fatal(resp.StatusCode) } buf, err := ioutil.ReadAll(resp.Body) if err != nil { log.Fatal(err) } fmt.Println(string(buf)) } ``` socks-1.0.2/go.mod000066400000000000000000000002461376412744400137600ustar00rootroot00000000000000module h12.io/socks go 1.9 require ( github.com/h12w/go-socks5 v0.0.0-20200522160539-76189e178364 github.com/phayes/freeport v0.0.0-20180830031419-95f893ade6f2 ) socks-1.0.2/go.sum000066400000000000000000000007041376412744400140040ustar00rootroot00000000000000github.com/h12w/go-socks5 v0.0.0-20200522160539-76189e178364 h1:5XxdakFhqd9dnXoAZy1Mb2R/DZ6D1e+0bGC/JhucGYI= github.com/h12w/go-socks5 v0.0.0-20200522160539-76189e178364/go.mod h1:eDJQioIyy4Yn3MVivT7rv/39gAJTrA7lgmYr8EW950c= github.com/phayes/freeport v0.0.0-20180830031419-95f893ade6f2 h1:JhzVVoYvbOACxoUmOs6V/G4D5nPVUW73rKvXxP4XUJc= github.com/phayes/freeport v0.0.0-20180830031419-95f893ade6f2/go.mod h1:iIss55rKnNBTvrwdmkUpLnDpZoAHvWaiq5+iMmen4AE= socks-1.0.2/net.go000066400000000000000000000024601376412744400137670ustar00rootroot00000000000000package socks import ( "bytes" "fmt" "net" "strconv" "time" ) type requestBuilder struct { bytes.Buffer } func (b *requestBuilder) add(data ...byte) { _, _ = b.Write(data) } func (c *config) sendReceive(conn net.Conn, req []byte) (resp []byte, err error) { if c.Timeout > 0 { if err := conn.SetWriteDeadline(time.Now().Add(c.Timeout)); err != nil { return nil, err } } _, err = conn.Write(req) if err != nil { return } resp, err = c.readAll(conn) return } func (c *config) readAll(conn net.Conn) (resp []byte, err error) { resp = make([]byte, 1024) if c.Timeout > 0 { if err := conn.SetReadDeadline(time.Now().Add(c.Timeout)); err != nil { return nil, err } } n, err := conn.Read(resp) resp = resp[:n] return } func lookupIPv4(host string) (net.IP, error) { ips, err := net.LookupIP(host) if err != nil { return nil, err } for _, ip := range ips { ipv4 := ip.To4() if ipv4 == nil { continue } return ipv4, nil } return nil, fmt.Errorf("no IPv4 address found for host: %s", host) } func splitHostPort(addr string) (host string, port uint16, err error) { host, portStr, err := net.SplitHostPort(addr) if err != nil { return "", 0, err } portInt, err := strconv.ParseUint(portStr, 10, 16) if err != nil { return "", 0, err } port = uint16(portInt) return } socks-1.0.2/parse.go000066400000000000000000000021151376412744400143100ustar00rootroot00000000000000package socks import ( "errors" "fmt" "net/url" "time" ) type ( config struct { Proto int Host string Auth *auth Timeout time.Duration } auth struct { Username string Password string } ) func parse(proxyURI string) (*config, error) { uri, err := url.Parse(proxyURI) if err != nil { return nil, err } cfg := &config{} switch uri.Scheme { case "socks4": cfg.Proto = SOCKS4 case "socks4a": cfg.Proto = SOCKS4A case "socks5": cfg.Proto = SOCKS5 default: return nil, fmt.Errorf("unknown SOCKS protocol %s", uri.Scheme) } cfg.Host = uri.Host user := uri.User.Username() password, _ := uri.User.Password() if user != "" || password != "" { if user == "" || password == "" || len(user) > 255 || len(password) > 255 { return nil, errors.New("invalid user name or password") } cfg.Auth = &auth{ Username: user, Password: password, } } query := uri.Query() timeout := query.Get("timeout") if timeout != "" { var err error cfg.Timeout, err = time.ParseDuration(timeout) if err != nil { return nil, err } } return cfg, nil } socks-1.0.2/parse_test.go000066400000000000000000000015101376412744400153450ustar00rootroot00000000000000package socks import ( "reflect" "testing" "time" ) func TestParse(t *testing.T) { t.Parallel() testcases := []struct { name string uri string cfg config }{ { name: "full config", uri: "socks5://u1:p1@127.0.0.1:8080?timeout=2s", cfg: config{ Proto: SOCKS5, Auth: &auth{ Username: "u1", Password: "p1", }, Host: "127.0.0.1:8080", Timeout: 2 * time.Second, }, }, { name: "simple socks5", uri: "socks5://127.0.0.1:8080", cfg: config{ Proto: SOCKS5, Host: "127.0.0.1:8080", }, }, } for _, tc := range testcases { tc := tc t.Run(tc.name, func(t *testing.T) { t.Parallel() cfg, err := parse(tc.uri) if err != nil { t.Fatal(err) } if !reflect.DeepEqual(cfg, &tc.cfg) { t.Fatalf("expect %v got %v", tc.cfg, cfg) } }) } } socks-1.0.2/socks.go000066400000000000000000000045531376412744400143300ustar00rootroot00000000000000// Copyright 2012, Hailiang Wang. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. /* Package socks implements a SOCKS (SOCKS4, SOCKS4A and SOCKS5) proxy client. A complete example using this package: package main import ( "h12.io/socks" "fmt" "net/http" "io/ioutil" ) func main() { dialSocksProxy := socks.Dial("socks5://127.0.0.1:1080?timeout=5s") tr := &http.Transport{Dial: dialSocksProxy} httpClient := &http.Client{Transport: tr} bodyText, err := TestHttpsGet(httpClient, "https://h12.io/about") if err != nil { fmt.Println(err.Error()) } fmt.Print(bodyText) } func TestHttpsGet(c *http.Client, url string) (bodyText string, err error) { resp, err := c.Get(url) if err != nil { return } defer resp.Body.Close() body, err := ioutil.ReadAll(resp.Body) if err != nil { return } bodyText = string(body) return } */ package socks // import "h12.io/socks" import ( "fmt" "net" ) // Constants to choose which version of SOCKS protocol to use. const ( SOCKS4 = iota SOCKS4A SOCKS5 ) // Dial returns the dial function to be used in http.Transport object. // Argument proxyURI should be in the format: "socks5://user:password@127.0.0.1:1080?timeout=5s". // The protocol could be socks5, socks4 and socks4a. func Dial(proxyURI string) func(string, string) (net.Conn, error) { cfg, err := parse(proxyURI) if err != nil { return dialError(err) } return cfg.dialFunc() } // DialSocksProxy returns the dial function to be used in http.Transport object. // Argument socksType should be one of SOCKS4, SOCKS4A and SOCKS5. // Argument proxy should be in this format "127.0.0.1:1080". func DialSocksProxy(socksType int, proxy string) func(string, string) (net.Conn, error) { return (&config{Proto: socksType, Host: proxy}).dialFunc() } func (c *config) dialFunc() func(string, string) (net.Conn, error) { switch c.Proto { case SOCKS5: return func(_, targetAddr string) (conn net.Conn, err error) { return c.dialSocks5(targetAddr) } case SOCKS4, SOCKS4A: return func(_, targetAddr string) (conn net.Conn, err error) { return c.dialSocks4(targetAddr) } } return dialError(fmt.Errorf("unknown SOCKS protocol %v", c.Proto)) } func dialError(err error) func(string, string) (net.Conn, error) { return func(_, _ string) (net.Conn, error) { return nil, err } } socks-1.0.2/socks4.go000066400000000000000000000034441376412744400144120ustar00rootroot00000000000000package socks import ( "errors" "net" "time" ) func (cfg *config) dialSocks4(targetAddr string) (_ net.Conn, err error) { socksType := cfg.Proto proxy := cfg.Host // dial TCP conn, err := net.Dial("tcp", proxy) if err != nil { return nil, err } defer func() { if err != nil { conn.Close() } }() // connection request host, port, err := splitHostPort(targetAddr) if err != nil { return nil, err } ip := net.IPv4(0, 0, 0, 1).To4() if socksType == SOCKS4 { ip, err = lookupIPv4(host) if err != nil { return nil, err } } req := []byte{ 4, // version number 1, // command CONNECT byte(port >> 8), // higher byte of destination port byte(port), // lower byte of destination port (big endian) ip[0], ip[1], ip[2], ip[3], // special invalid IP address to indicate the host name is provided 0, // user id is empty, anonymous proxy only } if socksType == SOCKS4A { req = append(req, []byte(host+"\x00")...) } resp, err := cfg.sendReceive(conn, req) if err != nil { return nil, err } else if len(resp) != 8 { return nil, errors.New("server does not respond properly") } switch resp[1] { case 90: // request granted case 91: return nil, errors.New("socks connection request rejected or failed") case 92: return nil, errors.New("socks connection request rejected because SOCKS server cannot connect to identd on the client") case 93: return nil, errors.New("socks connection request rejected because the client program and identd report different user-ids") default: return nil, errors.New("socks connection request failed, unknown error") } // clear the deadline before returning if err := conn.SetDeadline(time.Time{}); err != nil { return nil, err } return conn, nil } socks-1.0.2/socks5.go000066400000000000000000000047011376412744400144100ustar00rootroot00000000000000package socks import ( "errors" "net" ) func (cfg *config) dialSocks5(targetAddr string) (_ net.Conn, err error) { proxy := cfg.Host // dial TCP conn, err := net.Dial("tcp", proxy) if err != nil { return nil, err } defer func() { if err != nil { conn.Close() } }() var req requestBuilder version := byte(5) // socks version 5 method := byte(0) // method 0: no authentication (only anonymous access supported for now) if cfg.Auth != nil { method = 2 // method 2: username/password } // version identifier/method selection request req.add( version, // socks version 1, // number of methods method, ) resp, err := cfg.sendReceive(conn, req.Bytes()) if err != nil { return nil, err } else if len(resp) != 2 { return nil, errors.New("server does not respond properly") } else if resp[0] != 5 { return nil, errors.New("server does not support Socks 5") } else if resp[1] != method { return nil, errors.New("socks method negotiation failed") } if cfg.Auth != nil { version := byte(1) // user/password version 1 req.Reset() req.add( version, // user/password version byte(len(cfg.Auth.Username)), // length of username ) req.add([]byte(cfg.Auth.Username)...) req.add(byte(len(cfg.Auth.Password))) req.add([]byte(cfg.Auth.Password)...) resp, err := cfg.sendReceive(conn, req.Bytes()) if err != nil { return nil, err } else if len(resp) != 2 { return nil, errors.New("server does not respond properly") } else if resp[0] != version { return nil, errors.New("server does not support user/password version 1") } else if resp[1] != 0 { // not success return nil, errors.New("user/password login failed") } } // detail request host, port, err := splitHostPort(targetAddr) if err != nil { return nil, err } req.Reset() req.add( 5, // version number 1, // connect command 0, // reserved, must be zero 3, // address type, 3 means domain name byte(len(host)), // address length ) req.add([]byte(host)...) req.add( byte(port>>8), // higher byte of destination port byte(port), // lower byte of destination port (big endian) ) resp, err = cfg.sendReceive(conn, req.Bytes()) if err != nil { return } else if len(resp) != 10 { return nil, errors.New("server does not respond properly") } else if resp[1] != 0 { return nil, errors.New("can't complete SOCKS5 connection") } return conn, nil } socks-1.0.2/socks5_test.go000066400000000000000000000053631376412744400154540ustar00rootroot00000000000000package socks import ( "fmt" "io/ioutil" "log" "net" "net/http" "runtime" "strconv" "testing" "time" socks5 "github.com/h12w/go-socks5" "github.com/phayes/freeport" ) var httpTestServer = func() *http.Server { var err error httpTestPort, err := freeport.GetFreePort() if err != nil { panic(err) } s := &http.Server{ Addr: ":" + strconv.Itoa(httpTestPort), Handler: http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { w.Write([]byte("hello")) }), ReadTimeout: 10 * time.Second, WriteTimeout: 10 * time.Second, MaxHeaderBytes: 1 << 20, } go s.ListenAndServe() runtime.Gosched() tcpReady(httpTestPort, 2*time.Second) return s }() func newTestSocksServer(withAuth bool) (port int) { authenticator := socks5.Authenticator(socks5.NoAuthAuthenticator{}) if withAuth { authenticator = socks5.UserPassAuthenticator{ Credentials: socks5.StaticCredentials{ "test_user": "test_pass", }, } } conf := &socks5.Config{ Logger: log.New(ioutil.Discard, "", log.LstdFlags), AuthMethods: []socks5.Authenticator{ authenticator, }, } srv, err := socks5.New(conf) if err != nil { panic(err) } socksTestPort, err := freeport.GetFreePort() if err != nil { panic(err) } go func() { if err := srv.ListenAndServe("tcp", "0.0.0.0:"+strconv.Itoa(socksTestPort)); err != nil { panic(err) } }() runtime.Gosched() tcpReady(socksTestPort, 2*time.Second) return socksTestPort } func TestSocks5Anonymous(t *testing.T) { socksTestPort := newTestSocksServer(false) dialSocksProxy := Dial(fmt.Sprintf("socks5://127.0.0.1:%d?timeout=5s", socksTestPort)) tr := &http.Transport{Dial: dialSocksProxy} httpClient := &http.Client{Transport: tr} resp, err := httpClient.Get(fmt.Sprintf("http://localhost" + httpTestServer.Addr)) if err != nil { panic(err) } defer resp.Body.Close() respBody, err := ioutil.ReadAll(resp.Body) if err != nil { panic(err) } if string(respBody) != "hello" { t.Fatalf("expect response hello but got %s", respBody) } } func TestSocks5Auth(t *testing.T) { socksTestPort := newTestSocksServer(true) dialSocksProxy := Dial(fmt.Sprintf("socks5://test_user:test_pass@127.0.0.1:%d?timeout=5s", socksTestPort)) tr := &http.Transport{Dial: dialSocksProxy} httpClient := &http.Client{Transport: tr} resp, err := httpClient.Get(fmt.Sprintf("http://localhost" + httpTestServer.Addr)) if err != nil { panic(err) } defer resp.Body.Close() respBody, err := ioutil.ReadAll(resp.Body) if err != nil { panic(err) } if string(respBody) != "hello" { t.Fatalf("expect response hello but got %s", respBody) } } func tcpReady(port int, timeout time.Duration) { conn, err := net.DialTimeout("tcp", "127.0.0.1:"+strconv.Itoa(port), timeout) if err != nil { panic(err) } conn.Close() } socks-1.0.2/spec/000077500000000000000000000000001376412744400136025ustar00rootroot00000000000000socks-1.0.2/spec/SOCKS4.protocol.txt000066400000000000000000000155111376412744400171540ustar00rootroot00000000000000 SOCKS: A protocol for TCP proxy across firewalls Ying-Da Lee yingda@best.com or yingda@esd.sgi.com SOCKS was originally developed by David Koblas and subsequently modified and extended by me to its current running version -- version 4. It is a protocol that relays TCP sessions at a firewall host to allow application users transparent access across the firewall. Because the protocol is independent of application protocols, it can be (and has been) used for many different services, such as telnet, ftp, finger, whois, gopher, WWW, etc. Access control can be applied at the beginning of each TCP session; thereafter the server simply relays the data between the client and the application server, incurring minimum processing overhead. Since SOCKS never has to know anything about the application protocol, it should also be easy for it to accommodate applications which use encryption to protect their traffic from nosey snoopers. Two operations are defined: CONNECT and BIND. 1) CONNECT The client connects to the SOCKS server and sends a CONNECT request when it wants to establish a connection to an application server. The client includes in the request packet the IP address and the port number of the destination host, and userid, in the following format. +----+----+----+----+----+----+----+----+----+----+....+----+ | VN | CD | DSTPORT | DSTIP | USERID |NULL| +----+----+----+----+----+----+----+----+----+----+....+----+ # of bytes: 1 1 2 4 variable 1 VN is the SOCKS protocol version number and should be 4. CD is the SOCKS command code and should be 1 for CONNECT request. NULL is a byte of all zero bits. The SOCKS server checks to see whether such a request should be granted based on any combination of source IP address, destination IP address, destination port number, the userid, and information it may obtain by consulting IDENT, cf. RFC 1413. If the request is granted, the SOCKS server makes a connection to the specified port of the destination host. A reply packet is sent to the client when this connection is established, or when the request is rejected or the operation fails. +----+----+----+----+----+----+----+----+ | VN | CD | DSTPORT | DSTIP | +----+----+----+----+----+----+----+----+ # of bytes: 1 1 2 4 VN is the version of the reply code and should be 0. CD is the result code with one of the following values: 90: request granted 91: request rejected or failed 92: request rejected becasue SOCKS server cannot connect to identd on the client 93: request rejected because the client program and identd report different user-ids The remaining fields are ignored. The SOCKS server closes its connection immediately after notifying the client of a failed or rejected request. For a successful request, the SOCKS server gets ready to relay traffic on both directions. This enables the client to do I/O on its connection as if it were directly connected to the application server. 2) BIND The client connects to the SOCKS server and sends a BIND request when it wants to prepare for an inbound connection from an application server. This should only happen after a primary connection to the application server has been established with a CONNECT. Typically, this is part of the sequence of actions: -bind(): obtain a socket -getsockname(): get the IP address and port number of the socket -listen(): ready to accept call from the application server -use the primary connection to inform the application server of the IP address and the port number that it should connect to. -accept(): accept a connection from the application server The purpose of SOCKS BIND operation is to support such a sequence but using a socket on the SOCKS server rather than on the client. The client includes in the request packet the IP address of the application server, the destination port used in the primary connection, and the userid. +----+----+----+----+----+----+----+----+----+----+....+----+ | VN | CD | DSTPORT | DSTIP | USERID |NULL| +----+----+----+----+----+----+----+----+----+----+....+----+ # of bytes: 1 1 2 4 variable 1 VN is again 4 for the SOCKS protocol version number. CD must be 2 to indicate BIND request. The SOCKS server uses the client information to decide whether the request is to be granted. The reply it sends back to the client has the same format as the reply for CONNECT request, i.e., +----+----+----+----+----+----+----+----+ | VN | CD | DSTPORT | DSTIP | +----+----+----+----+----+----+----+----+ # of bytes: 1 1 2 4 VN is the version of the reply code and should be 0. CD is the result code with one of the following values: 90: request granted 91: request rejected or failed 92: request rejected becasue SOCKS server cannot connect to identd on the client 93: request rejected because the client program and identd report different user-ids. However, for a granted request (CD is 90), the DSTPORT and DSTIP fields are meaningful. In that case, the SOCKS server obtains a socket to wait for an incoming connection and sends the port number and the IP address of that socket to the client in DSTPORT and DSTIP, respectively. If the DSTIP in the reply is 0 (the value of constant INADDR_ANY), then the client should replace it with the IP address of the SOCKS server to which the cleint is connected. (This happens if the SOCKS server is not a multi-homed host.) In the typical scenario, these two numbers are made available to the application client prgram via the result of the subsequent getsockname() call. The application protocol must provide a way for these two pieces of information to be sent from the client to the application server so that it can initiate the connection, which connects it to the SOCKS server rather than directly to the application client as it normally would. The SOCKS server sends a second reply packet to the client when the anticipated connection from the application server is established. The SOCKS server checks the IP address of the originating host against the value of DSTIP specified in the client's BIND request. If a mismatch is found, the CD field in the second reply is set to 91 and the SOCKS server closes both connections. If the two match, CD in the second reply is set to 90 and the SOCKS server gets ready to relay the traffic on its two connections. From then on the client does I/O on its connection to the SOCKS server as if it were directly connected to the application server. For both CONNECT and BIND operations, the server sets a time limit (2 minutes in current CSTC implementation) for the establishment of its connection with the application server. If the connection is still not establiched when the time limit expires, the server closes its connection to the client and gives up. socks-1.0.2/spec/rfc1928.txt000066400000000000000000000464351376412744400154550ustar00rootroot00000000000000 Network Working Group M. Leech Request for Comments: 1928 Bell-Northern Research Ltd Category: Standards Track M. Ganis International Business Machines Y. Lee NEC Systems Laboratory R. Kuris Unify Corporation D. Koblas Independent Consultant L. Jones Hewlett-Packard Company March 1996 SOCKS Protocol Version 5 Status of this Memo This document specifies an Internet standards track protocol for the Internet community, and requests discussion and suggestions for improvements. Please refer to the current edition of the "Internet Official Protocol Standards" (STD 1) for the standardization state and status of this protocol. Distribution of this memo is unlimited. Acknowledgments This memo describes a protocol that is an evolution of the previous version of the protocol, version 4 [1]. This new protocol stems from active discussions and prototype implementations. The key contributors are: Marcus Leech: Bell-Northern Research, David Koblas: Independent Consultant, Ying-Da Lee: NEC Systems Laboratory, LaMont Jones: Hewlett-Packard Company, Ron Kuris: Unify Corporation, Matt Ganis: International Business Machines. 1. Introduction The use of network firewalls, systems that effectively isolate an organizations internal network structure from an exterior network, such as the INTERNET is becoming increasingly popular. These firewall systems typically act as application-layer gateways between networks, usually offering controlled TELNET, FTP, and SMTP access. With the emergence of more sophisticated application layer protocols designed to facilitate global information discovery, there exists a need to provide a general framework for these protocols to transparently and securely traverse a firewall. Leech, et al Standards Track [Page 1] RFC 1928 SOCKS Protocol Version 5 March 1996 There exists, also, a need for strong authentication of such traversal in as fine-grained a manner as is practical. This requirement stems from the realization that client-server relationships emerge between the networks of various organizations, and that such relationships need to be controlled and often strongly authenticated. The protocol described here is designed to provide a framework for client-server applications in both the TCP and UDP domains to conveniently and securely use the services of a network firewall. The protocol is conceptually a "shim-layer" between the application layer and the transport layer, and as such does not provide network- layer gateway services, such as forwarding of ICMP messages. 2. Existing practice There currently exists a protocol, SOCKS Version 4, that provides for unsecured firewall traversal for TCP-based client-server applications, including TELNET, FTP and the popular information- discovery protocols such as HTTP, WAIS and GOPHER. This new protocol extends the SOCKS Version 4 model to include UDP, and extends the framework to include provisions for generalized strong authentication schemes, and extends the addressing scheme to encompass domain-name and V6 IP addresses. The implementation of the SOCKS protocol typically involves the recompilation or relinking of TCP-based client applications to use the appropriate encapsulation routines in the SOCKS library. Note: Unless otherwise noted, the decimal numbers appearing in packet- format diagrams represent the length of the corresponding field, in octets. Where a given octet must take on a specific value, the syntax X'hh' is used to denote the value of the single octet in that field. When the word 'Variable' is used, it indicates that the corresponding field has a variable length defined either by an associated (one or two octet) length field, or by a data type field. 3. Procedure for TCP-based clients When a TCP-based client wishes to establish a connection to an object that is reachable only via a firewall (such determination is left up to the implementation), it must open a TCP connection to the appropriate SOCKS port on the SOCKS server system. The SOCKS service is conventionally located on TCP port 1080. If the connection request succeeds, the client enters a negotiation for the Leech, et al Standards Track [Page 2] RFC 1928 SOCKS Protocol Version 5 March 1996 authentication method to be used, authenticates with the chosen method, then sends a relay request. The SOCKS server evaluates the request, and either establishes the appropriate connection or denies it. Unless otherwise noted, the decimal numbers appearing in packet- format diagrams represent the length of the corresponding field, in octets. Where a given octet must take on a specific value, the syntax X'hh' is used to denote the value of the single octet in that field. When the word 'Variable' is used, it indicates that the corresponding field has a variable length defined either by an associated (one or two octet) length field, or by a data type field. The client connects to the server, and sends a version identifier/method selection message: +----+----------+----------+ |VER | NMETHODS | METHODS | +----+----------+----------+ | 1 | 1 | 1 to 255 | +----+----------+----------+ The VER field is set to X'05' for this version of the protocol. The NMETHODS field contains the number of method identifier octets that appear in the METHODS field. The server selects from one of the methods given in METHODS, and sends a METHOD selection message: +----+--------+ |VER | METHOD | +----+--------+ | 1 | 1 | +----+--------+ If the selected METHOD is X'FF', none of the methods listed by the client are acceptable, and the client MUST close the connection. The values currently defined for METHOD are: o X'00' NO AUTHENTICATION REQUIRED o X'01' GSSAPI o X'02' USERNAME/PASSWORD o X'03' to X'7F' IANA ASSIGNED o X'80' to X'FE' RESERVED FOR PRIVATE METHODS o X'FF' NO ACCEPTABLE METHODS The client and server then enter a method-specific sub-negotiation. Leech, et al Standards Track [Page 3] RFC 1928 SOCKS Protocol Version 5 March 1996 Descriptions of the method-dependent sub-negotiations appear in separate memos. Developers of new METHOD support for this protocol should contact IANA for a METHOD number. The ASSIGNED NUMBERS document should be referred to for a current list of METHOD numbers and their corresponding protocols. Compliant implementations MUST support GSSAPI and SHOULD support USERNAME/PASSWORD authentication methods. 4. Requests Once the method-dependent subnegotiation has completed, the client sends the request details. If the negotiated method includes encapsulation for purposes of integrity checking and/or confidentiality, these requests MUST be encapsulated in the method- dependent encapsulation. The SOCKS request is formed as follows: +----+-----+-------+------+----------+----------+ |VER | CMD | RSV | ATYP | DST.ADDR | DST.PORT | +----+-----+-------+------+----------+----------+ | 1 | 1 | X'00' | 1 | Variable | 2 | +----+-----+-------+------+----------+----------+ Where: o VER protocol version: X'05' o CMD o CONNECT X'01' o BIND X'02' o UDP ASSOCIATE X'03' o RSV RESERVED o ATYP address type of following address o IP V4 address: X'01' o DOMAINNAME: X'03' o IP V6 address: X'04' o DST.ADDR desired destination address o DST.PORT desired destination port in network octet order The SOCKS server will typically evaluate the request based on source and destination addresses, and return one or more reply messages, as appropriate for the request type. Leech, et al Standards Track [Page 4] RFC 1928 SOCKS Protocol Version 5 March 1996 5. Addressing In an address field (DST.ADDR, BND.ADDR), the ATYP field specifies the type of address contained within the field: o X'01' the address is a version-4 IP address, with a length of 4 octets o X'03' the address field contains a fully-qualified domain name. The first octet of the address field contains the number of octets of name that follow, there is no terminating NUL octet. o X'04' the address is a version-6 IP address, with a length of 16 octets. 6. Replies The SOCKS request information is sent by the client as soon as it has established a connection to the SOCKS server, and completed the authentication negotiations. The server evaluates the request, and returns a reply formed as follows: +----+-----+-------+------+----------+----------+ |VER | REP | RSV | ATYP | BND.ADDR | BND.PORT | +----+-----+-------+------+----------+----------+ | 1 | 1 | X'00' | 1 | Variable | 2 | +----+-----+-------+------+----------+----------+ Where: o VER protocol version: X'05' o REP Reply field: o X'00' succeeded o X'01' general SOCKS server failure o X'02' connection not allowed by ruleset o X'03' Network unreachable o X'04' Host unreachable o X'05' Connection refused o X'06' TTL expired o X'07' Command not supported o X'08' Address type not supported o X'09' to X'FF' unassigned o RSV RESERVED o ATYP address type of following address Leech, et al Standards Track [Page 5] RFC 1928 SOCKS Protocol Version 5 March 1996 o IP V4 address: X'01' o DOMAINNAME: X'03' o IP V6 address: X'04' o BND.ADDR server bound address o BND.PORT server bound port in network octet order Fields marked RESERVED (RSV) must be set to X'00'. If the chosen method includes encapsulation for purposes of authentication, integrity and/or confidentiality, the replies are encapsulated in the method-dependent encapsulation. CONNECT In the reply to a CONNECT, BND.PORT contains the port number that the server assigned to connect to the target host, while BND.ADDR contains the associated IP address. The supplied BND.ADDR is often different from the IP address that the client uses to reach the SOCKS server, since such servers are often multi-homed. It is expected that the SOCKS server will use DST.ADDR and DST.PORT, and the client-side source address and port in evaluating the CONNECT request. BIND The BIND request is used in protocols which require the client to accept connections from the server. FTP is a well-known example, which uses the primary client-to-server connection for commands and status reports, but may use a server-to-client connection for transferring data on demand (e.g. LS, GET, PUT). It is expected that the client side of an application protocol will use the BIND request only to establish secondary connections after a primary connection is established using CONNECT. In is expected that a SOCKS server will use DST.ADDR and DST.PORT in evaluating the BIND request. Two replies are sent from the SOCKS server to the client during a BIND operation. The first is sent after the server creates and binds a new socket. The BND.PORT field contains the port number that the SOCKS server assigned to listen for an incoming connection. The BND.ADDR field contains the associated IP address. The client will typically use these pieces of information to notify (via the primary or control connection) the application server of the rendezvous address. The second reply occurs only after the anticipated incoming connection succeeds or fails. Leech, et al Standards Track [Page 6] RFC 1928 SOCKS Protocol Version 5 March 1996 In the second reply, the BND.PORT and BND.ADDR fields contain the address and port number of the connecting host. UDP ASSOCIATE The UDP ASSOCIATE request is used to establish an association within the UDP relay process to handle UDP datagrams. The DST.ADDR and DST.PORT fields contain the address and port that the client expects to use to send UDP datagrams on for the association. The server MAY use this information to limit access to the association. If the client is not in possesion of the information at the time of the UDP ASSOCIATE, the client MUST use a port number and address of all zeros. A UDP association terminates when the TCP connection that the UDP ASSOCIATE request arrived on terminates. In the reply to a UDP ASSOCIATE request, the BND.PORT and BND.ADDR fields indicate the port number/address where the client MUST send UDP request messages to be relayed. Reply Processing When a reply (REP value other than X'00') indicates a failure, the SOCKS server MUST terminate the TCP connection shortly after sending the reply. This must be no more than 10 seconds after detecting the condition that caused a failure. If the reply code (REP value of X'00') indicates a success, and the request was either a BIND or a CONNECT, the client may now start passing data. If the selected authentication method supports encapsulation for the purposes of integrity, authentication and/or confidentiality, the data are encapsulated using the method-dependent encapsulation. Similarly, when data arrives at the SOCKS server for the client, the server MUST encapsulate the data as appropriate for the authentication method in use. 7. Procedure for UDP-based clients A UDP-based client MUST send its datagrams to the UDP relay server at the UDP port indicated by BND.PORT in the reply to the UDP ASSOCIATE request. If the selected authentication method provides encapsulation for the purposes of authenticity, integrity, and/or confidentiality, the datagram MUST be encapsulated using the appropriate encapsulation. Each UDP datagram carries a UDP request header with it: Leech, et al Standards Track [Page 7] RFC 1928 SOCKS Protocol Version 5 March 1996 +----+------+------+----------+----------+----------+ |RSV | FRAG | ATYP | DST.ADDR | DST.PORT | DATA | +----+------+------+----------+----------+----------+ | 2 | 1 | 1 | Variable | 2 | Variable | +----+------+------+----------+----------+----------+ The fields in the UDP request header are: o RSV Reserved X'0000' o FRAG Current fragment number o ATYP address type of following addresses: o IP V4 address: X'01' o DOMAINNAME: X'03' o IP V6 address: X'04' o DST.ADDR desired destination address o DST.PORT desired destination port o DATA user data When a UDP relay server decides to relay a UDP datagram, it does so silently, without any notification to the requesting client. Similarly, it will drop datagrams it cannot or will not relay. When a UDP relay server receives a reply datagram from a remote host, it MUST encapsulate that datagram using the above UDP request header, and any authentication-method-dependent encapsulation. The UDP relay server MUST acquire from the SOCKS server the expected IP address of the client that will send datagrams to the BND.PORT given in the reply to UDP ASSOCIATE. It MUST drop any datagrams arriving from any source IP address other than the one recorded for the particular association. The FRAG field indicates whether or not this datagram is one of a number of fragments. If implemented, the high-order bit indicates end-of-fragment sequence, while a value of X'00' indicates that this datagram is standalone. Values between 1 and 127 indicate the fragment position within a fragment sequence. Each receiver will have a REASSEMBLY QUEUE and a REASSEMBLY TIMER associated with these fragments. The reassembly queue must be reinitialized and the associated fragments abandoned whenever the REASSEMBLY TIMER expires, or a new datagram arrives carrying a FRAG field whose value is less than the highest FRAG value processed for this fragment sequence. The reassembly timer MUST be no less than 5 seconds. It is recommended that fragmentation be avoided by applications wherever possible. Implementation of fragmentation is optional; an implementation that does not support fragmentation MUST drop any datagram whose FRAG field is other than X'00'. Leech, et al Standards Track [Page 8] RFC 1928 SOCKS Protocol Version 5 March 1996 The programming interface for a SOCKS-aware UDP MUST report an available buffer space for UDP datagrams that is smaller than the actual space provided by the operating system: o if ATYP is X'01' - 10+method_dependent octets smaller o if ATYP is X'03' - 262+method_dependent octets smaller o if ATYP is X'04' - 20+method_dependent octets smaller 8. Security Considerations This document describes a protocol for the application-layer traversal of IP network firewalls. The security of such traversal is highly dependent on the particular authentication and encapsulation methods provided in a particular implementation, and selected during negotiation between SOCKS client and SOCKS server. Careful consideration should be given by the administrator to the selection of authentication methods. 9. References [1] Koblas, D., "SOCKS", Proceedings: 1992 Usenix Security Symposium. Author's Address Marcus Leech Bell-Northern Research Ltd P.O. Box 3511, Stn. C, Ottawa, ON CANADA K1Y 4H7 Phone: (613) 763-9145 EMail: mleech@bnr.ca Leech, et al Standards Track [Page 9] socks-1.0.2/spec/rfc1929.txt000066400000000000000000000067601376412744400154530ustar00rootroot00000000000000 Network Working Group M. Leech Request for Comments: 1929 Bell-Northern Research Ltd Category: Standards Track March 1996 Username/Password Authentication for SOCKS V5 Status of this Memo This document specifies an Internet standards track protocol for the Internet community, and requests discussion and suggestions for improvements. Please refer to the current edition of the "Internet Official Protocol Standards" (STD 1) for the standardization state and status of this protocol. Distribution of this memo is unlimited. 1. Introduction The protocol specification for SOCKS Version 5 specifies a generalized framework for the use of arbitrary authentication protocols in the initial socks connection setup. This document describes one of those protocols, as it fits into the SOCKS Version 5 authentication "subnegotiation". Note: Unless otherwise noted, the decimal numbers appearing in packet- format diagrams represent the length of the corresponding field, in octets. Where a given octet must take on a specific value, the syntax X'hh' is used to denote the value of the single octet in that field. When the word 'Variable' is used, it indicates that the corresponding field has a variable length defined either by an associated (one or two octet) length field, or by a data type field. 2. Initial negotiation Once the SOCKS V5 server has started, and the client has selected the Username/Password Authentication protocol, the Username/Password subnegotiation begins. This begins with the client producing a Username/Password request: +----+------+----------+------+----------+ |VER | ULEN | UNAME | PLEN | PASSWD | +----+------+----------+------+----------+ | 1 | 1 | 1 to 255 | 1 | 1 to 255 | +----+------+----------+------+----------+ Leech Standards Track [Page 1] RFC 1929 Username Authentication for SOCKS V5 March 1996 The VER field contains the current version of the subnegotiation, which is X'01'. The ULEN field contains the length of the UNAME field that follows. The UNAME field contains the username as known to the source operating system. The PLEN field contains the length of the PASSWD field that follows. The PASSWD field contains the password association with the given UNAME. The server verifies the supplied UNAME and PASSWD, and sends the following response: +----+--------+ |VER | STATUS | +----+--------+ | 1 | 1 | +----+--------+ A STATUS field of X'00' indicates success. If the server returns a `failure' (STATUS value other than X'00') status, it MUST close the connection. 3. Security Considerations This document describes a subnegotiation that provides authentication services to the SOCKS protocol. Since the request carries the password in cleartext, this subnegotiation is not recommended for environments where "sniffing" is possible and practical. 4. Author's Address Marcus Leech Bell-Northern Research Ltd P.O. Box 3511, Station C Ottawa, ON CANADA K1Y 4H7 Phone: +1 613 763 9145 EMail: mleech@bnr.ca Leech Standards Track [Page 2] socks-1.0.2/spec/socks4A.protocol.txt000066400000000000000000000035211376412744400175130ustar00rootroot00000000000000SOCKS 4A: A Simple Extension to SOCKS 4 Protocol Ying-Da Lee yingda@best.com or yingda@esd.sgi.com Please read SOCKS4.protocol first for an description of the version 4 protocol. This extension is intended to allow the use of SOCKS on hosts which are not capable of resolving all domain names. In version 4, the client sends the following packet to the SOCKS server to request a CONNECT or a BIND operation: +----+----+----+----+----+----+----+----+----+----+....+----+ | VN | CD | DSTPORT | DSTIP | USERID |NULL| +----+----+----+----+----+----+----+----+----+----+....+----+ # of bytes: 1 1 2 4 variable 1 VN is the SOCKS protocol version number and should be 4. CD is the SOCKS command code and should be 1 for CONNECT or 2 for BIND. NULL is a byte of all zero bits. For version 4A, if the client cannot resolve the destination host's domain name to find its IP address, it should set the first three bytes of DSTIP to NULL and the last byte to a non-zero value. (This corresponds to IP address 0.0.0.x, with x nonzero. As decreed by IANA -- The Internet Assigned Numbers Authority -- such an address is inadmissible as a destination IP address and thus should never occur if the client can resolve the domain name.) Following the NULL byte terminating USERID, the client must sends the destination domain name and termiantes it with another NULL byte. This is used for both CONNECT and BIND requests. A server using protocol 4A must check the DSTIP in the request packet. If it represent address 0.0.0.x with nonzero x, the server must read in the domain name that the client sends in the packet. The server should resolve the domain name and make connection to the destination host if it can. SOCKSified sockd may pass domain names that it cannot resolve to the next-hop SOCKS server.