Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Axum HTTP tracker: compact announce response in public mode #190

Conversation

josecelano
Copy link
Member

No description provided.

@josecelano josecelano changed the title Axum HTTP tracker: compact announce response in public mode Axum HTTP tracker: compact announce response in public mode Feb 20, 2023
@josecelano josecelano linked an issue Feb 20, 2023 that may be closed by this pull request
@josecelano
Copy link
Member Author

josecelano commented Feb 20, 2023

hi @WarmBeer I have some comments/questions regarding the compact announce response.

Questions

1.- Potential bug in the current implementation.

As I mentioned here, I think we are adding an extra "e" byte in the current response between the "peer" and "peer6" dictionary keys.

2.- I'm going to change the implementation to use the bip_bencode crate.

I've seen that @Power2All uses the bip_bencode crate here. I think that implementation is much cleaner.

3.- All keys in a Bencoded dictionary must be byte strings and must appear in lexicographical order.

In the current responses, keys are not ordered. I've already implemented the solution using the bip_bencode crate and the response is different.

I'm using this Bencode specification: https://en.wikipedia.org/wiki/Bencode

4.- Include one of both "peer" or "peer6" keys.

In the torrust-axum, only one of the keys appears, depending on whether the client IP is a IPV4 or IPV6 IP.

Reading the BEP, I assume we are doing the right thing by adding the extra key.

In case a compact response is requested, the tracker MAY add another key to the response; peers6. This key has the same layout as peers in compact mode, but instead of using 6 bytes per endpoint, 18 bytes are used. peers6 contains address-port pairs where the addresses are all IPv6.

5.- Include only IPV4 ips in "peer" key and IPV6 ips in "peer6" key.

We are always including both keys "peer" and "peer6", but we only add IPV4 ips in the "peer" key and IPV6 ips in the "peer6" keys.

In this case, I think we are doing it wrong because the BEP 07 says:

In case the tracker does not support the compact response as described in BEP-23, no change is necessary. Since the original peers response returns peer endpoints in their expanded string form, IPv6 addresses can be passed back this way.

So the normal announce response ("peer" key) includes both IPV4 and IPV6 peer ips.

Conclusion

In summary, I think I would:

  • Return always both keys "peer" and "peer6".
  • Include all IPs in both, regardless of the remote client IP type. I mean, even if the remote client uses IPV4, we include IPV6 peers in the "peer6" key.
  • In the "peer6" key, we convert IPV4 ips to IPV6.

@Power2All I think you are mixing IPV4 (6 bytes) and IPV6 (18 bytes) ips in the "peer6" key. How do you know where an IP finishes if not all the IPS have the same length?

cc @da2ce7

@josecelano josecelano marked this pull request as ready for review February 20, 2023 13:51
@josecelano josecelano force-pushed the issue-187-axum-http-tracker-compact-announce-req-public-mode branch from de3d90f to b7193b2 Compare February 20, 2023 13:51
@mickvandijke
Copy link
Member

mickvandijke commented Feb 20, 2023

Hi @josecelano

1.- Potential bug in the current implementation.

As I mentioned josecelano#1, I think we are adding an extra "e" byte in the current
response between the "peer" and "peer6" dictionary keys.

Yes I think you are right :').

2.- I'm going to change the implementation to use the bip_bencode crate.

I've seen that @Power2All is using that crate here. I think that implementation is much cleaner.

👍

3.- All keys in a Bencoded dictionary must be byte strings and must appear in lexicographical order.

In the current responses, keys are not ordered. I've already implemented the solution using the bip_bencode crate and the response is different.

I'm using this Bencode specification: https://en.wikipedia.org/wiki/Bencode

👍

4.- Include one of both "peer" or "peer6" keys.

In the torrust-axum, only one of the keys appears, depending on whether the client IP is a IPV4 or IPV6 IP.

Reading the BEP, I assume we are doing the right thing by adding the extra key.

In case a compact response is requested, the tracker MAY add another key to the response; peers6. This key has the same layout as peers in compact mode, but instead of using 6 bytes per endpoint, 18 bytes are used. peers6 contains address-port pairs where the addresses are all IPv6.

