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