// 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 }
// 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 }
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") }
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() }
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 }
// 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 }
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 } } }
// 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 }