We already filter the peers for a certain ip version: https://github.com/torrust/torrust-tracker/blob/develop/src/tracker/torrent.rs#L58 . So I suppose we can also drop the empty peers or peers6 key in compact announce responses. However that might lead to side effects as it is not according to the spec.

5.- Include only IPV4 ips in "peer" key and IPV6 ips in "peer6" key.

We are always including both keys "peer" and "peer6", but we only add IPV4 ips in the "peer" key and IPV6 ips in the "peer6" keys.

In this case, I think we are doing it wrong because the BEP 07 says:

In case the tracker does not support the compact response as described in BEP-23, no change is necessary. Since the original peers response returns peer endpoints in their expanded string form, IPv6 addresses can be passed back this way.

So the normal announce response ("peer" key) includes both IPV4 and IPV6 peer ips.

We already pass all peers under one key peers in a non-compact response: https://github.com/torrust/torrust-tracker/blob/main/src/http/handlers.rs#L107 . Is this what you mean?

@josecelano
Copy link
Member Author

Hi @da2ce7 @WarmBeer, this is ready to review. I have fixed two bugs:

  • An extra byte b"e" in the compact response.
  • Dictionary keys were not sorted in the compact response.

I have not changed any other behaviour, but please read my comment above because we might need to introduce some changes. If we need to fix the current behaviour we can open a new issue.

@josecelano
Copy link
Member Author

josecelano commented Feb 20, 2023

Hi @josecelano

1.- Potential bug in the current implementation.

As I mentioned josecelano#1, I think we are adding an extra "e" byte in the current
response between the "peer" and "peer6" dictionary keys.

Yes I think you are right :').

2.- I'm going to change the implementation to use the bip_bencode crate.

I've seen that @Power2All is using that crate here. I think that implementation is much cleaner.

+1

3.- All keys in a Bencoded dictionary must be byte strings and must appear in lexicographical order.

In the current responses, keys are not ordered. I've already implemented the solution using the bip_bencode crate and the response is different.

I'm using this Bencode specification: https://en.wikipedia.org/wiki/Bencode

+1

4.- Include one of both "peer" or "peer6" keys.

In the torrust-axum, only one of the keys appears, depending on whether the client IP is a IPV4 or IPV6 IP.

Reading the BEP, I assume we are doing the right thing by adding the extra key.

In case a compact response is requested, the tracker MAY add another key to the response; peers6. This key has the same layout as peers in compact mode, but instead of using 6 bytes per endpoint, 18 bytes are used. peers6 contains address-port pairs where the addresses are all IPv6.

We already filter the peers for a certain ip version: https://github.com/torrust/torrust-tracker/blob/develop/src/tracker/torrent.rs#L58 . So I suppose we can also drop the empty peers or peers6 key in compact announce responses. However that might lead to side effects as it is not according to the spec.

5.- Include only IPV4 ips in "peer" key and IPV6 ips in "peer6" key.

We are always including both keys "peer" and "peer6", but we only add IPV4 ips in the "peer" key and IPV6 ips in the "peer6" keys.

In this case, I think we are doing it wrong because the BEP 07 says:

In case the tracker does not support the compact response as described in BEP-23, no change is necessary. Since the original peers response returns peer endpoints in their expanded string form, IPv6 addresses can be passed back this way.

So the normal announce response ("peer" key) includes both IPV4 and IPV6 peer ips.

We already pass all peers under one key peers in a non-compact response: https://github.com/torrust/torrust-tracker/blob/main/src/http/handlers.rs#L107 . Is this what you mean?

hi @WarmBeer ,

The Axum Torrust fork adds all IPs (V4 and V6) in both "peer" and "peer6".

I think it's wrong for the "peer" key (IPV4) because IPs would have different sizes. But for the "peer6" key, we could convert IPV4 ips into IPV6. My question is whether we should do that or not.

Additionally, The Axum Torrust fork filters IP depending on the client's IP. I mean, if the remote client is using an IPV4 IP, the response will include only the "peer" key (and not the "peer6" key) with both IPV4 and IPV6 peers. I would prefer always to return both of them as we do.

I'm always talking only about the compact response.

