Skip to content

Latest commit

 

History

8 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 

Repository files navigation

pirate-seeder

A crawler for the Pirate Chain P2P network that exposes a list of reliable nodes via a built-in authoritative DNS server - the same role a Bitcoin-style "DNS seed" plays for any Bitcoin-derived network, run here for Pirate (ARRR).

It also crawls I2P peers directly through a local I2P router's SAM bridge (e.g. TreasureChest's embedded pirate-i2pd), and can reach Tor peers through a SOCKS5 proxy.

Features

  • Connects outbound to known peers over TLS 1.3 (TreasureChest enforces TLS on P2P connections by default and drops plaintext ones), does the version/verack handshake, and asks for their address book (getaddr/addr/addrv2) to discover more.
  • Understands modern Tor v3 (.onion) and I2P (.b32.i2p) addresses via addrv2 (BIP155), not just IPv4/IPv6.
  • Scores each peer's reliability over exponentially-weighted 2h/8h/1d/1w/1M windows, and bans or temporarily ignores consistently bad ones.
  • Answers DNS A/AAAA/NS/SOA queries for a configured hostname with a random sample of currently-good peers, plus the x<hex-service-flags>.host filtered-query convention wallets use to ask for peers with specific service bits.
  • Event-driven (libevent) rather than one OS thread per crawled connection, so one process can have many crawls in flight at once; SOCKS5/SAM dials (which need a blocking handshake libevent has no native support for) run on a small dedicated worker pool and hand the connected socket off to the same async code path used for direct connections.
  • Low memory and CPU footprint - this is a crawler and a tiny DNS server, not a full node.

Requirements

Ubuntu/Debian:

sudo apt-get install build-essential pkg-config libssl-dev libevent-dev

Building

make            # release build -> ./pirate-seeder
make asan       # debug build with ASan/UBSan, for development only
sudo make install PREFIX=/usr/local

Running

pirate-seeder needs a subdomain delegated to it via DNS, not just an A record pointing at it - delegation is what lets it answer every query for that subdomain dynamically (rotating through whichever peers currently score well) instead of a DNS provider just handing back one fixed IP forever. That delegation happens at your DNS provider, once, before you ever run the binary; the pieces then map directly onto its command-line flags as follows.

