github.com/jlmucb/cloudproxy@v0.0.0-20170830161738-b5aa0b619bc4/go/apps/mixnet/socks5.go (about)

     1  // Copyright (c) 2015, Google Inc. All rights reserved.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package mixnet
    16  
    17  import (
    18  	"errors"
    19  	"net"
    20  	"strconv"
    21  )
    22  
    23  // Codes used in the RFC standard of SOCKS version 5.
    24  const (
    25  	SocksVersion            = 0x05
    26  	SocksMethodNoAuth       = 0x00
    27  	SocksNoAcceptableMethod = 0xff
    28  	SocksCmdConnect         = 0x01
    29  	SocksAtypIPv4           = 0x01
    30  	SocksRepSuccess         = 0x00
    31  	SocksRepFailure         = 0x01
    32  	SocksRepUnsupported     = 0x07
    33  )
    34  
    35  // SocksConn implements the net.Conn interface and contains a destination
    36  // network and address for the proxy.
    37  type SocksConn struct {
    38  	net.Conn
    39  	network, dstAddr string // Destination network and address.
    40  }
    41  
    42  // DestinationAddr returns the destination address negotiated in the SOCKS
    43  // protocol.
    44  func (c *SocksConn) DestinationAddr() string {
    45  	return c.dstAddr
    46  }
    47  
    48  // SocksListener implements the net.Listener interface as a SOCKS server. This
    49  // program partially implements the server role in version 5 of the SOCKS
    50  // protocol specified in RFC 1928. In particular, it only supports TCP clients
    51  // with no authentication who request CONNECT to IPv4 addresses; neither BIND
    52  // nor UDP ASSOCIATE are supported.
    53  type SocksListener struct {
    54  	net.Listener
    55  	network string // Network protocol for proxying, e.g. "tcp".
    56  }
    57  
    58  // SocksListen binds an address to a socket and returns a
    59  // SocksListener for serving SOCKS clients.
    60  func SocksListen(network, addr string) (net.Listener, error) {
    61  	l, err := net.Listen(network, addr)
    62  	if err != nil {
    63  		return nil, err
    64  	}
    65  	return &SocksListener{l, network}, nil
    66  }
    67  
    68  // Accept exposes the SOCKS5 protocol to connecting client. Return the
    69  // connection and the requested destination address.
    70  func (l *SocksListener) Accept() (net.Conn, error) {
    71  	c, err := l.Listener.Accept()
    72  	if err != nil {
    73  		return nil, err
    74  	}
    75  
    76  	// First, wait for greeting from client containing the SOCKS version and
    77  	// requested methods.
    78  	msg := make([]byte, MaxMsgBytes)
    79  	reply := make([]byte, MaxMsgBytes)
    80  	bytes, err := c.Read(msg)
    81  	if err != nil {
    82  		c.Close()
    83  		return nil, err
    84  	}
    85  
    86  	// Parse client's greeting, making sure that it is the proper length.
    87  	// Only the NO AUTHENTICATION REQUIRED method is allowed. Note that this
    88  	// makes the server non-compliant since GSSAPI is not allowed.
    89  	ok := false
    90  	var ver, nmethods int
    91  	if bytes > 2 {
    92  		ver = int(msg[0])
    93  		nmethods = int(msg[1])
    94  		if bytes >= 2+nmethods {
    95  			for _, method := range msg[2 : 2+nmethods] {
    96  				if method == SocksMethodNoAuth {
    97  					ok = true
    98  					break
    99  				}
   100  			}
   101  		}
   102  	}
   103  
   104  	// Second, reply with selected method.
   105  	reply[0] = SocksVersion
   106  	if ok {
   107  		reply[1] = SocksMethodNoAuth
   108  	} else {
   109  		reply[1] = SocksNoAcceptableMethod
   110  	}
   111  
   112  	if _, err = c.Write(reply[:2]); err != nil {
   113  		c.Close()
   114  		return nil, err
   115  	}
   116  
   117  	// If NO ACCEPTABLE METHOD, the client closes the connection.
   118  	if !ok {
   119  		c.Close()
   120  		return nil, errors.New("socks: client did not provide acceptable method")
   121  	}
   122  
   123  	// Third, wait for command from client.
   124  	bytes, err = c.Read(msg)
   125  	if err != nil {
   126  		c.Close()
   127  		return nil, err
   128  	}
   129  
   130  	// Test that client's command is long enough. It must be at least 6 bytes long
   131  	// to accomadate the version, command, reserved byte, address type, and
   132  	// destination port.
   133  	if bytes < 6 {
   134  		reply[0] = SocksVersion
   135  		reply[1] = SocksRepFailure
   136  		for i := 2; i < 6; i++ {
   137  			reply[i] = 0x00
   138  		}
   139  		defer c.Close()
   140  		if _, err = c.Write(reply[:6]); err != nil {
   141  			return nil, err
   142  		}
   143  		return nil, errors.New("socks: client sent a malformed command")
   144  	}
   145  
   146  	ver = int(msg[0])
   147  	cmd := msg[1]
   148  	// msg[2] is a reserved byte in the protocol.
   149  	atyp := msg[3]
   150  
   151  	// Only CONNECT to IPv4 addresses is allowed. Since traffic will be proxied
   152  	// over the mixnet, don't connect to the intended host just yet. Reply to
   153  	// the client.
   154  	copy(reply, msg[:bytes])
   155  	if ver == SocksVersion && cmd == SocksCmdConnect /* CONNECT */ && atyp == SocksAtypIPv4 /* IPv4 */ {
   156  		reply[1] = SocksRepSuccess
   157  	} else {
   158  		reply[1] = SocksRepUnsupported
   159  	}
   160  	if _, err = c.Write(reply[:bytes]); err != nil {
   161  		c.Close()
   162  		return nil, err
   163  	}
   164  
   165  	// dstAddr specifies the destination of the client. At this point the
   166  	// proxy is ready to construct a circuit and relay a message on behalf of
   167  	// the client.
   168  	port := strconv.Itoa((int(msg[bytes-2]) << 8) + int(msg[bytes-1]))
   169  	dstAddr := strconv.Itoa(int(msg[4])) + "." +
   170  		strconv.Itoa(int(msg[5])) + "." +
   171  		strconv.Itoa(int(msg[6])) + "." +
   172  		strconv.Itoa(int(msg[7])) + ":" + port
   173  
   174  	return &SocksConn{c, l.network, dstAddr}, nil
   175  }