@josecelano
Copy link
Member Author

hey @WarmBeer I see what you told me:

#[must_use]
pub fn get_peers(&self, optional_excluded_address: Option<&SocketAddr>) -> Vec<&peer::Peer> {
    self.peers
        .values()
        .filter(|peer| match optional_excluded_address {
            // Don't filter on ip_version
            None => true,
            // Filter out different ip_version from remote_addr
            Some(excluded_address) => {
                // Skip ip address of client
                if peer.peer_addr.ip() == excluded_address.ip() {
                    return false;
                }

                match peer.peer_addr.ip() {
                    IpAddr::V4(_) => excluded_address.is_ipv4(),
                    IpAddr::V6(_) => excluded_address.is_ipv6(),
                }
            }
        })
        .take(MAX_SCRAPE_TORRENTS as usize)
        .collect()
}

If the client has an IPV4 IP, we remove all peers with IPV6 addresses even before building the compact response. I think we should rename that method because it filters out the client peer and all peers that do not use the same IP type/version as the client peer. Are you sure that's the correct behavior? I'm going to take a look at the fork's implementations. Maybe they are also doing the same before building the response.

@josecelano
Copy link
Member Author

josecelano commented Feb 20, 2023

Hey @WarmBeer, sorry, one more question. The function:

#[must_use]
pub fn get_peers(&self, optional_excluded_address: Option<&SocketAddr>) -> Vec<&peer::Peer> {
    self.peers
        .values()
        .filter(|peer| match optional_excluded_address {
            // Don't filter on ip_version
            None => true,
            // Filter out different ip_version from remote_addr
            Some(excluded_address) => {
                // Skip ip address of client
                if peer.peer_addr.ip() == excluded_address.ip() {
                    return false;
                }

                match peer.peer_addr.ip() {
                    IpAddr::V4(_) => excluded_address.is_ipv4(),
                    IpAddr::V6(_) => excluded_address.is_ipv6(),
                }
            }
        })
        .take(MAX_SCRAPE_TORRENTS as usize)
        .collect()
}

filters out the peers that have the same IP as the peer that is being announced and also other peers which do not have the same IP type (V4 or V6) as the announced peer, right?

But shouldn't two peers with the same IP but different ports be considered two different peers?

@josecelano josecelano marked this pull request as draft February 20, 2023 16:38
@josecelano
Copy link
Member Author

Hi @da2ce7 @WarmBeer, this is ready to review. I have fixed two bugs:

  • An extra byte b"e" in the compact response.
  • Dictionary keys were not sorted in the compact response.

I have not changed any other behaviour, but please read my comment above because we might need to introduce some changes. If we need to fix the current behaviour we can open a new issue.

I've just converted it into a draft again because I want to refactor some functions, especially function names to make it more explicit the way we calculate the list of peers for a given peer client.

@josecelano josecelano force-pushed the issue-187-axum-http-tracker-compact-announce-req-public-mode branch from d595151 to eed4348 Compare February 20, 2023 17:52
@josecelano josecelano marked this pull request as ready for review February 20, 2023 17:53
@josecelano
Copy link
Member Author

Hey @WarmBeer, sorry, one more question. The function:

#[must_use]
pub fn get_peers(&self, optional_excluded_address: Option<&SocketAddr>) -> Vec<&peer::Peer> {
    self.peers
        .values()
        .filter(|peer| match optional_excluded_address {
            // Don't filter on ip_version
            None => true,
            // Filter out different ip_version from remote_addr
            Some(excluded_address) => {
                // Skip ip address of client
                if peer.peer_addr.ip() == excluded_address.ip() {
                    return false;
                }

                match peer.peer_addr.ip() {
                    IpAddr::V4(_) => excluded_address.is_ipv4(),
                    IpAddr::V6(_) => excluded_address.is_ipv6(),
                }
            }
        })
        .take(MAX_SCRAPE_TORRENTS as usize)
        .collect()
}

filters out the peers that have the same IP as the peer that is being announced and also other peers which do not have the same IP type (V4 or V6) as the announced peer, right?

But shouldn't two peers with the same IP but different ports be considered two different peers?

