urlrustsha1bittorrenttorrent

Rust (Bittorrent): Failing at announcing, with response "Requested download is not authorized for use with this tracker"


I'm trying to find peers in the Bittorrent network, but I'm getting the response "Requested download is not authorized for use with this tracker". The torrent file I'm trying to download is "Ubuntu 20.04.2.0 Desktop (64-bit)" and it can be found here. I have checked against other Bittorrent-clients, and have confirmed that the info_hash is correct. I'm leaning towards that my error might be because of some incorrect url-encoding, but I'm not sure.

The networking part of code is using the reqwest crate. To url-encode the info_hash, I'm using the urlencode crate. Here is the code for url-encoding and sending the GET request:

let client = reqwest::blocking::Client::new();
   
let info_hash_encoded = urlencoding::encode_binary(&torrent.info_hash).into_owned().to_uppercase();
let resp = client
    .get(&torrent.announce)
    .query(&[
        ("info_hash", info_hash_encoded.as_str()),
        ("peer_id", PEER_ID),
        ("port", PORT),
        ("uploaded", "0"),
        ("downloaded", "0"),
        ("compact", "1"),
        ("left", torrent.length.to_string().as_str()),
    ])
    .send()?
    .text()?;

println!("{:?}", resp);

Where torrent.info_hash is the info hash as a byte vector (Vec<u8>).

Here is how the reqwest response actually looks like:

Response { url: Url { scheme: "https", cannot_be_a_base: false, username: "", password: None, host: Some(Domain("torrent.ubuntu.com")), port: None, path: "/announce", query: Some("info_hash=K%25A4%25FB%25F7%2523%251A%253AF%250E%2586%2589%2527%2507%25D2%255C%2513U3%25A1J&peer_id=-rqbt01-jsbckj94ksj3&port=5035&uploaded=0&downloaded=0&compact=1&left=2877227008"), fragment: None }, status: 200, headers: {"date": "Sat, 17 Jul 2021 17:05:25 GMT", "server": "Apache/2.4.18 (Ubuntu)", "content-length": "85", "content-type": "text/plain", "pragma": "no-cache", "vary": "Accept-Encoding"} }

I first thought the problem might be because the info_hash_encoded was in lowercase hex, but after uppercasing it, I'm still recieving the same error. By the way, the info hash in hex-form is: 4ba4fbf7231a3a660e86892707d25c135533a16a.

Thanks!

Edit: It turns out that the hash somehow got encoded twice, but I'm still having the same problem even after fixing that. Does anybody know what would be the correct url encoded info hash so I can compare it with what I currently have? I also tried implementing my own url encoding following this spec, but I am still recieving the same error.


Solution

  • I had two bugs that stopped this from working:

    1. info_hash was being encoded twice, resulting in "%" characters being encoded to "%25".
    2. Every non-numerical byte should be encoded as %<xx>, meaning "%7" should be "%07". I was missing leading zero's.

    Here is what worked for me:

    use std::error::Error;
    use std::fmt::Write;
    
    pub fn url_encode_bytes(content: &[u8]) -> Result<String, Box<dyn Error>> {
        let mut out: String = String::new();
    
        for byte in content.iter() {
            match *byte as char {
                '0'..='9' | 'a'..='z' | 'A'..='Z' | '.' | '-' | '_' | '~' => out.push(*byte as char),
                _ => write!(&mut out, "%{:02X}", byte)?,
            };
        }
    
        Ok(out)
    }
    

    I haven't figured out a nice solution to the double encoding issue, but currently I'm just creating the info_hash query manually like this:

    let url_builder = ureq::get(&torrent.announce)
        .query("peer_id", PEER_ID)
        .query("port", PORT)
        .query("uploaded", "0")
        .query("downloaded", "0")
        .query("compact", "1")
        .query("left", LENGTH);
    
    let url = format!(
        "{}{}",
        url_builder.url(),
        format!("&info_hash={}", url_encode_bytes(&torrent.info_hash)?)
    );
    

    I also switched from the reqwest crate to the ureq crate.
    The correct url-encoded hash (as far as I'm aware) is: K%A4%FB%F7%23%1A%3Af%0E%86%89%27%07%D2%5C%13U3%A1j.