From 3df2e66e38dd15d29be60566af17a74670c6de49 Mon Sep 17 00:00:00 2001 From: FrenchGithubUser Date: Sat, 13 Sep 2025 15:24:31 +0200 Subject: [PATCH 1/3] add fake peer injection mechanism, closes #7 --- config/dev.exs | 1 + config/prod.exs | 1 + config/runtime.exs | 1 + config/test.exs | 1 + docker-compose.yml | 1 + lib/ex_tracker/swarm.ex | 13 +++++++++++++ 6 files changed, 18 insertions(+) diff --git a/config/dev.exs b/config/dev.exs index ae203b6..89408ef 100644 --- a/config/dev.exs +++ b/config/dev.exs @@ -49,6 +49,7 @@ config :extracker, reverse_proxy_address: "", http_request_timeout: 60_000, integration: "none", + fake_peers_in_responses: 0, debug: true config :logger, diff --git a/config/prod.exs b/config/prod.exs index 0f16683..8b5d3da 100644 --- a/config/prod.exs +++ b/config/prod.exs @@ -49,6 +49,7 @@ config :extracker, reverse_proxy_address: "", http_request_timeout: 60_000, integration: "none", + fake_peers_in_responses: 0, debug: false config :logger, diff --git a/config/runtime.exs b/config/runtime.exs index 2d8313c..ceed2d4 100644 --- a/config/runtime.exs +++ b/config/runtime.exs @@ -52,6 +52,7 @@ if config_env() in [:prod] do reverse_proxy_address: "", # specify the address of a reverse proxy if present (caddy, nginx, apache, etc) http_request_timeout: 60_000, # time before *outgoing* http requests timeout (mainly for integrations) integration: "none", # select which integration (if any) to be enabled (current options: "arcadia", "none") + fake_peers_in_responses: 0, # amount of fake peers to inject in the responses (prevent mass scraping of torrent peer lists), a recommended value is 3 debug: false # enable extra debug logs and checks config :logger, level: :notice # log minimum level. info and debug may get spammy diff --git a/config/test.exs b/config/test.exs index dabf65e..bd5f58c 100644 --- a/config/test.exs +++ b/config/test.exs @@ -49,6 +49,7 @@ config :extracker, reverse_proxy_address: "", http_request_timeout: 60_000, integration: "none", + fake_peers_in_responses: 0, debug: false config :logger, diff --git a/docker-compose.yml b/docker-compose.yml index f120400..e51866a 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -61,6 +61,7 @@ services: # - EXTRACKER_REVERSE_PROXY_ADDRESS= # - EXTRACKER_HTTP_REQUEST_TIMEOUT= # - EXTRACKER_INTEGRATION= +# - EXTRACKER_FAKE_PEERS_IN_RESPONSES= # - EXTRACKER_DEBUG=false # - EXTRACKER_ARCADIA_API_BIND_ADDRESS= # - EXTRACKER_ARCADIA_API_PORT= diff --git a/lib/ex_tracker/swarm.ex b/lib/ex_tracker/swarm.ex index 98dc0d7..336184c 100644 --- a/lib/ex_tracker/swarm.ex +++ b/lib/ex_tracker/swarm.ex @@ -249,6 +249,19 @@ defmodule ExTracker.Swarm do true -> Enum.map(result, fn {sid, data} -> {PeerID.from_storage(sid), data} end) end + + # inject fake peers according to the amount in the config + |> case do + list -> + fake_peers_amount = Application.get_env(:extracker, :fake_peers_in_responses, 0) + if fake_peers_amount > 0 do + fake_peers = for _ <- 1..fake_peers_amount, + do: <<0x04, :rand.uniform(255), :rand.uniform(255), :rand.uniform(255), :rand.uniform(255)>> + list ++ fake_peers + else + list + end + end rescue # the swarm table may be gone while the query reaches this point From ec08de63b0116df112e6b578ea4fb9a983787eb6 Mon Sep 17 00:00:00 2001 From: FrenchGithubUser Date: Sun, 14 Sep 2025 09:53:39 +0200 Subject: [PATCH 2/3] applied requested changes --- lib/ex_tracker/swarm.ex | 48 +++++++++++++++++++++++++++++------------ 1 file changed, 34 insertions(+), 14 deletions(-) diff --git a/lib/ex_tracker/swarm.ex b/lib/ex_tracker/swarm.ex index 336184c..186a461 100644 --- a/lib/ex_tracker/swarm.ex +++ b/lib/ex_tracker/swarm.ex @@ -245,24 +245,13 @@ defmodule ExTracker.Swarm do # convert the IDs back to the normal type case include_data do false -> - Enum.map(result, &PeerID.from_storage/1) + result + |> Enum.map(&PeerID.from_storage/1) + |> add_fake_peers(family, include_data) true -> Enum.map(result, fn {sid, data} -> {PeerID.from_storage(sid), data} end) end - # inject fake peers according to the amount in the config - |> case do - list -> - fake_peers_amount = Application.get_env(:extracker, :fake_peers_in_responses, 0) - if fake_peers_amount > 0 do - fake_peers = for _ <- 1..fake_peers_amount, - do: <<0x04, :rand.uniform(255), :rand.uniform(255), :rand.uniform(255), :rand.uniform(255)>> - list ++ fake_peers - else - list - end - end - rescue # the swarm table may be gone while the query reaches this point e in ArgumentError -> @@ -270,6 +259,37 @@ defmodule ExTracker.Swarm do [] end end + + def add_fake_peers(peers, :inet, false) do + fake_peers_amount = Application.get_env(:extracker, :fake_peers_in_responses, 0) + if fake_peers_amount > 0 do + fake_peers = for _ <- 1..fake_peers_amount do + {a, b, c, d} = {:rand.uniform(255), :rand.uniform(255), :rand.uniform(255), :rand.uniform(255)} + port = :rand.uniform(65535) + PeerID.new({a, b, c, d}, port) + end + peers ++ fake_peers + else + peers + end + end + + def add_fake_peers(peers, :inet6, false) do + fake_peers_amount = Application.get_env(:extracker, :fake_peers_in_responses, 0) + if fake_peers_amount > 0 do + fake_peers = for _ <- 1..fake_peers_amount do + ip = {:rand.uniform(65535), :rand.uniform(65535), :rand.uniform(65535), :rand.uniform(65535), + :rand.uniform(65535), :rand.uniform(65535), :rand.uniform(65535), :rand.uniform(65535)} + port = :rand.uniform(65535) + PeerID.new(ip, port) + end + peers ++ fake_peers + else + peers + end + end + + def add_fake_peers(peers, :all, _), do: peers def get_all_peers(swarm, include_data) do get_peers(swarm, :all, :all, :all, include_data) From 2a1571e05c29f9335a566fa0c714b13aa40c6345 Mon Sep 17 00:00:00 2001 From: FrenchGithubUser Date: Mon, 15 Sep 2025 10:14:03 +0200 Subject: [PATCH 3/3] use match/case instead of if/else --- lib/ex_tracker/swarm.ex | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/lib/ex_tracker/swarm.ex b/lib/ex_tracker/swarm.ex index 186a461..9a6149f 100644 --- a/lib/ex_tracker/swarm.ex +++ b/lib/ex_tracker/swarm.ex @@ -261,31 +261,29 @@ defmodule ExTracker.Swarm do end def add_fake_peers(peers, :inet, false) do - fake_peers_amount = Application.get_env(:extracker, :fake_peers_in_responses, 0) - if fake_peers_amount > 0 do - fake_peers = for _ <- 1..fake_peers_amount do + case Application.get_env(:extracker, :fake_peers_in_responses, 0) do + amount when amount > 0 -> + fake_peers = for _ <- 1..amount do {a, b, c, d} = {:rand.uniform(255), :rand.uniform(255), :rand.uniform(255), :rand.uniform(255)} port = :rand.uniform(65535) PeerID.new({a, b, c, d}, port) end peers ++ fake_peers - else - peers + _ -> peers end end def add_fake_peers(peers, :inet6, false) do - fake_peers_amount = Application.get_env(:extracker, :fake_peers_in_responses, 0) - if fake_peers_amount > 0 do - fake_peers = for _ <- 1..fake_peers_amount do + case Application.get_env(:extracker, :fake_peers_in_responses, 0) do + amount when amount > 0 -> + fake_peers = for _ <- 1..amount do ip = {:rand.uniform(65535), :rand.uniform(65535), :rand.uniform(65535), :rand.uniform(65535), :rand.uniform(65535), :rand.uniform(65535), :rand.uniform(65535), :rand.uniform(65535)} port = :rand.uniform(65535) PeerID.new(ip, port) end peers ++ fake_peers - else - peers + _ -> peers end end