@WarmBeer I've changed the function to:

pub fn get_peers_for_peer(&self, client: &Peer) -> Vec<&peer::Peer> {
    self.peers
        .values()
        // Take peers which are not the client peer
        .filter(|peer| peer.peer_addr != client.peer_addr)
        // Take only peers with the same IP version as the client peer
        .filter(|peer| peer.ip_version() == client.ip_version())
        // Limit the number of peers on the result
        .take(MAX_SCRAPE_TORRENTS as usize)
        .collect()
}

Now, two peers with the same IP but different ports are considered different peers, and they will be included in the announce response. Let me know if that's wrong for some reason.

The PR is ready to review again.

It will be used to build the bencoded compact annouce response in the
HTTP tracker. We are currently writting directly bytes into a byte
buffer, but Bencode specification imposes some restrictions like:

The keys in a dictionary must me alphabetically orderded. We are not
doing that in the current implementation.
- Remove extra byte "e" between "peer" and "peer6" dictionary keys.
- Alphabetically order dictionary keys.
Those test should have been enabled when the implementation was done.
…ut a different port

Other refactores were made to improve funtions names.

BREAKING CHANGE: before this a peer with the same IP as the client that
is making the announce request was removed from the announce response
regardless whether they have the same IP or not.
@josecelano
Copy link
Member Author

hi @WarmBeer, in the normal (non-compact) announce response, we are returning the hex representation of the peer ID. The torrust Axum fork does the same:

https://tracker.gbitt.info/announce?info_hash=%81%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00&peer_addr=2.137.87.41&downloaded=0&uploaded=0&peer_id=-qB00000000000000001&port=17548&left=0&event=completed&compact=0

d8:completei1e10:downloadedi2e10:incompletei0e8:intervali1800e12:min intervali1800e5:peersld2:ip11:83.57.29.577:peer id40:2d714230303030303030303030303030303030314:porti17548e

Peer IR = "-qB00000000000000001" = "2d71423030303030303030303030303030303031" = "2d 71 42 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 31"

but I'm not sure that's the correct way. As the bencode specification allows any byte string I think we should just return the raw 20-byte array.

Currently the response body is a "plain/text" but I think it should be an "application/octet-stream". [Bencoded files contained binary data](Because bencoded files contain binary data).

What do you think?

cc @Power2All

@mickvandijke
Copy link
Member

mickvandijke commented Feb 21, 2023

Hey @josecelano ,

hi @WarmBeer ,

The Axum Torrust fork adds all IPs (V4 and V6) in both "peer" and "peer6".

I think it's wrong for the "peer" key (IPV4) because IPs would have different sizes. But for the "peer6" key, we could convert IPV4 ips into IPV6. My question is whether we should do that or not.

Additionally, The Axum Torrust fork filters IP depending on the client's IP. I mean, if the remote client is using an IPV4 IP, the response will include only the "peer" key (and not the "peer6" key) with both IPV4 and IPV6 peers. I would prefer always to return both of them as we do.

I'm always talking only about the compact response.

I tried Googling whether this is an ok practice, but I could not find a concise answer. So I think it is best to not map ipv4 for now, until we can test that it is useful and does not introduce any problems.

@mickvandijke
Copy link
Member

filters out the peers that have the same IP as the peer that is being announced and also other peers which do not have the same IP type (V4 or V6) as the announced peer, right?

But shouldn't two peers with the same IP but different ports be considered two different peers?

Yes, you are right.

I was thinking that it might be even more correct to filter on peer id instead of ip + port, but I suppose that would only help out one edge case where a peer announces using different ports because it had to restart or something.

However, maybe the peer id will also renew when a peer restarts.

@mickvandijke
Copy link
Member

Hi @josecelano , @Power2All

hi @WarmBeer, in the normal (non-compact) announce response, we are returning the hex representation of the peer ID. The torrust Axum fork does the same:

https://tracker.gbitt.info/announce?info_hash=%81%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00&peer_addr=2.137.87.41&downloaded=0&uploaded=0&peer_id=-qB00000000000000001&port=17548&left=0&event=completed&compact=0

