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