叮当猫咪
公共IP地址是一个模糊的概念,在实践中,它可能是也可能不是静态地址。你对此了解多少?它只是一个在一定时间内有效的终结点,这取决于许多因素,例如使用哪个接口发出查询。我们可以使用主线位托伦特 dht 给我们一些指示。Go 语言提供了由阿纳克罗利克斯编写的很酷的 dht 包。当使用谓词查询节点时,我们会收到一个数据包,其中包含对等方与我们的查询关联的远程IP地址。这在 bep10 中进行了描述。find_peers如果UDP连接不是一个好的选择,您可以选择查询比特跟踪器,如bep24中所述考虑到对等方可能是恶意的,因此结果越多越好。下面的程序输出与从查询的节点队列的 POV 启动查询的计算机关联的外部网络地址列表。地址按响应数评分。另读 https://www.bittorrent.org/beps/bep_0005.htmlfound 9 bootstrap peersfound 6 peers4 [2001:861:51c5:xxx:40d1:8061:1fe0:xxx]:90902 81.96.42.191:90904同行告诉我们我们正在使用,我们可以推断这是ipv6。[2001:861:51c5:xxx:40d1:8061:1fe0:xxx]:90902他们告诉我们正在使用,ipv4接口。81.96.42.191:9090package mainimport ( "encoding/json" "errors" "fmt" "io/ioutil" "log" "net" "os" "sort" "sync" "time" "github.com/anacrolix/dht" "github.com/anacrolix/dht/krpc" "github.com/anacrolix/torrent/bencode")var maxTimeout = time.Second * 5func main() { b, _ := ioutil.ReadFile("db.json") var rawAddrs []string json.Unmarshal(b, &rawAddrs) defer func() { if len(rawAddrs) < 1 { return } if len(rawAddrs) > 30 { rawAddrs = rawAddrs[:30] } buf, err := json.Marshal(rawAddrs) if err != nil { panic(err) } err = ioutil.WriteFile("db.json", buf, os.ModePerm) if err != nil { panic(err) } fmt.Fprintf(os.Stderr, "%v peers recorded\n", len(rawAddrs)) }() bootstrap, err := parseAddrs(rawAddrs) if err != nil { bootstrap, err = globalBootstrapAddrs() if err != nil { panic(err) } } findPeers := []byte(`d1:ad2:id20:abcdefghij01234567899:info_hash20:mnopqrstuvwxyz123456e1:q9:get_peers1:t2:aa1:y1:qe`) local, err := net.ResolveUDPAddr("udp", "0.0.0.0:9090") if err != nil { panic(err) } ln, err := net.ListenUDP("udp", local) if err != nil { panic(err) } addrscores := map[string]int{} var drain drain defer drain.Wait() fmt.Fprintf(os.Stderr, "found %v bootstrap peers\n", len(bootstrap)) res, errs := readResponses(ln, len(bootstrap), sendQuery(ln, bootstrap, findPeers)) drain.Errors(errs) peers := []net.Addr{} for d := range res { if isValidAddr(d.IP.UDP()) { addrscores[d.IP.String()]++ d.R.ForAllNodes(func(arg1 krpc.NodeInfo) { peers = append(peers, arg1.Addr.UDP()) }) } } if len(peers) > 0 { fmt.Fprintf(os.Stderr, "found %v peers\n", len(peers)) res, errs = readResponses(ln, len(peers), sendQuery(ln, peers, findPeers)) drain.Errors(errs) for d := range res { if isValidAddr(d.IP.UDP()) { addrscores[d.IP.String()]++ } } } for _, peer := range peers { if isValidAddr(peer) { rawAddrs = append(rawAddrs, peer.String()) } } addrs := make([]string, 0, len(addrscores)) for addr := range addrscores { addrs = append(addrs, addr) } sort.Slice(addrs, func(i int, j int) bool { return addrscores[addrs[i]] > addrscores[addrs[j]] }) for _, addr := range addrs { fmt.Printf("%-4v %v\n", addrscores[addr], addr) }}type drain struct{ sync.WaitGroup }func (d *drain) Errors(errs <-chan error) { d.Add(1) go func() { defer d.Done() for err := range errs { fmt.Fprintln(os.Stderr, err) } }()}func parseAddrs(rawAddrs []string) (addrs []net.Addr, err error) { for _, s := range rawAddrs { host, port, err := net.SplitHostPort(s) if err != nil { panic(err) } ua, err := net.ResolveUDPAddr("udp", net.JoinHostPort(host, port)) if err != nil { log.Printf("error resolving %q: %v", host, err) continue } addrs = append(addrs, ua) } if len(addrs) == 0 { err = errors.New("nothing resolved") } return}func globalBootstrapAddrs() (addrs []net.Addr, err error) { bootstrap, err := dht.GlobalBootstrapAddrs("udp") if err != nil { return nil, err } for _, b := range bootstrap { addrs = append(addrs, b.Raw()) } return}func isValidAddr(addr net.Addr) bool { // so weird guys. return addr.String() != "<nil>" && addr.String() != ":0"}func sendQuery(ln *net.UDPConn, peers []net.Addr, query []byte) chan error { errs := make(chan error) for _, addr := range peers { go func(addr net.Addr) { _, err := ln.WriteTo(query, addr) if err != nil { errs <- addressedError{Op: "send", error: err, Addr: addr} } }(addr) } return errs}func readResponses(ln *net.UDPConn, count int, errs chan error) (<-chan krpc.Msg, <-chan error) { data := make(chan krpc.Msg) var wg sync.WaitGroup for i := 0; i < count; i++ { wg.Add(1) go func() { defer wg.Done() buf := make([]byte, 1000) ln.SetReadDeadline(time.Now().Add(maxTimeout)) n, remoteAddr, err := ln.ReadFromUDP(buf) if err != nil { errs <- addressedError{Op: "rcv", error: err, Addr: remoteAddr} return } var m krpc.Msg err = bencode.Unmarshal(buf[:n], &m) if err != nil { errs <- addressedError{Op: "rcv", error: err, Addr: remoteAddr} return } data <- m }() } go func() { wg.Wait() close(errs) close(data) }() return data, errs}type addressedError struct { error Op string Addr net.Addr}func (a addressedError) Error() string { if !isValidAddr(a.Addr) { return fmt.Sprintf("%-5v %v", a.Op, a.error.Error()) } return fmt.Sprintf("%-5v %v: %v", a.Op, a.Addr.String(), a.error.Error())}