d8:completei1e10:downloadedi2e10:incompletei0e8:intervali1800e12:min intervali1800e5:peersld2:ip11:83.57.29.577:peer id40:2d714230303030303030303030303030303030314:porti17548e
Peer IR = "-qB00000000000000001" = "2d71423030303030303030303030303030303031" = "2d 71 42 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 31"

but I'm not sure that's the correct way. As the bencode specification allows any byte string I think we should just return the raw 20-byte array.

Currently the response body is a "plain/text" but I think it should be an "application/octet-stream". [Bencoded files contained binary data](Because bencoded files contain binary data).

What do you think?

cc @Power2All

I have tested a few random public trackers to see what they respond and it seems that 99% sends the peer id as raw bytes with the response Content-Type set to text/plain. So I think we should do the same.

@josecelano
Copy link
Member Author

filters out the peers that have the same IP as the peer that is being announced and also other peers which do not have the same IP type (V4 or V6) as the announced peer, right?

But shouldn't two peers with the same IP but different ports be considered two different peers?

Yes, you are right.

I was thinking that it might be even more correct to filter on peer id instead of ip + port, but I suppose that would only help out one edge case where a peer announces using different ports because it had to restart or something.

However, maybe the peer id will also renew when a peer restarts.

Yes, I was also considering that, but I guess the client only care about how many peers they can get the torrent from, regardless their ID.

@josecelano
Copy link
Member Author

Hi @josecelano , @Power2All

hi @WarmBeer, in the normal (non-compact) announce response, we are returning the hex representation of the peer ID. The torrust Axum fork does the same:

https://tracker.gbitt.info/announce?info_hash=%81%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00&peer_addr=2.137.87.41&downloaded=0&uploaded=0&peer_id=-qB00000000000000001&port=17548&left=0&event=completed&compact=0

d8:completei1e10:downloadedi2e10:incompletei0e8:intervali1800e12:min intervali1800e5:peersld2:ip11:83.57.29.577:peer id40:2d714230303030303030303030303030303030314:porti17548e
Peer IR = "-qB00000000000000001" = "2d71423030303030303030303030303030303031" = "2d 71 42 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 31"

but I'm not sure that's the correct way. As the bencode specification allows any byte string I think we should just return the raw 20-byte array.

Currently the response body is a "plain/text" but I think it should be an "application/octet-stream". [Bencoded files contained binary data](Because bencoded files contain binary data).

What do you think?

cc @Power2All

I have tested a few random public trackers to see what they respond and it seems that 99% sends the peer id as raw bytes with the response Content-Type set to text/plain. So I think we should do the same.

OK, @WarmBeer that means:

  • We can't use a Rust string (UTF8 valid).
  • We have to bencode the 20-byte array for the peer ID and not the hex string representation, which has 40 chars/bytes.

Right?

@mickvandijke
Copy link
Member

Hi @josecelano , @Power2All

hi @WarmBeer, in the normal (non-compact) announce response, we are returning the hex representation of the peer ID. The torrust Axum fork does the same:

https://tracker.gbitt.info/announce?info_hash=%81%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00&peer_addr=2.137.87.41&downloaded=0&uploaded=0&peer_id=-qB00000000000000001&port=17548&left=0&event=completed&compact=0

d8:completei1e10:downloadedi2e10:incompletei0e8:intervali1800e12:min intervali1800e5:peersld2:ip11:83.57.29.577:peer id40:2d714230303030303030303030303030303030314:porti17548e
Peer IR = "-qB00000000000000001" = "2d71423030303030303030303030303030303031" = "2d 71 42 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 31"

but I'm not sure that's the correct way. As the bencode specification allows any byte string I think we should just return the raw 20-byte array.

Currently the response body is a "plain/text" but I think it should be an "application/octet-stream". [Bencoded files contained binary data](Because bencoded files contain binary data).

What do you think?

cc @Power2All

I have tested a few random public trackers to see what they respond and it seems that 99% sends the peer id as raw bytes with the response Content-Type set to text/plain. So I think we should do the same.

OK, @WarmBeer that means:

  • We can't use a Rust string (UTF8 valid).
  • We have to bencode the 20-byte array for the peer ID and not the hex string representation, which has 40 chars/bytes.

