tor.go raw

   1  package connmgr
   2  
   3  import (
   4  	"encoding/binary"
   5  	"errors"
   6  	"net"
   7  )
   8  
   9  const (
  10  	torSucceeded         = 0x00
  11  	torGeneralError      = 0x01
  12  	torNotAllowed        = 0x02
  13  	torNetUnreachable    = 0x03
  14  	torHostUnreachable   = 0x04
  15  	torConnectionRefused = 0x05
  16  	torTTLExpired        = 0x06
  17  	torCmdNotSupported   = 0x07
  18  	torAddrNotSupported  = 0x08
  19  )
  20  
  21  var (
  22  	// ErrTorInvalidAddressResponse indicates an invalid address was returned by the Tor DNS resolver.
  23  	ErrTorInvalidAddressResponse = errors.New("invalid address response")
  24  	// ErrTorInvalidProxyResponse indicates the Tor proxy returned a response in an unexpected format.
  25  	ErrTorInvalidProxyResponse = errors.New("invalid proxy response")
  26  	// ErrTorUnrecognizedAuthMethod indicates the authentication method provided is not recognized.
  27  	ErrTorUnrecognizedAuthMethod = errors.New("invalid proxy authentication method")
  28  	torStatusErrors              = map[byte]error{
  29  		torSucceeded:         errors.New("tor succeeded"),
  30  		torGeneralError:      errors.New("tor general error"),
  31  		torNotAllowed:        errors.New("tor not allowed"),
  32  		torNetUnreachable:    errors.New("tor network is unreachable"),
  33  		torHostUnreachable:   errors.New("tor host is unreachable"),
  34  		torConnectionRefused: errors.New("tor connection refused"),
  35  		torTTLExpired:        errors.New("tor TTL expired"),
  36  		torCmdNotSupported:   errors.New("tor command not supported"),
  37  		torAddrNotSupported:  errors.New("tor address type not supported"),
  38  	}
  39  )
  40  
  41  // TorLookupIP uses Tor to resolve DNS via the SOCKS extension they provide for resolution over the Tor network. Tor
  42  // itself doesn't support ipv6 so this doesn't either.
  43  func TorLookupIP(host, proxy string) ([]net.IP, error) {
  44  	conn, e := net.Dial("tcp", proxy)
  45  	if e != nil {
  46  		return nil, e
  47  	}
  48  	defer func() {
  49  		if e = conn.Close(); E.Chk(e) {
  50  		}
  51  	}()
  52  	buf := []byte{'\x05', '\x01', '\x00'}
  53  	_, e = conn.Write(buf)
  54  	if e != nil {
  55  		return nil, e
  56  	}
  57  	buf = make([]byte, 2)
  58  	_, e = conn.Read(buf)
  59  	if e != nil {
  60  		return nil, e
  61  	}
  62  	if buf[0] != '\x05' {
  63  		return nil, ErrTorInvalidProxyResponse
  64  	}
  65  	if buf[1] != '\x00' {
  66  		return nil, ErrTorUnrecognizedAuthMethod
  67  	}
  68  	buf = make([]byte, 7+len(host))
  69  	buf[0] = 5      // protocol version
  70  	buf[1] = '\xF0' // Tor Resolve
  71  	buf[2] = 0      // reserved
  72  	buf[3] = 3      // Tor Resolve
  73  	buf[4] = byte(len(host))
  74  	copy(buf[5:], host)
  75  	buf[5+len(host)] = 0 // Port 0
  76  	_, e = conn.Write(buf)
  77  	if e != nil {
  78  		return nil, e
  79  	}
  80  	buf = make([]byte, 4)
  81  	_, e = conn.Read(buf)
  82  	if e != nil {
  83  		return nil, e
  84  	}
  85  	if buf[0] != 5 {
  86  		return nil, ErrTorInvalidProxyResponse
  87  	}
  88  	if buf[1] != 0 {
  89  		if int(buf[1]) >= len(torStatusErrors) {
  90  			return nil, ErrTorInvalidProxyResponse
  91  		} else if e = torStatusErrors[buf[1]]; E.Chk(e) {
  92  			return nil, e
  93  		}
  94  		return nil, ErrTorInvalidProxyResponse
  95  	}
  96  	if buf[3] != 1 {
  97  		e = torStatusErrors[torGeneralError]
  98  		return nil, e
  99  	}
 100  	buf = make([]byte, 4)
 101  	bytes, e := conn.Read(buf)
 102  	if e != nil {
 103  		return nil, e
 104  	}
 105  	if bytes != 4 {
 106  		return nil, ErrTorInvalidAddressResponse
 107  	}
 108  	r := binary.BigEndian.Uint32(buf)
 109  	addr := make([]net.IP, 1)
 110  	addr[0] = net.IPv4(byte(r>>24), byte(r>>16), byte(r>>8), byte(r))
 111  	return addr, nil
 112  }
 113