Exemplo n.º 1
0
// newNetAddress attempts to extract the IP address and port from the passed
// net.Addr interface and create a bitcoin NetAddress structure using that
// information.
func newNetAddress(addr net.Addr, services btcwire.ServiceFlag) (*btcwire.NetAddress, error) {
	// addr will be a net.TCPAddr when not using a proxy.
	if tcpAddr, ok := addr.(*net.TCPAddr); ok {
		ip := tcpAddr.IP
		port := uint16(tcpAddr.Port)
		na := btcwire.NewNetAddressIPPort(ip, port, services)
		return na, nil
	}

	// addr will be a socks.ProxiedAddr when using a proxy.
	if proxiedAddr, ok := addr.(*socks.ProxiedAddr); ok {
		ip := net.ParseIP(proxiedAddr.Host)
		if ip == nil {
			ip = net.ParseIP("0.0.0.0")
		}
		port := uint16(proxiedAddr.Port)
		na := btcwire.NewNetAddressIPPort(ip, port, services)
		return na, nil
	}

	// For the most part, addr should be one of the two above cases, but
	// to be safe, fall back to trying to parse the information from the
	// address string as a last resort.
	host, portStr, err := net.SplitHostPort(addr.String())
	if err != nil {
		return nil, err
	}
	ip := net.ParseIP(host)
	port, err := strconv.ParseUint(portStr, 10, 16)
	if err != nil {
		return nil, err
	}
	na := btcwire.NewNetAddressIPPort(ip, uint16(port), services)
	return na, nil
}
Exemplo n.º 2
0
// hostToNetAddress returns a netaddress given a host address. If the address is
// a tor .onion address this will be taken care of. else if the host is not an
// IP address it will be resolved (via tor if required).
func hostToNetAddress(host string, port uint16, services btcwire.ServiceFlag) (*btcwire.NetAddress, error) {
	// tor address is 16 char base32 + ".onion"
	var ip net.IP
	if len(host) == 22 && host[16:] == ".onion" {
		// go base32 encoding uses capitals (as does the rfc
		// but tor and bitcoind tend to user lowercase, so we switch
		// case here.
		data, err := base32.StdEncoding.DecodeString(
			strings.ToUpper(host[:16]))
		if err != nil {
			return nil, err
		}
		prefix := []byte{0xfd, 0x87, 0xd8, 0x7e, 0xeb, 0x43}
		ip = net.IP(append(prefix, data...))
	} else if ip = net.ParseIP(host); ip == nil {
		ips, err := btcdLookup(host)
		if err != nil {
			return nil, err
		}
		if len(ips) == 0 {
			return nil, fmt.Errorf("No addresses found for %s", host)
		}
		ip = ips[0]
	}

	return btcwire.NewNetAddressIPPort(ip, port, services), nil
}
Exemplo n.º 3
0
func NewNetAddress(addr net.Addr, services btcwire.ServiceFlag) (*btcwire.NetAddress, error) {
	// addr will be addr net.TCPAddr when not using a proxy.
	if tcpAddr, ok := addr.(*net.TCPAddr); ok {
		ip := tcpAddr.IP
		port := uint16(tcpAddr.Port)
		na := btcwire.NewNetAddressIPPort(ip, port, services)
		return na, nil
	}

	return nil, errors.New("Couldn't create address")
}
Exemplo n.º 4
0
func (s *server) upnpUpdateThread() {
	// Go off immediately to prevent code duplication, thereafter we renew
	// lease every 15 minutes.
	timer := time.NewTimer(0 * time.Second)
	lport, _ := strconv.ParseInt(activeNetParams.DefaultPort, 10, 16)
	first := true
out:
	for {
		select {
		case <-timer.C:
			// TODO(oga) pick external port  more cleverly
			// TODO(oga) know which ports we are listening to on an external net.
			// TODO(oga) if specific listen port doesn't work then ask for wildcard
			// listen port?
			// XXX this assumes timeout is in seconds.
			listenPort, err := s.nat.AddPortMapping("tcp", int(lport), int(lport),
				"btcd listen port", 20*60)
			if err != nil {
				srvrLog.Warnf("can't add UPnP port mapping: %v", err)
			}
			if first && err == nil {
				// TODO(oga): look this up periodically to see if upnp domain changed
				// and so did ip.
				externalip, err := s.nat.GetExternalAddress()
				if err != nil {
					srvrLog.Warnf("UPnP can't get external address: %v", err)
					continue out
				}
				na := btcwire.NewNetAddressIPPort(externalip, uint16(listenPort),
					btcwire.SFNodeNetwork)
				err = s.addrManager.AddLocalAddress(na, addrmgr.UpnpPrio)
				if err != nil {
					// XXX DeletePortMapping?
				}
				srvrLog.Warnf("Successfully bound via UPnP to %s", addrmgr.NetAddressKey(na))
				first = false
			}
			timer.Reset(time.Minute * 15)
		case <-s.quit:
			break out
		}
	}

	timer.Stop()

	if err := s.nat.DeletePortMapping("tcp", int(lport), int(lport)); err != nil {
		srvrLog.Warnf("unable to remove UPnP port mapping: %v", err)
	} else {
		srvrLog.Debugf("succesfully disestablished UPnP port mapping")
	}

	s.wg.Done()
}
Exemplo n.º 5
0
func deserialiseNetAddress(addr string) (*btcwire.NetAddress, error) {
	host, portStr, err := net.SplitHostPort(addr)
	if err != nil {
		return nil, err
	}
	ip := net.ParseIP(host)
	port, err := strconv.ParseUint(portStr, 10, 16)
	if err != nil {
		return nil, err
	}
	na := btcwire.NewNetAddressIPPort(ip, uint16(port),
		btcwire.SFNodeNetwork)
	return na, nil
}
Exemplo n.º 6
0
// newServer returns a new btcd server configured to listen on addr for the
// bitcoin network type specified in btcnet.  Use start to begin accepting
// connections from peers.
func newServer(listenAddrs []string, db btcdb.Db, btcnet btcwire.BitcoinNet) (*server, error) {
	nonce, err := btcwire.RandomUint64()
	if err != nil {
		return nil, err
	}

	amgr := NewAddrManager()

	var listeners []net.Listener
	var nat NAT
	if !cfg.DisableListen {
		ipv4Addrs, ipv6Addrs, wildcard, err :=
			parseListeners(listenAddrs)
		if err != nil {
			return nil, err
		}
		listeners = make([]net.Listener, 0, len(ipv4Addrs)+len(ipv6Addrs))
		discover := true
		if len(cfg.ExternalIPs) != 0 {
			discover = false
			// if this fails we have real issues.
			port, _ := strconv.ParseUint(
				activeNetParams.listenPort, 10, 16)

			for _, sip := range cfg.ExternalIPs {
				eport := uint16(port)
				host, portstr, err := net.SplitHostPort(sip)
				if err != nil {
					// no port, use default.
					host = sip
				} else {
					port, err := strconv.ParseUint(
						portstr, 10, 16)
					if err != nil {
						srvrLog.Warnf("Can not parse "+
							"port from %s for "+
							"externalip: %v", sip,
							err)
						continue
					}
					eport = uint16(port)
				}
				na, err := hostToNetAddress(host, eport,
					btcwire.SFNodeNetwork)
				if err != nil {
					srvrLog.Warnf("Not adding %s as "+
						"externalip: %v", sip, err)
					continue
				}

				amgr.addLocalAddress(na, ManualPrio)
			}
		} else if discover && cfg.Upnp {
			nat, err = Discover()
			if err != nil {
				srvrLog.Warnf("Can't discover upnp: %v", err)
			}
			// nil nat here is fine, just means no upnp on network.
		}

		// TODO(oga) nonstandard port...
		if wildcard {
			port, err :=
				strconv.ParseUint(activeNetParams.listenPort,
					10, 16)
			if err != nil {
				// I can't think of a cleaner way to do this...
				goto nowc
			}
			addrs, err := net.InterfaceAddrs()
			for _, a := range addrs {
				ip, _, err := net.ParseCIDR(a.String())
				if err != nil {
					continue
				}
				na := btcwire.NewNetAddressIPPort(ip,
					uint16(port), btcwire.SFNodeNetwork)
				if discover {
					amgr.addLocalAddress(na, InterfacePrio)
				}
			}
		}
	nowc:

		for _, addr := range ipv4Addrs {
			listener, err := net.Listen("tcp4", addr)
			if err != nil {
				srvrLog.Warnf("Can't listen on %s: %v", addr,
					err)
				continue
			}
			listeners = append(listeners, listener)

			if discover {
				if na, err := deserialiseNetAddress(addr); err == nil {
					amgr.addLocalAddress(na, BoundPrio)
				}
			}
		}

		for _, addr := range ipv6Addrs {
			listener, err := net.Listen("tcp6", addr)
			if err != nil {
				srvrLog.Warnf("Can't listen on %s: %v", addr,
					err)
				continue
			}
			listeners = append(listeners, listener)
			if discover {
				if na, err := deserialiseNetAddress(addr); err == nil {
					amgr.addLocalAddress(na, BoundPrio)
				}
			}
		}

		if len(listeners) == 0 {
			return nil, errors.New("No valid listen address")
		}
	}

	s := server{
		nonce:       nonce,
		listeners:   listeners,
		btcnet:      btcnet,
		addrManager: amgr,
		newPeers:    make(chan *peer, cfg.MaxPeers),
		donePeers:   make(chan *peer, cfg.MaxPeers),
		banPeers:    make(chan *peer, cfg.MaxPeers),
		wakeup:      make(chan bool),
		query:       make(chan interface{}),
		relayInv:    make(chan *btcwire.InvVect, cfg.MaxPeers),
		broadcast:   make(chan broadcastMsg, cfg.MaxPeers),
		quit:        make(chan bool),
		nat:         nat,
		db:          db,
	}
	bm, err := newBlockManager(&s)
	if err != nil {
		return nil, err
	}
	s.blockManager = bm
	s.txMemPool = newTxMemPool(&s)

	if !cfg.DisableRPC {
		s.rpcServer, err = newRPCServer(cfg.RPCListeners, &s)
		if err != nil {
			return nil, err
		}
	}
	return &s, nil
}
Exemplo n.º 7
0
func main() {
	flag.Parse()
	if *mainnetFlag {
		btcnet = btc.MainNet
	}

	var addrMap = make(map[string]Node)

	numWorkers := 250
	// Multiplex writes into single channel
	var incomingAddrs = make(chan []*btc.NetAddress)
	var outgoingAddr = make(chan *btc.NetAddress, 5e5)
	var liveNodes = make(chan Node)

	for i := 0; i < numWorkers; i += 1 {
		go connHandler(i, incomingAddrs, liveNodes, outgoingAddr)
	}

	rt := time.Duration(*runTime)
	timer := time.NewTimer(time.Second * rt)
	var visited = make(map[string]struct{})
	var addrs []*btc.NetAddress
	var node Node
	cnt := 0

	// Initial connection into net
	pair := strings.Split(*bootstrap, ":")
	ip := pair[0]
	port, _ := strconv.ParseUint(pair[1], 10, 16)
	home := btc.NewNetAddressIPPort(net.ParseIP(ip), uint16(port), 0)
	// Give first goroutine something to do :)
	outgoingAddr <- home

MainLoop:
	for {
		// This select statement does one of 3 things:
		// [1] Receives lists of addresses to search and hands them off to connection workers
		// [2] Receives responding nodes from child workers
		// [3] Times out execution of the script and cleans up
		select {
		case addrs = <-incomingAddrs:
			for i := range addrs {
				addr := addrs[i]
				key := addressFmt(*addr)
				if _, ok := visited[key]; !ok {
					cnt += 1
					outgoingAddr <- addr
				}
				// empty struct
				visited[key] = struct{}{}
			}
		case node = <-liveNodes:
			addrMap[key(node)] = node
		case <-timer.C:
			fmt.Printf("Run Summary:\nNodes responding: %d\nNodes buffered: %d\nNodes visited: %d\n", len(addrMap), cnt, len(visited))
			outs := ""
			for addrStr, node := range addrMap {
				outs += addrStr + " " + node.UserAgent + "\n"
			}
			ioutil.WriteFile(*outFile, []byte(outs), 0644)
			break MainLoop
		}
	}
}
Exemplo n.º 8
0
// newOutbountPeer returns a new outbound bitcoin peer for the provided server and
// address and connects to it asynchronously. If the connection is successful
// then the peer will also be started.
func newOutboundPeer(s *server, addr string, persistent bool) *peer {
	p := newPeerBase(s, false)
	p.addr = addr
	p.persistent = persistent

	// Setup p.na with a temporary address that we are connecting to with
	// faked up service flags.  We will replace this with the real one after
	// version negotiation is successful.  The only failure case here would
	// be if the string was incomplete for connection so can't be split
	// into address and port, and thus this would be invalid anyway.  In
	// which case we return nil to be handled by the caller.  This must be
	// done before we fork off the goroutine because as soon as this
	// function returns the peer must have a valid netaddress.
	ip, portStr, err := net.SplitHostPort(addr)
	if err != nil {
		p.logError("Tried to create a new outbound peer with invalid "+
			"address %s: %v", addr, err)
		return nil
	}

	port, err := strconv.ParseUint(portStr, 10, 16)
	if err != nil {
		p.logError("Tried to create a new outbound peer with invalid "+
			"port %s: %v", portStr, err)
		return nil
	}
	p.na = btcwire.NewNetAddressIPPort(net.ParseIP(ip), uint16(port), 0)

	go func() {
		// Select which dial method to call depending on whether or
		// not a proxy is configured.  Also, add proxy information to
		// logged address if needed.
		dial := net.Dial
		faddr := addr
		if cfg.Proxy != "" {
			proxy := &socks.Proxy{
				Addr:     cfg.Proxy,
				Username: cfg.ProxyUser,
				Password: cfg.ProxyPass,
			}
			dial = proxy.Dial
			faddr = fmt.Sprintf("%s via proxy %s", addr, cfg.Proxy)
		}

		// Attempt to connect to the peer.  If the connection fails and
		// this is a persistent connection, retry after the retry
		// interval.
		for atomic.LoadInt32(&p.disconnect) == 0 {
			log.Debugf("SRVR: Attempting to connect to %s", faddr)
			conn, err := dial("tcp", addr)
			if err != nil {
				p.retrycount += 1
				log.Debugf("SRVR: Failed to connect to %s: %v",
					faddr, err)
				if !persistent {
					p.server.donePeers <- p
					return
				}
				scaledInterval := connectionRetryInterval.Nanoseconds() * p.retrycount / 2
				scaledDuration := time.Duration(scaledInterval)
				log.Debugf("SRVR: Retrying connection to %s "+
					"in %s", faddr, scaledDuration)
				time.Sleep(scaledDuration)
				continue
			}

			// While we were sleeping trying to connect, the server
			// may have scheduled a shutdown.  In that case ditch
			// the peer immediately.
			if atomic.LoadInt32(&p.disconnect) == 0 {
				p.timeConnected = time.Now()
				p.server.addrManager.Attempt(p.na)

				// Connection was successful so log it and start peer.
				log.Debugf("SRVR: Connected to %s",
					conn.RemoteAddr())
				p.conn = conn
				atomic.AddInt32(&p.connected, 1)
				p.retrycount = 0
				p.Start()
			}

			return
		}
	}()
	return p
}