func TestTrackerClient(t *testing.T) { Convey("Should make an HTTP GET request and receive response", t, func() { ts := newTestServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { w.WriteHeader(200) w.Header().Set("Content-Type", "text/plain") fakeResp := "\x64\x38\x3a\x63\x6f\x6d\x70\x6c\x65\x74\x65\x69\x31\x31\x30\x37\x65\x31\x30\x3a\x64\x6f\x77\x6e\x6c\x6f\x61\x64\x65\x64\x69\x33\x35\x30\x34\x34\x65\x31\x30\x3a\x69\x6e\x63\x6f\x6d\x70\x6c\x65\x74\x65\x69\x32\x32\x36\x65\x38\x3a\x69\x6e\x74\x65\x72\x76\x61\x6c\x69\x31\x39\x36\x32\x65\x31\x32\x3a\x6d\x69\x6e\x20\x69\x6e\x74\x65\x72\x76\x61\x6c\x69\x39\x38\x31\x65\x35\x3a\x70\x65\x65\x72\x73\x31\x32\x30\x30\x3a\x25\xed\xc0\x31\xc8\xd5\x69\x67\x2d\xab\xd4\x44\x57\x08\x68\x1d\xc8\xd5\x71\x15\x46\x9b\x6d\x8d\xc5\x01\xf0\x38\x9f\xb4\xc9\x3e\x59\xc9\xae\x3a\x29\x6f\x07\xfd\x91\xe5\x2e\xa6\xbf\x0d\xef\x33\x75\xcc\xc0\x2c\x9b\x0a\x29\xc8\xea\x7d\xc8\x53\xb1\x07\x71\xe0\x83\xd7\x69\x63\x1c\xaf\x82\x7b\x7d\x14\xa1\x1d\x34\x41\x75\xd0\x66\xaf\x44\x17\x7c\xfd\xdb\xe0\x57\xaa\xdf\x49\xc2\x09\x11\x21\x55\x60\x57\x7f\x99\x62\xbf\x07\xc1\x24\x1a\xe1\x3b\x98\x63\x02\xeb\x64\x4f\xb0\x23\x16\x8b\x34\x56\x9a\xb1\x4b\x1a\xe1\x78\x3b\xb3\xec\x67\xee\x9f\x00\x5d\x5a\xd6\x6b\xbd\x0a\x47\x20\x6e\x8b\xc5\xd5\x11\xa6\x8f\xc7\x31\xee\x29\xc4\x93\x3a\x5f\x9f\x38\x98\x1a\xe1\x69\x62\x5c\x87\x50\xab\x67\x2c\x31\xe1\xc2\x42\x62\xd1\x32\xd3\x72\xaf\x59\x02\xc9\xa8\xc8\xd5\x58\x82\x16\xbe\x74\xa7\x54\xd3\x12\xe3\xc8\xd5\x4f\x0c\xf7\x13\xb2\x72\x3e\xd2\x6e\xd4\xaf\xc8\x29\x8d\x8a\x08\x85\x9c\x25\x83\xbb\x0f\xff\x98\x1f\xad\xf2\x0c\x54\xbb\xd8\xac\x8e\x36\xb3\xed\xd4\x53\xb0\x26\x1a\xe1\xc6\x07\x39\xc5\xc8\xd5\xc5\x02\xd0\x37\xac\x1e\xc3\x9a\xbc\x68\xaf\xc8\xbd\x1b\x84\x52\xb9\x11\xbc\x5d\x6f\x03\xc8\xd5\xb9\x15\xd8\x98\xd7\xa3\xb5\xb0\x23\x18\x2b\xfd\xb1\x10\xe6\xfd\xa1\xe3\x82\x2b\x37\x66\x1a\xf4\x6d\xad\x60\x36\x7d\x7b\x67\x39\x51\x60\xa7\xb0\x5e\x8f\x2b\x49\x9d\xaa\x4c\xbe\xdc\x2a\x3e\x7a\x4a\x5d\x80\xad\xfc\x28\x49\xca\x36\xad\xc8\x7a\x32\x4a\x4d\x32\xc8\xd5\x29\xbe\x10\x22\x51\xfe\x29\x65\x83\x4d\x7a\x20\x25\xbb\x63\x93\x5d\x45\xc9\xbe\x5d\x73\x46\xca\xbd\xe9\x51\x91\x96\x89\xbb\x3e\x2a\x32\x7b\x67\xb5\x01\x47\xce\x64\x58\x77\x6e\x4f\x51\x5d\x45\x6b\x98\x09\x21\x23\x27\x5f\x10\x49\x28\xdf\xa8\x5b\xd2\xc0\x2f\x1a\xe1\x55\x9a\x69\xd5\x28\x72\x53\xfa\x05\x18\xc8\xd5\x43\xa1\xd1\x18\x23\x27\x25\xbb\x81\xa6\xb3\xed\x25\x8e\xc9\x0b\xde\xb2\x05\x4f\x4a\xd3\xd3\x33\xc4\xd9\x9c\x8c\x85\x9c\xbd\xca\x10\xb8\x94\x33\xbc\xa8\x22\xf7\x2d\x8c\xbb\x05\xed\xf9\x81\x8f\xb5\x88\x86\x20\x2d\x26\xb3\x9c\x63\x0b\x95\x94\xab\x05\xd6\x68\x62\xd6\x95\x14\x36\xda\xc8\xd5\x6d\xfe\x33\x2b\xc8\xd5\x57\x67\xd3\xd6\xf4\x5b\x55\xcb\x79\x20\xc8\xd5\x4e\x8a\x87\x1c\x1a\xe1\x32\x53\x30\x50\x05\xdc\x29\x60\x0e\x92\x11\x5c\xc9\x4a\xa4\x22\x3d\x3f\xbf\xfe\x6d\x66\x97\x8e\xbe\xd6\xbb\x0d\xf7\xc2\xb5\xef\x17\xa9\x93\xee\xb2\x22\x9a\x82\x88\xad\xb1\x29\xf3\x1b\x92\x2b\xb1\x09\x13\xad\x7d\x8e\x6c\x21\x7f\xe1\xb0\x88\x60\xfe\x70\x26\xfd\xa4\x59\xd8\x81\x23\x51\xdf\x55\xd8\x37\xb5\xf8\x94\x55\xae\x3f\xe6\xc8\xd5\x52\xe0\x7e\x39\xab\x61\x4e\x01\x4c\xa7\xbd\x16\x47\xbf\x0c\xb2\xf4\xad\x46\x24\xc5\xe9\xc8\xd5\x2e\x82\x70\xc4\x93\x8e\x25\xed\x16\x6f\xae\x90\x05\x66\x9b\xd7\x6b\xfd\x02\xbe\x0d\x30\xb3\xf5\xd5\x50\x78\x74\x1b\x48\xc5\xcf\x77\xae\x3e\x3d\xc4\xcd\xcf\x83\x76\xcb\xbd\xc5\x30\x43\x83\x0c\xba\xb6\xd5\xe7\xf6\x02\xb9\x15\xd8\xb6\xe2\xf6\xb3\xc7\x99\xe1\xa2\xde\xb1\xb3\xb5\x22\xe5\x14\xb1\x6a\xdb\x73\x88\x63\x96\x81\x8d\x7e\x62\x80\x67\xe5\xca\xa2\x69\x03\x5e\x17\x12\x36\xaf\xc8\x55\x48\xea\x2d\xcc\xa4\x52\xe9\x3d\x1c\x58\xd8\x51\xc4\xd1\xcb\x73\x60\x4d\x5f\x39\x88\x8a\x0d\x40\xc9\xf4\x3a\xc8\xd5\x29\xf8\xc0\xe0\x36\x6d\x29\x2b\x4d\xd1\x56\x6c\x25\x92\x7f\xb6\x81\xc7\x18\x06\xc3\xb6\xd0\x5d\xc9\x4b\x6e\xf3\x48\x16\xc5\x00\x92\x89\xb1\x12\xbb\x55\x87\x9c\xf1\x5f\xb9\x15\xd9\x15\xe6\xd1\x9a\x44\x04\x58\xa9\x60\x97\x4d\x88\x1c\xc2\xa9\x69\x9a\x73\x76\x9e\xc9\x5f\x71\x64\x53\xea\x62\x57\x30\x96\x4b\x1a\xe1\x53\xae\xe1\x48\x53\xe6\x4f\xa5\x5f\x85\x2b\xc0\x4e\x19\x20\xca\xa2\xc0\x32\xb3\x66\xcd\xcd\xde\x2e\xb9\xe7\xdf\xbe\x78\x18\x1b\x7c\x21\x53\x20\x02\x33\xa9\x0a\x1a\xe1\xc9\x53\x17\x38\x59\x5e\xc8\x4b\xb0\x54\x74\x17\xc3\x9a\x6f\x1e\xc1\xd7\xbd\xdf\xb0\xcd\x3f\x0a\xba\x7d\x08\xf8\x1a\xe1\xb5\xae\x69\x20\xac\x0a\xb1\x17\xc8\xfb\x07\xd0\x95\xff\xe0\x24\x80\xda\x5f\x4f\x60\x07\xc8\xd5\x5c\x35\x22\x0f\x53\xad\x4f\x9a\xaa\x6a\xc9\x0c\x49\xa8\x5b\x14\x2b\x17\x3b\x5a\x8b\xfb\x64\x63\x32\x1b\xe0\x8a\x1a\xe1\x18\x83\x74\x10\xd3\x00\x05\x00\x5e\x97\x97\x11\xd4\xae\x51\x45\xdd\x9c\xc9\x83\x45\x63\xc8\xd5\xbe\x2d\x1e\x69\x53\x2c\xbd\x52\xd6\x5e\x9d\x71\xb9\x15\xd8\xa3\xdd\xdb\xb1\xce\x10\x7b\x5b\xac\xb0\x64\x4c\x04\x2a\x13\x74\x5b\x1e\xdd\xec\xcb\x69\x68\xee\xce\x66\x1e\x60\xea\x45\xb5\xc8\xd5\x5c\x28\xf8\xeb\x9f\xdb\x5a\xce\x0b\xc1\xd4\x79\x5a\x3d\x4e\xdf\xc8\xd5\x55\xcc\xb7\x5d\x39\xf3\x51\xea\x90\xe4\xa3\x7f\x51\xc4\x8e\xc0\xbb\xc3\x4e\x8b\xd1\xad\x46\x34\x4d\x2e\xf7\x15\x70\x6a\x41\x5c\xe4\x38\xd8\xe0\x29\x8d\x1d\xe1\x5d\xa0\x29\x8d\x1c\x57\x2e\x6a\x18\x2f\x78\xd7\x1a\xe1\xd5\xbf\xe4\x81\x27\x10\xc9\xf1\x19\x12\x1a\xe1\xc5\x09\x96\xb1\x1a\xe1\xc2\xe2\x9a\x3d\xde\xa7\xba\x87\x70\x72\xc3\x7a\xb2\xb8\xc4\x89\x30\x39\x82\xb9\x6d\x94\xcb\x19\x79\x98\xb7\x63\xd0\x55\x5c\x82\x46\x7f\xc8\xd5\x57\xcf\xc7\x06\xc8\xd5\x56\x61\x8d\x30\x8e\x6e\x50\x42\xf4\x7a\x8b\xb5\x4d\x5d\x7f\x2a\xc8\xd5\x45\x29\x0e\x82\xc8\x7a\x2e\xb4\xc4\xee\x4a\x42\x2e\xa6\xbf\x07\x5d\xb9\x02\x5c\x10\xd7\xef\xdc\xc9\x16\x26\xef\xd3\x28\x65" fmt.Fprint(w, fakeResp) })) tc := NewTrackerClient() tc.HTTP.Transport = &http.Transport{ Proxy: func(req *http.Request) (*url.URL, error) { return url.Parse(ts.URL) }, } filename := "../testfiles/kali-linux-2.0-i386.iso.torrent" metainfo := structure.NewMetainfo(filename) tReq := structure.NewTrackerRequest(metainfo) tResp, err := tc.MakeAnnounceRequest(tReq, "started") So(tc, ShouldNotBeNil) So(err, ShouldBeNil) So(tResp, ShouldNotBeNil) So(tResp.Complete, ShouldEqual, 1107) }) Convey("Should handle failures", t, func() { ts := newTestServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { w.WriteHeader(200) w.Header().Set("Content-Type", "text/plain") fakeResp := "d14:failure reason8:an errore" fmt.Fprint(w, fakeResp) })) tc := NewTrackerClient() tc.HTTP.Transport = &http.Transport{ Proxy: func(req *http.Request) (*url.URL, error) { return url.Parse(ts.URL) }, } filename := "../testfiles/kali-linux-2.0-i386.iso.torrent" metainfo := structure.NewMetainfo(filename) tReq := structure.NewTrackerRequest(metainfo) tResp, err := tc.MakeAnnounceRequest(tReq, "started") So(tc, ShouldNotBeNil) So(err, ShouldNotBeNil) So(tResp, ShouldNotBeNil) So(tResp.FailureReason, ShouldEqual, "an error") }) }
func main() { // Set up logging to file and stdout f, err := os.OpenFile("torro.log", os.O_APPEND|os.O_CREATE|os.O_RDWR, 0666) if err != nil { fmt.Printf("Error opening file: %v", err) } defer f.Close() mw := io.MultiWriter(os.Stdout, f) log.SetOutput(mw) println("TORRO!\n\n\n") // Read command line flags and arguments pPrint := flag.String("print", "metainfo", "either tokens, parsed, or metainfo") pUPNP := flag.Bool("upnp", false, "open port through UPNP") pAnnounce := flag.Bool("announce", false, "send announce request to tracker") flag.Parse() var filename string fmt.Println(flag.Args()) if len(flag.Args()) > 0 { filename = flag.Args()[0] } else { filename = "testfiles/TheInternetsOwnBoyTheStoryOfAaronSwartz_archive.torrent" } if *pUPNP { fmt.Println("Opening port through UPNP") d, _ := upnp.Discover() ip, _ := d.ExternalIP() _ = d.Forward(55555, "torro") defer d.Clear(55555) log.Printf("Discovered: %q\n", d) log.Printf("External IP: %q\n", ip) log.Printf("Location: %q\n", d.Location()) } // Read actual .torrent file fmt.Println("Parsing: ", filename) data, err := ioutil.ReadFile(filename) if err != nil { panic(err) } // Lex and Parse .torrent file torrentStr := string(data) lex := bencoding.BeginLexing(".torrent", torrentStr, bencoding.LexBegin) tokens := bencoding.Collect(lex) output := bencoding.Parse(tokens) result := output.Output.(map[string]interface{}) // Read .torrent metainfo and make request to the announce URL metainfo := structure.NewMetainfo(filename) c := client.NewTrackerClient() req := structure.NewTrackerRequest(metainfo) req.PeerID = "-qB3230-u~QGMmUs~yXH" req.Port = 55555 req.Compact = true req.NoPeerID = true if *pAnnounce { res, err := c.MakeAnnounceRequest(req, client.TrackerRequestStarted) if err != nil { fmt.Println(res.FailureReason) panic(err.Error()) } fmt.Println(res) log.Println("StartListening") port := 55555 peerId := []byte("-TR2840-nj5ovtkoz2ed") s := client.NewBTService(port, peerId) s.StartListening() } switch *pPrint { case "tokens": PrintTokens(&tokens) case "parsed": PrintParsedStructure(result) case "metainfo": PrintMetainfo(metainfo) default: PrintMetainfo(metainfo) } // time.Sleep(time.Second * 60) }