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  }