Right?

@josecelano That's right :)

@josecelano
Copy link
Member Author

josecelano commented Feb 21, 2023

Hi @josecelano , @Power2All

hi @WarmBeer, in the normal (non-compact) announce response, we are returning the hex representation of the peer ID. The torrust Axum fork does the same:

https://tracker.gbitt.info/announce?info_hash=%81%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00&peer_addr=2.137.87.41&downloaded=0&uploaded=0&peer_id=-qB00000000000000001&port=17548&left=0&event=completed&compact=0

d8:completei1e10:downloadedi2e10:incompletei0e8:intervali1800e12:min intervali1800e5:peersld2:ip11:83.57.29.577:peer id40:2d714230303030303030303030303030303030314:porti17548e
Peer IR = "-qB00000000000000001" = "2d71423030303030303030303030303030303031" = "2d 71 42 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 31"

but I'm not sure that's the correct way. As the bencode specification allows any byte string I think we should just return the raw 20-byte array.

Currently the response body is a "plain/text" but I think it should be an "application/octet-stream". [Bencoded files contained binary data](Because bencoded files contain binary data).

What do you think?

cc @Power2All

I have tested a few random public trackers to see what they respond and it seems that 99% sends the peer id as raw bytes with the response Content-Type set to text/plain. So I think we should do the same.

OK, @WarmBeer that means:

  • We can't use a Rust string (UTF8 valid).
  • We have to bencode the 20-byte array for the peer ID and not the hex string representation, which has 40 chars/bytes.

Right?

@josecelano That's right :)

OK thank you very much @WarmBeer ! I'm going to switch this PR again to draft to change it, even if the goal for this PR is just to migrate to Axum, I think It makes sense to fix it now in the Axum implementation.

Regarding what other trackers are doing with the MIME type, maybe it's not that wrong because the MIME type plan/text does not imply an specific encoding:

https://www.rfc-editor.org/rfc/rfc5147.html#page-3

like the bencode does.

A byte string (a sequence of bytes, not necessarily characters) is encoded as :. The length is encoded in base 10, like integers, but must be non-negative (zero is allowed); the contents are just the bytes that make up the string. The string "spam" would be encoded as 4:spam. The specification does not deal with encoding of characters outside the ASCII set; to mitigate this, some BitTorrent applications explicitly communicate the encoding (most commonly UTF-8) in various non-standard ways. This is identical to how netstrings work, except that netstrings additionally append a comma suffix after the byte sequence.

@josecelano josecelano marked this pull request as draft February 21, 2023 12:44
@josecelano
Copy link
Member Author

josecelano commented Feb 21, 2023

Hi @WarmBeer, the current non-compact response only returns peers using the same IP version as the client (the peer making the request). What I understand from BEP 7 is we should return all peers regardless of what IP version they are using:

https://www.bittorrent.org/beps/bep_0007.html

"In case the tracker does not support the compact response as described in BEP-23, no change is necessary. Since the original peers response returns peer endpoints in their expanded string form, IPv6 addresses can be passed back this way."

"In case a compact response is requested, the tracker MAY add another key to the response; peers6. This key has the same layout as peers in compact mode, but instead of using 6 bytes per endpoint, 18 bytes are used. peers6 contains address-port pairs where the addresses are all IPv6."

The current behavior:

Non-compact response:

pub struct NonCompact {
    pub interval: u32,
    pub interval_min: u32,
    pub complete: u32,
    pub incomplete: u32,
    pub peers: Vec<Peer>,  // <- Only IPV4 or IPV6 depending of what the client is using
                           // <- no "peers6" key
}

Compact response:

pub struct Compact {
    pub interval: u32,
    pub interval_min: u32,
    pub complete: u32,
    pub incomplete: u32,
    pub peers: Vec<CompactPeer>,  // <- Only IPV4 peers
    pub peers6: Vec<CompactPeer>, // <- Only IPV6 peers
}

The behaviour I think we should implement:

Non-compact response:

pub struct NonCompact {
    pub interval: u32,
    pub interval_min: u32,
    pub complete: u32,
    pub incomplete: u32,
    pub peers: Vec<Peer>,  // <- IPV4 and IPV6 peers
                           // <- no "peers6" key
}

