| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769 |
- package pt
- import (
- "bufio"
- "fmt"
- "io"
- "net"
- "time"
- )
- const (
- socks4Version = 0x04
- socks5Version = 0x05
- socksAuthNoneRequired = 0x00
- socksAuthUsernamePassword = 0x02
- socksAuthNoAcceptableMethods = 0xff
- socksCmdConnect = 0x01
- socksReserved = 0x00
- socksAtypeV4 = 0x01
- socksAtypeDomainName = 0x03
- socksAtypeV6 = 0x04
- socksAuthRFC1929Ver = 0x01
- socksAuthRFC1929Success = 0x00
- socksAuthRFC1929Fail = 0x01
- socksRepSucceeded = 0x00
- // "general SOCKS server failure"
- SocksRepGeneralFailure = 0x01
- // "connection not allowed by ruleset"
- SocksRepConnectionNotAllowed = 0x02
- // "Network unreachable"
- SocksRepNetworkUnreachable = 0x03
- // "Host unreachable"
- SocksRepHostUnreachable = 0x04
- // "Connection refused"
- SocksRepConnectionRefused = 0x05
- // "TTL expired"
- SocksRepTTLExpired = 0x06
- // "Command not supported"
- SocksRepCommandNotSupported = 0x07
- // "Address type not supported"
- SocksRepAddressNotSupported = 0x08
- socks4ResponseVersion = 0x00
- socks4RequestGranted = 0x5a
- socks4RequestRejected = 0x5b
- )
- // Put a sanity timeout on how long we wait for a SOCKS request.
- const socksRequestTimeout = 5 * time.Second
- // SocksRequest describes a SOCKS request.
- type SocksRequest struct {
- // The endpoint requested by the client as a "host:port" string.
- Target string
- // The userid string sent by the client.
- Username string
- // The password string sent by the client.
- Password string
- // The parsed contents of Username as a key–value mapping.
- Args Args
- }
- // SocksConn encapsulates a net.Conn and information associated with a SOCKS request.
- type SocksConn struct {
- net.Conn
- Req SocksRequest
- socksVersion byte
- }
- // Send a message to the proxy client that access to the given address is
- // granted.
- // For SOCKS5, Addr is ignored, and "0.0.0.0:0" is always sent back for
- // BND.ADDR/BND.PORT in the SOCKS response.
- // For SOCKS4a, if the IP field inside addr is not an IPv4 address, the IP
- // portion of the response will be four zero bytes.
- func (conn *SocksConn) Grant(addr *net.TCPAddr) error {
- if conn.socksVersion == socks4Version {
- return sendSocks4aResponseGranted(conn, addr)
- }
- return sendSocks5ResponseGranted(conn)
- }
- // Send a message to the proxy client that access was rejected or failed. This
- // sends back a "General Failure" error code. RejectReason should be used if
- // more specific error reporting is desired.
- func (conn *SocksConn) Reject() error {
- if conn.socksVersion == socks4Version {
- return sendSocks4aResponseRejected(conn)
- }
- return sendSocks5ResponseRejected(conn, SocksRepGeneralFailure)
- }
- // Send a message to the proxy client that access was rejected, with the
- // specific error code indicating the reason behind the rejection.
- // For SOCKS4a, the reason is ignored.
- func (conn *SocksConn) RejectReason(reason byte) error {
- if conn.socksVersion == socks4Version {
- return sendSocks4aResponseRejected(conn)
- }
- return sendSocks5ResponseRejected(conn, reason)
- }
- // SocksListener wraps a net.Listener in order to read a SOCKS request on Accept.
- //
- // func handleConn(conn *pt.SocksConn) error {
- // defer conn.Close()
- // remote, err := net.Dial("tcp", conn.Req.Target)
- // if err != nil {
- // conn.Reject()
- // return err
- // }
- // defer remote.Close()
- // err = conn.Grant(remote.RemoteAddr().(*net.TCPAddr))
- // if err != nil {
- // return err
- // }
- // // do something with conn and remote
- // return nil
- // }
- // ...
- // ln, err := pt.ListenSocks("tcp", "127.0.0.1:0")
- // if err != nil {
- // panic(err.Error())
- // }
- // for {
- // conn, err := ln.AcceptSocks()
- // if err != nil {
- // log.Printf("accept error: %s", err)
- // if e, ok := err.(net.Error); !ok || !e.Temporary() {
- // break
- // }
- // continue
- // }
- // go handleConn(conn)
- // }
- type SocksListener struct {
- net.Listener
- }
- // Open a net.Listener according to network and laddr, and return it as a
- // SocksListener.
- func ListenSocks(network, laddr string) (*SocksListener, error) {
- ln, err := net.Listen(network, laddr)
- if err != nil {
- return nil, err
- }
- return NewSocksListener(ln), nil
- }
- // Create a new SocksListener wrapping the given net.Listener.
- func NewSocksListener(ln net.Listener) *SocksListener {
- return &SocksListener{ln}
- }
- // Accept is the same as AcceptSocks, except that it returns a generic net.Conn.
- // It is present for the sake of satisfying the net.Listener interface.
- func (ln *SocksListener) Accept() (net.Conn, error) {
- return ln.AcceptSocks()
- }
- // Call Accept on the wrapped net.Listener, do SOCKS negotiation, and return a
- // SocksConn. After accepting, you must call either conn.Grant or conn.Reject
- // (presumably after trying to connect to conn.Req.Target).
- //
- // Errors returned by AcceptSocks may be temporary (for example, EOF while
- // reading the request, or a badly formatted userid string), or permanent (e.g.,
- // the underlying socket is closed). You can determine whether an error is
- // temporary and take appropriate action with a type conversion to net.Error.
- // For example:
- //
- // for {
- // conn, err := ln.AcceptSocks()
- // if err != nil {
- // if e, ok := err.(net.Error); ok && e.Temporary() {
- // log.Printf("temporary accept error; trying again: %s", err)
- // continue
- // }
- // log.Printf("permanent accept error; giving up: %s", err)
- // break
- // }
- // go handleConn(conn)
- // }
- func (ln *SocksListener) AcceptSocks() (*SocksConn, error) {
- c, err := ln.Listener.Accept()
- if err != nil {
- return nil, err
- }
- conn := new(SocksConn)
- conn.Conn = c
- err = conn.SetDeadline(time.Now().Add(socksRequestTimeout))
- if err != nil {
- conn.Close()
- err = newTemporaryNetError("AcceptSocks: conn.SetDeadline() #1 failed: %s", err.Error())
- return nil, err
- }
- rw := bufio.NewReadWriter(bufio.NewReader(conn), bufio.NewWriter(conn))
- // Determine which SOCKS version the client is using and branch on it.
- if version, err := socksPeekByte(rw.Reader); err != nil {
- conn.Close()
- err = newTemporaryNetError("AcceptSocks: socksPeekByte() failed: %s", err.Error())
- return nil, err
- } else if version == socks4Version {
- conn.socksVersion = socks4Version
- conn.Req, err = readSocks4aConnect(rw.Reader)
- if err != nil {
- conn.Close()
- return nil, err
- }
- } else if version == socks5Version {
- conn.socksVersion = socks5Version
- conn.Req, err = socks5Handshake(rw)
- if err != nil {
- conn.Close()
- return nil, err
- }
- } else {
- conn.Close()
- err = newTemporaryNetError("AcceptSocks: Illegal SOCKS version: 0x%02x", version)
- return nil, err
- }
- err = conn.SetDeadline(time.Time{})
- if err != nil {
- conn.Close()
- err = newTemporaryNetError("AcceptSocks: conn.SetDeadline() #2 failed: %s", err.Error())
- return nil, err
- }
- return conn, nil
- }
- // Returns "socks5", suitable to be included in a call to Cmethod.
- func (ln *SocksListener) Version() string {
- return "socks5"
- }
- // socks5handshake conducts the SOCKS5 handshake up to the point where the
- // client command is read and the proxy must open the outgoing connection.
- // Returns a SocksRequest.
- func socks5Handshake(rw *bufio.ReadWriter) (req SocksRequest, err error) {
- // Negotiate the authentication method.
- var method byte
- if method, err = socks5NegotiateAuth(rw); err != nil {
- return
- }
- // Authenticate the client.
- if err = socks5Authenticate(rw, method, &req); err != nil {
- return
- }
- // Read the command.
- err = socks5ReadCommand(rw, &req)
- return
- }
- // socks5NegotiateAuth negotiates the authentication method and returns the
- // selected method as a byte. On negotiation failures an error is returned.
- func socks5NegotiateAuth(rw *bufio.ReadWriter) (method byte, err error) {
- // Validate the version.
- if err = socksReadByteVerify(rw.Reader, "version", socks5Version); err != nil {
- err = newTemporaryNetError("socks5NegotiateAuth: %s", err.Error())
- return
- }
- // Read the number of methods.
- var nmethods byte
- if nmethods, err = socksReadByte(rw.Reader); err != nil {
- err = newTemporaryNetError("socks5NegotiateAuth: Failed to read nmethods byte: %s", err.Error())
- return
- }
- // Read the methods.
- var methods []byte
- if methods, err = socksReadBytes(rw.Reader, int(nmethods)); err != nil {
- err = newTemporaryNetError("socks5NegotiateAuth: Failed to read methods bytes: %s", err.Error())
- return
- }
- // Pick the most "suitable" method.
- method = socksAuthNoAcceptableMethods
- for _, m := range methods {
- // [Psiphon]
- // Some SOCKS5 clients send both None and Username/Password when in fact they are only
- // able to auth with None. Since we don't need pluggable transport parameters and prefer
- // enabling clients to proxy, we prefer None, which allows those clients to connect.
- /*
- switch m {
- case socksAuthNoneRequired:
- // Pick Username/Password over None if the client happens to
- // send both.
- if method == socksAuthNoAcceptableMethods {
- method = m
- }
- case socksAuthUsernamePassword:
- method = m
- }
- */
- switch m {
- case socksAuthNoneRequired:
- method = m
- case socksAuthUsernamePassword:
- if method == socksAuthNoAcceptableMethods {
- method = m
- }
- }
- // [Psiphon]
- }
- // Send the negotiated method.
- var msg [2]byte
- msg[0] = socks5Version
- msg[1] = method
- if _, err = rw.Writer.Write(msg[:]); err != nil {
- err = newTemporaryNetError("socks5NegotiateAuth: Failed to write negotiated method: %s", err.Error())
- return
- }
- if err = socksFlushBuffers(rw); err != nil {
- err = newTemporaryNetError("socks5NegotiateAuth: Failed to flush buffers: %s", err.Error())
- return
- }
- return
- }
- // socks5Authenticate authenticates the client via the chosen authentication
- // mechanism.
- func socks5Authenticate(rw *bufio.ReadWriter, method byte, req *SocksRequest) (err error) {
- switch method {
- case socksAuthNoneRequired:
- // Straight into reading the connect.
- case socksAuthUsernamePassword:
- if err = socks5AuthRFC1929(rw, req); err != nil {
- return
- }
- case socksAuthNoAcceptableMethods:
- err = newTemporaryNetError("socks5Authenticate: SOCKS method select had no compatible methods")
- return
- default:
- err = newTemporaryNetError("socks5Authenticate: SOCKS method select picked a unsupported method 0x%02x", method)
- return
- }
- if err = socksFlushBuffers(rw); err != nil {
- err = newTemporaryNetError("socks5Authenticate: Failed to flush buffers: %s", err)
- return
- }
- return
- }
- // socks5AuthRFC1929 authenticates the client via RFC 1929 username/password
- // auth. As a design decision any valid username/password is accepted as this
- // field is primarily used as an out-of-band argument passing mechanism for
- // pluggable transports.
- func socks5AuthRFC1929(rw *bufio.ReadWriter, req *SocksRequest) (err error) {
- sendErrResp := func() {
- // Swallow the write/flush error here, we are going to close the
- // connection and the original failure is more useful.
- resp := []byte{socksAuthRFC1929Ver, socksAuthRFC1929Fail}
- rw.Write(resp[:])
- socksFlushBuffers(rw)
- }
- // Validate the fixed parts of the command message.
- if err = socksReadByteVerify(rw.Reader, "auth version", socksAuthRFC1929Ver); err != nil {
- sendErrResp()
- err = newTemporaryNetError("socks5AuthRFC1929: %s", err)
- return
- }
- // Read the username.
- var ulen byte
- if ulen, err = socksReadByte(rw.Reader); err != nil {
- err = newTemporaryNetError("socks5AuthRFC1929: Failed to read username length: %s", err)
- return
- }
- if ulen < 1 {
- sendErrResp()
- err = newTemporaryNetError("socks5AuthRFC1929: username with 0 length")
- return
- }
- var uname []byte
- if uname, err = socksReadBytes(rw.Reader, int(ulen)); err != nil {
- err = newTemporaryNetError("socks5AuthRFC1929: Failed to read username: %s", err)
- return
- }
- req.Username = string(uname)
- // Read the password.
- var plen byte
- if plen, err = socksReadByte(rw.Reader); err != nil {
- err = newTemporaryNetError("socks5AuthRFC1929: Failed to read password length: %s", err)
- return
- }
- if plen < 1 {
- sendErrResp()
- err = newTemporaryNetError("socks5AuthRFC1929: password with 0 length")
- return
- }
- var passwd []byte
- if passwd, err = socksReadBytes(rw.Reader, int(plen)); err != nil {
- err = newTemporaryNetError("socks5AuthRFC1929: Failed to read password: %s", err)
- return
- }
- if !(plen == 1 && passwd[0] == 0x00) {
- // tor will set the password to 'NUL' if there are no arguments.
- req.Password = string(passwd)
- }
- // [Psiphon]
- // Since we don't need pluggable transport parameters and prefer enabling clients to proxy,
- // don't parse or validate username/password as PT args.
- /*
- // Mash the username/password together and parse it as a pluggable
- // transport argument string.
- if req.Args, err = parseClientParameters(req.Username + req.Password); err != nil {
- sendErrResp()
- err = newTemporaryNetError("socks5AuthRFC1929: failed to parse client parameters: %s", err)
- return
- }
- */
- // [Psiphon]
- // Write success response
- resp := []byte{socksAuthRFC1929Ver, socksAuthRFC1929Success}
- if _, err = rw.Write(resp[:]); err != nil {
- err = newTemporaryNetError("socks5AuthRFC1929: failed to write success response: %s", err)
- return
- }
- return
- }
- // socks5ReadCommand reads a SOCKS5 client command and parses out the relevant
- // fields into a SocksRequest. Only CMD_CONNECT is supported.
- func socks5ReadCommand(rw *bufio.ReadWriter, req *SocksRequest) (err error) {
- sendErrResp := func(reason byte) {
- // Swallow errors that occur when writing/flushing the response,
- // connection will be closed anyway.
- sendSocks5ResponseRejected(rw, reason)
- socksFlushBuffers(rw)
- }
- // Validate the fixed parts of the command message.
- if err = socksReadByteVerify(rw.Reader, "version", socks5Version); err != nil {
- sendErrResp(SocksRepGeneralFailure)
- err = newTemporaryNetError("socks5ReadCommand: %s", err)
- return
- }
- if err = socksReadByteVerify(rw.Reader, "command", socksCmdConnect); err != nil {
- sendErrResp(SocksRepCommandNotSupported)
- err = newTemporaryNetError("socks5ReadCommand: %s", err)
- return
- }
- if err = socksReadByteVerify(rw.Reader, "reserved", socksReserved); err != nil {
- sendErrResp(SocksRepGeneralFailure)
- err = newTemporaryNetError("socks5ReadCommand: %s", err)
- return
- }
- // Read the destination address/port.
- // XXX: This should probably eventually send socks 5 error messages instead
- // of rudely closing connections on invalid addresses.
- var atype byte
- if atype, err = socksReadByte(rw.Reader); err != nil {
- err = newTemporaryNetError("socks5ReadCommand: Failed to read address type: %s", err)
- return
- }
- var host string
- switch atype {
- case socksAtypeV4:
- var addr []byte
- if addr, err = socksReadBytes(rw.Reader, net.IPv4len); err != nil {
- err = newTemporaryNetError("socks5ReadCommand: Failed to read IPv4 address: %s", err)
- return
- }
- host = net.IPv4(addr[0], addr[1], addr[2], addr[3]).String()
- case socksAtypeDomainName:
- var alen byte
- if alen, err = socksReadByte(rw.Reader); err != nil {
- err = newTemporaryNetError("socks5ReadCommand: Failed to read domain name length: %s", err)
- return
- }
- if alen == 0 {
- err = newTemporaryNetError("socks5ReadCommand: SOCKS request had domain name with 0 length")
- return
- }
- var addr []byte
- if addr, err = socksReadBytes(rw.Reader, int(alen)); err != nil {
- err = newTemporaryNetError("socks5ReadCommand: Failed to read domain name: %s", err)
- return
- }
- host = string(addr)
- case socksAtypeV6:
- var rawAddr []byte
- if rawAddr, err = socksReadBytes(rw.Reader, net.IPv6len); err != nil {
- err = newTemporaryNetError("socks5ReadCommand: Failed to read IPv6 address: %s", err)
- return
- }
- addr := make(net.IP, net.IPv6len)
- copy(addr[:], rawAddr[:])
- host = fmt.Sprintf("[%s]", addr.String())
- default:
- sendErrResp(SocksRepAddressNotSupported)
- err = newTemporaryNetError("socks5ReadCommand: SOCKS request had unsupported address type 0x%02x", atype)
- return
- }
- var rawPort []byte
- if rawPort, err = socksReadBytes(rw.Reader, 2); err != nil {
- err = newTemporaryNetError("socks5ReadCommand: Failed to read port number: %s", err)
- return
- }
- port := int(rawPort[0])<<8 | int(rawPort[1])<<0
- if err = socksFlushBuffers(rw); err != nil {
- err = newTemporaryNetError("socks5ReadCommand: Failed to flush buffers: %s", err)
- return
- }
- req.Target = fmt.Sprintf("%s:%d", host, port)
- return
- }
- // Send a SOCKS5 response with the given code. BND.ADDR/BND.PORT is always the
- // IPv4 address/port "0.0.0.0:0".
- func sendSocks5Response(w io.Writer, code byte) error {
- resp := make([]byte, 4+4+2)
- resp[0] = socks5Version
- resp[1] = code
- resp[2] = socksReserved
- resp[3] = socksAtypeV4
- // BND.ADDR/BND.PORT should be the address and port that the outgoing
- // connection is bound to on the proxy, but Tor does not use this
- // information, so all zeroes are sent.
- if _, err := w.Write(resp[:]); err != nil {
- err = newTemporaryNetError("sendSocks5Response: Failed write response: %s", err)
- return err
- }
- return nil
- }
- // Send a SOCKS5 response code 0x00.
- func sendSocks5ResponseGranted(w io.Writer) error {
- return sendSocks5Response(w, socksRepSucceeded)
- }
- // Send a SOCKS5 response with the provided failure reason.
- func sendSocks5ResponseRejected(w io.Writer, reason byte) error {
- return sendSocks5Response(w, reason)
- }
- /*
- * Common helpers
- */
- func socksFlushBuffers(rw *bufio.ReadWriter) error {
- if err := rw.Writer.Flush(); err != nil {
- return err
- }
- if err := socksFlushReadBuffer(rw.Reader); err != nil {
- return err
- }
- return nil
- }
- func socksFlushReadBuffer(r *bufio.Reader) error {
- if r.Buffered() > 0 {
- return fmt.Errorf("%d bytes left after SOCKS message", r.Buffered())
- }
- return nil
- }
- func socksReadByte(r *bufio.Reader) (byte, error) {
- return r.ReadByte()
- }
- func socksReadBytes(r *bufio.Reader, n int) ([]byte, error) {
- ret := make([]byte, n)
- if _, err := io.ReadFull(r, ret); err != nil {
- return nil, err
- }
- return ret, nil
- }
- func socksReadByteVerify(r *bufio.Reader, descr string, expected byte) error {
- val, err := socksReadByte(r)
- if err != nil {
- return err
- }
- if val != expected {
- return fmt.Errorf("SOCKS message field %s was 0x%02x, not 0x%02x", descr, val, expected)
- }
- return nil
- }
- func socksReadBytesUntil(r *bufio.Reader, end byte) ([]byte, error) {
- val, err := r.ReadBytes(end)
- if err != nil {
- return nil, err
- }
- return val, nil
- }
- func socksPeekByte(r *bufio.Reader) (b byte, err error) {
- var byteSlice []byte
- if byteSlice, err = r.Peek(1); err != nil {
- return
- }
- b = byteSlice[0]
- return
- }
- // temporaryNetError is used for our custom errors. All such errors are "temporary";
- // that is, the listener doesn't need to be torn down when they occur. They also
- // need to implement the net.Error interface.
- type temporaryNetError struct {
- error
- }
- // Ensure temporaryNetError implements net.Error
- var _ net.Error = temporaryNetError{}
- func newTemporaryNetError(errMsg string, args ...interface{}) *temporaryNetError {
- return &temporaryNetError{
- error: fmt.Errorf(errMsg, args...),
- }
- }
- func (tne temporaryNetError) Timeout() bool {
- return false
- }
- func (tne temporaryNetError) Temporary() bool {
- return true
- }
- /*
- * SOCKS4a-specific code
- */
- // Read a SOCKS4a connect request. Returns a SocksRequest.
- func readSocks4aConnect(r *bufio.Reader) (req SocksRequest, err error) {
- // Validate the version.
- if err = socksReadByteVerify(r, "version", socks4Version); err != nil {
- err = newTemporaryNetError("readSocks4aConnect: %s", err.Error())
- return
- }
- var cmdConnect byte
- if cmdConnect, err = socksReadByte(r); err != nil {
- err = newTemporaryNetError("readSocks4aConnect: Failed to read connect command: %s", err.Error())
- return
- }
- if cmdConnect != socksCmdConnect {
- err = newTemporaryNetError("readSocks4aConnect: SOCKS header had command 0x%02x, not 0x%02x", cmdConnect, socksCmdConnect)
- return
- }
- var rawPort []byte
- if rawPort, err = socksReadBytes(r, 2); err != nil {
- err = newTemporaryNetError("readSocks4aConnect: Failed to read port: %s", err.Error())
- return
- }
- port := int(rawPort[0])<<8 | int(rawPort[1])<<0
- var rawHostIP []byte
- if rawHostIP, err = socksReadBytes(r, 4); err != nil {
- err = newTemporaryNetError("readSocks4aConnect: Failed to read IP address: %s", err.Error())
- return
- }
- // If there's a hostname, it comes after the username, so we'll wait a bit
- // before we process the IP info.
- var usernameBytes []byte
- usernameBytes, err = socksReadBytesUntil(r, '\x00')
- if err != nil {
- err = newTemporaryNetError("readSocks4aConnect: Failed to read username: %s", err.Error())
- return
- }
- req.Username = string(usernameBytes[:len(usernameBytes)-1])
- // [Psiphon]
- // Since we don't need pluggable transport parameters and prefer enabling clients to proxy,
- // don't parse or validate username/password as PT args.
- /*
- req.Args, err = parseClientParameters(req.Username)
- if err != nil {
- err = newTemporaryNetError("readSocks4aConnect: Failed to parse client parameters: %s", err.Error())
- return
- }
- */
- // [Psiphon]
- var host string
- if rawHostIP[0] == 0 && rawHostIP[1] == 0 && rawHostIP[2] == 0 && rawHostIP[3] != 0 {
- // If the IP is of the form 0.0.0.x (with x nonzero), then a domain name is provided.
- var hostBytes []byte
- if hostBytes, err = socksReadBytesUntil(r, '\x00'); err != nil {
- err = newTemporaryNetError("readSocks4aConnect: Failed to read domain name: %s", err.Error())
- return
- }
- host = string(hostBytes[:len(hostBytes)-1])
- } else {
- host = net.IPv4(rawHostIP[0], rawHostIP[1], rawHostIP[2], rawHostIP[3]).String()
- }
- req.Target = fmt.Sprintf("%s:%d", host, port)
- if err = socksFlushReadBuffer(r); err != nil {
- err = newTemporaryNetError("readSocks4aConnect: Failed to flush buffers: %s", err.Error())
- return
- }
- return
- }
- // Send a SOCKS4a response with the given code and address. If the IP field
- // inside addr is not an IPv4 address, the IP portion of the response will be
- // four zero bytes.
- func sendSocks4aResponse(w io.Writer, code byte, addr *net.TCPAddr) error {
- var resp [8]byte
- resp[0] = socks4ResponseVersion
- resp[1] = code
- resp[2] = byte((addr.Port >> 8) & 0xff)
- resp[3] = byte((addr.Port >> 0) & 0xff)
- ipv4 := addr.IP.To4()
- if ipv4 != nil {
- resp[4] = ipv4[0]
- resp[5] = ipv4[1]
- resp[6] = ipv4[2]
- resp[7] = ipv4[3]
- }
- if _, err := w.Write(resp[:]); err != nil {
- err = newTemporaryNetError("sendSocks4aResponse: Failed to write response: %s", err.Error())
- return err
- }
- return nil
- }
- // Send a SOCKS4a response code 0x5a.
- func sendSocks4aResponseGranted(w io.Writer, addr *net.TCPAddr) error {
- return sendSocks4aResponse(w, socks4RequestGranted, addr)
- }
- // Send a SOCKS4a response code 0x5b (with an all-zero address).
- func sendSocks4aResponseRejected(w io.Writer) error {
- emptyAddr := net.TCPAddr{IP: net.IPv4(0, 0, 0, 0), Port: 0}
- return sendSocks4aResponse(w, socks4RequestRejected, &emptyAddr)
- }
|