feat(http-tracker): support I2P peers - #2059
Conversation
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## develop #2059 +/- ##
===========================================
+ Coverage 81.97% 82.18% +0.21%
===========================================
Files 349 349
Lines 24849 25076 +227
Branches 24849 25076 +227
===========================================
+ Hits 20369 20608 +239
+ Misses 4173 4160 -13
- Partials 307 308 +1 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
There was a problem hiding this comment.
Pull request overview
Adds I2P peer announcing and matchmaking to the HTTP tracker through a cross-cutting peer-address model. The draft still contains unresolved parsing, validation, deserialization, statistics, and REST contract issues.
Changes:
- Adds validated I2P destinations and network-isolated swarm coordination.
- Encodes I2P peers in compact and non-compact HTTP responses.
- Updates dependent packages, tests, documentation, and review evidence.
Reviewed changes
Copilot reviewed 48 out of 49 changed files in this pull request and generated 8 comments.
Show a summary per file
| File | Description |
|---|---|
README.md |
Advertises I2P support. |
project-words.txt |
Adds review and I2P terminology. |
packages/udp-server/src/lib.rs |
Adapts UDP fixtures to PeerAddress. |
packages/udp-server/src/handlers/announce.rs |
Excludes non-clearnet peers from UDP responses. |
packages/udp-core/src/peer_builder.rs |
Wraps UDP addresses as clearnet peers. |
packages/tracker-core/tests/common/test_env.rs |
Handles non-Copy peers. |
packages/tracker-core/tests/common/fixtures.rs |
Updates peer fixtures. |
packages/tracker-core/src/torrent/services.rs |
Clones generalized peer values. |
packages/tracker-core/src/test_helpers.rs |
Updates test peers. |
packages/tracker-core/src/peer_tests.rs |
Updates serialization fixture. |
packages/tracker-core/src/announce_handler.rs |
Preserves I2P addresses during IP assignment. |
packages/torrent-repository-benchmarking/tests/repository/mod.rs |
Updates benchmark tests for cloned peers. |
packages/torrent-repository-benchmarking/tests/entry/mod.rs |
Adapts entry tests to PeerAddress. |
packages/torrent-repository-benchmarking/src/entry/single.rs |
Supports generalized peer keys. |
packages/torrent-repository-benchmarking/src/entry/peer_list.rs |
Excludes peers by PeerAddress. |
packages/torrent-repository-benchmarking/benches/helpers/utils.rs |
Updates benchmark peer constant. |
packages/swarm-coordination-registry/src/swarm/registry.rs |
Clones non-Copy announcements. |
packages/swarm-coordination-registry/src/swarm/coordinator.rs |
Stores and isolates I2P and clearnet peers. |
packages/swarm-coordination-registry/src/statistics/event/handler.rs |
Updates event tests for cloned peers. |
packages/swarm-coordination-registry/src/lib.rs |
Updates swarm fixtures. |
packages/swarm-coordination-registry/examples/bench_peers.rs |
Updates benchmark addresses. |
packages/rest-api-runtime-adapter/src/v1/conversion.rs |
Converts peers by reference. |
packages/rest-api-runtime-adapter/src/v1/adapters/torrent.rs |
Adapts torrent conversion call. |
packages/primitives/src/peer.rs |
Introduces the cross-network PeerAddress. |
packages/primitives/src/lib.rs |
Exports I2P primitives. |
packages/primitives/src/i2p.rs |
Parses, validates, and hashes Destinations. |
packages/primitives/Cargo.toml |
Adds Base64 and SHA-256 dependencies. |
packages/http-protocol/src/v1/responses/announce/mod.rs |
Exports response address types. |
packages/http-protocol/src/v1/responses/announce/encoding.rs |
Encodes I2P response forms. |
packages/http-protocol/src/v1/responses/announce/data.rs |
Generalizes protocol peer addresses. |
packages/http-protocol/src/v1/requests/announce.rs |
Parses I2P announce addresses. |
packages/http-protocol/src/v1/query.rs |
Preserves = inside query values. |
packages/http-protocol/Cargo.toml |
Adds the primitives dependency. |
packages/http-core/src/services/scrape.rs |
Adapts scrape tests to optional IPs. |
packages/http-core/src/services/announce.rs |
Builds I2P peer announcements. |
packages/http-core/src/lib.rs |
Updates HTTP peer fixtures. |
packages/http-core/benches/helpers/util.rs |
Adapts announce benchmark helpers. |
packages/http-core/benches/helpers/sync.rs |
Updates benchmark invocation. |
packages/axum-rest-api-server/tests/server/v1/contract/context/torrent.rs |
Adapts REST contract fixture conversion. |
packages/axum-http-server/tests/server/v1/contract/for_all_config_modes/receiving_an_announce_request.rs |
Adds I2P HTTP contract coverage. |
packages/axum-http-server/src/v1/handlers/announce.rs |
Maps domain I2P peers to wire responses. |
packages/axum-http-server/src/v1/extractors/announce_request.rs |
Updates extractor expectations. |
docs/pr-reviews-manual/README.md |
Documents manual-review artifacts. |
docs/pr-reviews-manual/pr-2050/review-pass-1.md |
Records findings and required work. |
docs/pr-reviews-manual/pr-2050/manual-test-evidence.md |
Records reproducible I2P tests. |
docs/packages.md |
Documents HTTP I2P behavior. |
docs/issues/open/1987-add-config-option-to-use-ip-from-announce-query-string/ISSUE.md |
Documents I2P address precedence. |
cspell.json |
Excludes runtime storage from spelling checks. |
Cargo.lock |
Locks added dependencies. |
Suppressed comments (1)
packages/http-protocol/src/v1/requests/announce.rs:606
- The full untrusted Destination is copied into
InvalidParam, whose display text is returned in the bencoded failure response. An attacker can therefore reflect a very large query value into response/log output. Use a dedicated I2P error containing only a bounded reason and lengths, never the submitted Destination.
return Err(ParseAnnounceQueryError::InvalidParam {
param_name: IP.to_owned(),
param_value: raw_param,
location: Location::caller(),
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
| Ok(Self { | ||
| name: pair[0].to_owned(), | ||
| value: pair[1].to_owned(), | ||
| name: name.to_owned(), | ||
| value: value.to_owned(), |
| peers6.extend(u128::from(peer.ip).to_be_bytes()); | ||
| peers6.extend(peer.port.to_be_bytes()); | ||
| } | ||
| CompactPeer::I2p(hash) => peers.extend(hash), |
| match I2pDestination::from_str(&raw_param) { | ||
| Ok(destination) => return Ok(Some(AnnounceAddress::I2p(destination))), | ||
| Err(_) if has_i2p_suffix => { | ||
| return Err(ParseAnnounceQueryError::InvalidParam { |
| Err(_) => {} | ||
| } | ||
|
|
||
| Ok(None) |
| let alphabet = | ||
| Alphabet::new(I2P_BASE64_ALPHABET).expect("the I2P Base64 alphabet must contain 64 unique ASCII characters"); | ||
| let engine = GeneralPurpose::new(&alphabet, GeneralPurposeConfig::new()); | ||
| let decoded = engine.decode(encoded).map_err(|_| ParseI2pDestinationError::InvalidBase64)?; |
| let certificate_payload_length = usize::from(u16::from_be_bytes([ | ||
| decoded[I2P_CERTIFICATE_LENGTH_OFFSET], | ||
| decoded[I2P_CERTIFICATE_LENGTH_OFFSET + 1], | ||
| ])); | ||
| let expected_length = MIN_I2P_DESTINATION_BYTES + certificate_payload_length; |
| .filter(|peer| peer::ReadInfo::get_address(peer.as_ref()) != peer_addr) | ||
| .filter(|peer| peer.peer_addr.is_i2p() == peer_addr.is_i2p()); |
| pub enum PeerAddress { | ||
| Clearnet(SocketAddr), | ||
| I2p(I2pPeerAddress), |
d74b608 to
c8d906f
Compare
c8d906f to
883ab67
Compare
Supersedes
Supersedes #2050 with a rebased, GPG-signed history while preserving Frigyes Erdosi Szucs as the author of the two implementation commits.
Included
docs/pr-reviews-manual/pr-2050/.Validation
./contrib/dev-tools/git/hooks/pre-commit.sh --format=jsoncargo test --package torrust-tracker-http-protocol --liblinter allReview status
This draft is intentionally not ready to merge. The manual review identifies the following required work before merge:
%3D%3Dis accepted without changing raw binaryinfo_hashorpeer_idhandling.InvalidParam.completeandincompletedescribe peers reachable by the requester, while preserving intentional aggregate administrative statistics.ipquery value as authenticated I2P identity. Before enabling I2P announces, either enforce a trusted transport-derived Destination on a dedicated listener or reject I2P announces until that enforcement exists. The policy must also account for fabricated-Destination spam and swarm pollution with bounded input, rate limits keyed by trusted identity/source, admission/peer and response limits, expiry/cleanup, and privacy-aware metrics.A7 is a merge blocker. Details, acceptance criteria, and the trust-boundary deployment model are documented in
docs/pr-reviews-manual/pr-2050/destination-spoofing-analysis.mdandreview-pass-1.md.The contributor may use this branch as the signed/rebased base for follow-up fixes. REST API I2P representation is explicitly deferred to the REST API overhaul epic #144 and its ADR.