Compact response:

pub struct Compact {
    pub interval: u32,
    pub interval_min: u32,
    pub complete: u32,
    pub incomplete: u32,
    pub peers: Vec<CompactPeer>,  // <- Only IPV4 peers
    pub peers6: Vec<CompactPeer>, // <- Only IPV6 peers
}

@mickvandijke
Copy link
Member

https://www.bittorrent.org/beps/bep_0007.html

Hey @josecelano , that makes sense. I thought it would be useless to include incompatible ip's in the response.

@josecelano
Copy link
Member Author

https://www.bittorrent.org/beps/bep_0007.html

Hey @josecelano , that makes sense. I thought it would be useless to include incompatible ip's in the response.

OK, @WarmBeer then I will also fix that in this PR.

I also thought it would be useless, but I guess a peer could use different IPs to connect to other peers. And it also seems that if you bind a socket to the wildcard address (on the server) the client could make a request from an IPV4 address.

@Power2All
Copy link
Contributor

I would have say, check out Torrust-Axum project on my account.
That works as expected, for IPv4 and IPv6, both compact and non-compact format.
Tested on qBittorrent, PicoTorrent and Transmission.

@josecelano
Copy link
Member Author

Hi @WarmBeer, the "peer id" key in the non-compact response is also wrong. It should be "peer id" with a whitespace, not "peer_id".

For example:

https://tracker.gbitt.info/announce?info_hash=%81%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00&peer_addr=2.137.87.41&downloaded=0&uploaded=0&peer_id=-qB00000000000000001&port=17548&left=0&event=completed&compact=0

d8:completei1e10:downloadedi4e10:incompletei0e8:intervali1800e12:min intervali1800e5:peersld2:ip11:83.57.29.577:peer id40:2d714230303030303030303030303030303030314:porti17548eeee

See Torrust Axum implementation.

Fixed some errors in the normal (non-compact) announce response in the
HTTP tracker. Only fo rthe new Aux, implementation:

- The peer id should be a 20-byte string not the hex value representation as an string.
- Response body (bencode) should be binary (bytes).
- The "peer id" key in the peer dictionary should have a white space "peer id" intead of "peer_id" (with underscore).
@josecelano josecelano force-pushed the issue-187-axum-http-tracker-compact-announce-req-public-mode branch from ee0c2f1 to 7b9131e Compare February 21, 2023 18:41
…e response

The normal (non-compact) announce response should included all peers
except the peer making the request.

We were excluding peers that are nos using the same IP version as the
peer making the request.

Peers are included in the bencoded response in the "peers" key of the
main bencoded dictionary.
@josecelano
Copy link
Member Author

josecelano commented Feb 21, 2023

Hi @WarmBeer, I've fixed the bugs. I've also checked the response from another tracker that I've installed locally:

http://localhost:8000/announce?info_hash=%81%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00&peer_addr=2.137.87.41&downloaded=0&uploaded=0&peer_id=-qB00000000000000001&port=17548&left=0&event=completed&compact=0

d8:completei1e10:incompletei0e8:intervali600e5:peersld2:ip3:::17:peer id20:-qB000000000000000014:porti17548eeee

As you can see, the "peer id" key has a whitespace, and the peer id is only 20 bytes (-qB00000000000000001).

The response does not have any MIME-type header.

image

Finally, I've left the default Axum header for a body containing bytes. It is supposed to be application/octet-stream (see https://docs.rs/axum/latest/axum/response/index.html) but I do not see any:

image

I think the default browser behaviour is to show the body if all bytes have a char representation and to download the contents if it has binary data. But not sure about this,.

@josecelano josecelano marked this pull request as ready for review February 21, 2023 19:42
@Power2All
Copy link
Contributor

Content-Type can be plain text or octet, it doesn't matter.
All clients will either except any of them.

@josecelano josecelano merged commit b826f59 into torrust:develop Feb 22, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
Archived in project
Development

Successfully merging this pull request may close these issues.

Axum HTTP tracker: compact announce request in public mode
3 participants