diff --git a/chaincfg/params.go b/chaincfg/params.go index 120fe0c4..7165f4a7 100644 --- a/chaincfg/params.go +++ b/chaincfg/params.go @@ -50,6 +50,16 @@ type Checkpoint struct { Hash *chainhash.Hash } +// DNSSeed identifies a DNS seed. +type DNSSeed struct { + // Host defines the hostname of the seed. + Host string + + // HasFiltering defines whether the seed supports filtering + // by service flags (wire.ServiceFlag). + HasFiltering bool +} + // Params defines a Bitcoin network by its parameters. These parameters may be // used by Bitcoin applications to differentiate networks as well as addresses // and keys for one network from those intended for use on another network. @@ -65,7 +75,7 @@ type Params struct { // DNSSeeds defines a list of DNS seeds for the network that are used // as one method to discover peers. - DNSSeeds []string + DNSSeeds []DNSSeed // GenesisBlock defines the first block of the chain. GenesisBlock *wire.MsgBlock @@ -155,14 +165,14 @@ var MainNetParams = Params{ Name: "mainnet", Net: wire.MainNet, DefaultPort: "8333", - DNSSeeds: []string{ - "seed.bitcoin.sipa.be", - "dnsseed.bluematt.me", - "dnsseed.bitcoin.dashjr.org", - "seed.bitcoinstats.com", - "seed.bitnodes.io", - "bitseed.xf2.org", - "seed.bitcoin.jonasschnelli.ch", + DNSSeeds: []DNSSeed{ + {"seed.bitcoin.sipa.be", true}, + {"dnsseed.bluematt.me", true}, + {"dnsseed.bitcoin.dashjr.org", false}, + {"seed.bitcoinstats.com", true}, + {"seed.bitnodes.io", false}, + {"bitseed.xf2.org", false}, + {"seed.bitcoin.jonasschnelli.ch", true}, }, // Chain parameters @@ -235,7 +245,7 @@ var RegressionNetParams = Params{ Name: "regtest", Net: wire.TestNet, DefaultPort: "18444", - DNSSeeds: []string{}, + DNSSeeds: []DNSSeed{}, // Chain parameters GenesisBlock: ®TestGenesisBlock, @@ -288,10 +298,11 @@ var TestNet3Params = Params{ Name: "testnet3", Net: wire.TestNet3, DefaultPort: "18333", - DNSSeeds: []string{ - "testnet-seed.bitcoin.schildbach.de", - "testnet-seed.bitcoin.petertodd.org", - "testnet-seed.bluematt.me", + DNSSeeds: []DNSSeed{ + {"testnet-seed.bitcoin.jonasschnelli.ch", true}, + {"testnet-seed.bitcoin.schildbach.de", false}, + {"seed.tbtc.petertodd.org", true}, + {"testnet-seed.bluematt.me", false}, }, // Chain parameters @@ -351,7 +362,7 @@ var SimNetParams = Params{ Name: "simnet", Net: wire.SimNet, DefaultPort: "18555", - DNSSeeds: []string{}, // NOTE: There must NOT be any seeds. + DNSSeeds: []DNSSeed{}, // NOTE: There must NOT be any seeds. // Chain parameters GenesisBlock: &simNetGenesisBlock, @@ -416,6 +427,11 @@ var ( hdPrivToPubKeyIDs = make(map[[4]byte][]byte) ) +// String returns the hostname of the DNS seed in human-readable form. +func (d DNSSeed) String() string { + return d.Host +} + // Register registers the network parameters for a Bitcoin network. This may // error with ErrDuplicateNet if the network is already registered (either // due to a previous Register call, or the network being one of the default diff --git a/connmgr/seed.go b/connmgr/seed.go index e4715372..8c7a0e0d 100644 --- a/connmgr/seed.go +++ b/connmgr/seed.go @@ -5,6 +5,7 @@ package connmgr import ( + "fmt" mrand "math/rand" "net" "strconv" @@ -29,19 +30,28 @@ type OnSeed func(addrs []*wire.NetAddress) type LookupFunc func(string) ([]net.IP, error) // SeedFromDNS uses DNS seeding to populate the address manager with peers. -func SeedFromDNS(chainParams *chaincfg.Params, lookupFn LookupFunc, seedFn OnSeed) { - for _, seeder := range chainParams.DNSSeeds { - go func(seeder string) { +func SeedFromDNS(chainParams *chaincfg.Params, reqServices wire.ServiceFlag, + lookupFn LookupFunc, seedFn OnSeed) { + + for _, dnsseed := range chainParams.DNSSeeds { + var host string + if !dnsseed.HasFiltering || reqServices == wire.SFNodeNetwork { + host = dnsseed.Host + } else { + host = fmt.Sprintf("x%x.%s", uint64(reqServices), dnsseed.Host) + } + + go func(host string) { randSource := mrand.New(mrand.NewSource(time.Now().UnixNano())) - seedpeers, err := lookupFn(seeder) + seedpeers, err := lookupFn(host) if err != nil { - log.Infof("DNS discovery failed on seed %s: %v", seeder, err) + log.Infof("DNS discovery failed on seed %s: %v", host, err) return } numPeers := len(seedpeers) - log.Infof("%d addresses found from DNS seed %s", numPeers, seeder) + log.Infof("%d addresses found from DNS seed %s", numPeers, host) if numPeers == 0 { return @@ -61,6 +71,6 @@ func SeedFromDNS(chainParams *chaincfg.Params, lookupFn LookupFunc, seedFn OnSee } seedFn(addresses) - }(seeder) + }(host) } } diff --git a/server.go b/server.go index 4fc28aea..6fcb7238 100644 --- a/server.go +++ b/server.go @@ -40,6 +40,10 @@ const ( // the server. defaultServices = wire.SFNodeNetwork | wire.SFNodeBloom + // defaultRequiredServices describes the default services that are + // required to be supported by outbound peers. + defaultRequiredServices = wire.SFNodeNetwork + // defaultMaxOutbound is the default number of max outbound peers. defaultMaxOutbound = 8 @@ -1627,14 +1631,15 @@ func (s *server) peerHandler() { if !cfg.DisableDNSSeed { // Add peers discovered through DNS to the address manager. - connmgr.SeedFromDNS(activeNetParams.Params, btcdLookup, func(addrs []*wire.NetAddress) { - // Bitcoind uses a lookup of the dns seeder here. This - // is rather strange since the values looked up by the - // DNS seed lookups will vary quite a lot. - // to replicate this behaviour we put all addresses as - // having come from the first one. - s.addrManager.AddAddresses(addrs, addrs[0]) - }) + connmgr.SeedFromDNS(activeNetParams.Params, defaultRequiredServices, + btcdLookup, func(addrs []*wire.NetAddress) { + // Bitcoind uses a lookup of the dns seeder here. This + // is rather strange since the values looked up by the + // DNS seed lookups will vary quite a lot. + // to replicate this behaviour we put all addresses as + // having come from the first one. + s.addrManager.AddAddresses(addrs, addrs[0]) + }) } go s.connManager.Start()