1. Pick two hostnames

  • Seed hostname - the name wallets/nodes will actually query, e.g. dnsseed.example.com. This becomes -h.
  • Nameserver hostname - the name that identifies this VPS as a nameserver, e.g. ns-dnsseed.example.com. This becomes -n. It does not need to be (and usually isn't) the same as the seed hostname.

2. Create exactly two records at your DNS provider

# Name Type Content Notes
1 ns-dnsseed.example.com A <this VPS's public IP> Must not be proxied/CDN'd (e.g. on Cloudflare, "DNS only" / grey cloud, not orange). A CDN proxy only forwards HTTP(S); it can't forward raw DNS queries, so a proxied record here would silently break everything downstream.
2 dnsseed.example.com NS ns-dnsseed.example.com This is the actual delegation. NS records aren't proxiable, so there's no toggle to worry about here.

Record 1 is glue - it's just how resolvers find the VPS at all. Record 2 is what actually hands authority for dnsseed.example.com over to that VPS; after it propagates, your DNS provider no longer answers queries for that name (or any name under it) itself, it just refers resolvers to record 1's target.

Nothing else needs to exist in your DNS provider for this - no SOA record (providers don't let you create one manually; see below), no separate record for the -m mailbox, no wildcard.

3. Run it

./pirate-seeder -h dnsseed.example.com -n ns-dnsseed.example.com -m admin.example.com
Flag Value Where it came from
-h dnsseed.example.com the name you're serving (record 2's Name)
-n ns-dnsseed.example.com the nameserver identity (record 2's Content, == record 1's Name)
-m admin.example.com your contact e-mail with @ replaced by . - reported in SOA records, not a DNS record itself

Run this on the VPS whose IP is in record 1 - pirate-seeder binds a local UDP port; it isn't told the domain name, so it has to physically be the machine that record 1 points at.

4. Verify from any other machine

dig NS dnsseed.example.com      # should show ns-dnsseed.example.com
dig A dnsseed.example.com       # should return one or more live peer IPs

If step 4 returns nothing, double check record 1 isn't proxied/CDN'd (the most common cause) and that UDP port 53 is actually reachable on the VPS (see "Running as non-root" below if you're not running as root).

Why there's no SOA record to create

DNS providers only let you create record types that make sense as one entry among many in a zone you own (A, NS, CNAME, ...). SOA is different - it's a single, automatic property of owning a zone, not something you add to one, so no provider exposes it as a creatable type. Once record 2 delegates dnsseed.example.com away, pirate-seeder is the owner of that zone as far as the rest of the internet is concerned, and it generates its own SOA record on the fly from -n and -m (see WriteRecordSoa in src/dns_server.cpp) - there's nothing to configure for it beyond those two flags you already set in step 3.

I2P

By default, pirate-seeder tries to discover a local I2P router's SAM bridge by reading -i2psam out of ~/.komodo/PIRATE/PIRATE.conf (the same key lightwalletd reads for its own I2P support), falling back to i2pd's default of 127.0.0.1:7656 if no config is found. Override with --i2p-sam <ip:port>, or point at a specific conf file with --pirate-conf <path>. If no SAM bridge is reachable, I2P peers are simply skipped rather than penalized - they're re-queued for whenever a bridge does become available.

Tor

Tor peers need a SOCKS5 proxy to dial out through, since this seeder doesn't resolve .onion addresses itself - point -o at one:

./pirate-seeder -h dnsseed.example.com -n ns-dnsseed.example.com -m admin.example.com \
  -o 127.0.0.1:9050

(TreasureChest's own embedded Tor currently only runs a control port, not a SOCKS proxy, so this needs a separately-run Tor with SocksPort enabled - either a system Tor package, or your own instance.)

Running as non-root

Binding UDP port 53 needs root. To run pirate-seeder unprivileged, redirect port 53 to an unprivileged port instead of running the process as root:

sudo iptables -t nat -A PREROUTING -p udp --dport 53 -j REDIRECT --to-port 5353
./pirate-seeder -h dnsseed.example.com -n ns-dnsseed.example.com -m admin.example.com -p 5353

Options

  -h, --host <host>       Hostname of the DNS seed
  -n, --ns <ns>           Hostname of the nameserver
  -m, --mbox <mbox>       Contact e-mail for SOA records ('@' replaced by '.')
  -t, --threads <n>       Concurrent P2P crawl sessions (default 64)
      --dial-threads <n>  Worker threads for SOCKS5/SAM dials (default 8)
  -d, --dnsthreads <n>    DNS server instances, SO_REUSEPORT (default 4)
  -p, --port <port>       UDP port for the DNS server (default 53)
  -o, --onion <ip:port>   SOCKS5 proxy for Tor peers
  -i, --proxyipv4 <a:p>   SOCKS5 proxy for IPv4 peers
  -k, --proxyipv6 <a:p>   SOCKS5 proxy for IPv6 peers
      --i2p-sam <ip:port> I2P SAM bridge for crawling I2P peers
      --pirate-conf <path> PIRATE.conf to read -i2psam from
  -w, --filter <f1,f2,..> Allowed service-flag filters for x<hex>.host queries
      --db <path>         Address database path (default: dnsseed.dat)
      --testnet           Use testnet parameters
      --wipeban           Clear the persisted ban list on startup
      --wipeignore        Clear persisted ignore timers on startup

Network parameters

Mainnet/testnet magic bytes, default ports, and protocol version are defined in src/wire.h, copied from TreasureChest's src/chainparams.cpp and src/version.h. If Pirate's network parameters ever change, update both places together.

Design notes

This is a from-scratch modernization of the design pioneered by Pieter Wuille's original bitcoin-seeder: a crawler plus a small hand-rolled authoritative DNS server, since a general-purpose DNS server can't dynamically rotate its answers based on which peers are currently reachable. That overall shape carries over well to any Bitcoin-derived network and didn't need reinventing - what changed is the implementation: modern C++17 throughout, libevent instead of a thread per crawled connection, BIP155 (addrv2) address support so Tor v3 and I2P peers can actually be represented and gossiped (the old fixed 16-byte address format they came from physically can't hold either), an I2P SAM client for crawling I2P peers directly, and TLS on every direct/proxied P2P connection (via libevent's OpenSSL bufferevent wrapper) since TreasureChest's net.cpp enforces it by default and closes the socket on a failed handshake with no plaintext fallback - a plaintext-only crawler simply can't reach real peers on this network.

License

MIT, see LICENSE.

About

No description, website, or topics provided.

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages