NAME
Net::BitTorrent::SSRF - Server-Side Request Forgery Protection
SYNOPSIS
use Net::BitTorrent::SSRF qw[is_safe_ip is_safe_host is_safe_url resolve_and_pin];
# Check a raw IP address
die 'unsafe' unless is_safe_ip('8.8.8.8');
# Check a hostname (resolves DNS and validates all IPs)
die 'unsafe' unless is_safe_host('tracker.example.com');
# Check a full URL (extracts host, resolves, validates)
die 'unsafe' unless is_safe_url('http://tracker.example.com/announce');
# Resolve a hostname to a validated safe IP + port (DNS pinning)
my ($ip, $port) = resolve_and_pin('tracker.example.com', 80)
or die 'could not resolve to a safe address';
DESCRIPTION
Net::BitTorrent::SSRF provides utility functions to detect and block outbound connections to RFC 1918 private ranges, loopback, link-local, multicast, cloud metadata endpoints, and other address spaces that should never be contacted by a BitTorrent client on behalf of untrusted input.
This module is used by the tracker, web seed, and DHT subsystems to prevent Server-Side Request Forgery (SSRF) attacks where a malicious torrent file, magnet link, tracker response, or DHT node tricks the client into probing internal networks.
FUNCTIONS
is_safe_ip( $ip )
Returns true if $ip is a public (non-private) IP address string. Returns false for loopback, RFC 1918 private, link-local, ULA, multicast, unspecified, and unparseable inputs.
if ( is_safe_ip( $ip ) ) {
# safe to connect
}
Blocked ranges:
127.0.0.0/8- IPv4 loopback10.0.0.0/8- RFC 1918 private172.16.0.0/12- RFC 1918 private192.168.0.0/16- RFC 1918 private169.254.0.0/16- Link-local (includes169.254.169.254cloud metadata)224.0.0.0/4- IPv4 multicast0.0.0.0- Unspecified::1- IPv6 loopbackfe80::/10- IPv6 link-localfc00::/7- IPv6 ULAff00::/8- IPv6 multicast::- IPv6 unspecified
is_safe_host( $host )
Returns true if $host (an IP address or hostname) resolves exclusively to public IP addresses. If $host is already a valid IP, this behaves identically to is_safe_ip. Otherwise, $host is resolved via getaddrinfo and every resulting IP is checked with is_safe_ip.
unless ( is_safe_host( $tracker_host ) ) {
warn 'refusing to connect to ' .$tracker_host;
}
is_safe_url( $url )
Extracts the hostname from $url using URI and passes it to is_safe_host. Returns true if the URL's host resolves to only public IPs.
my $http = HTTP::Tiny->new();
if ( is_safe_url( $target_url ) ) {
my $res = $http->get( $target_url );
}
resolve_and_pin( $host, $port = undef )
Resolves $host via getaddrinfo, validates every resolved IP with is_safe_ip, and returns ($safe_ip, $port) for the first safe result. Returns an empty list on failure (DNS error, no results, or all resolved IPs are unsafe).
my ($ip, $port) = resolve_and_pin('tracker.example.com', 80)
or die 'could not resolve to a safe address';
# $ip is now a validated public IP, $port is the resolved or original port
If $host is already a valid safe IP (passes is_safe_ip), it is returned immediately without DNS resolution. This function is intended for DNS pinning: resolve once, validate, and use the result for the actual connection to minimize the TOCTOU window between resolution and connection.
A full TOCTOU elimination would require overriding HTTP::Tiny's internal connection logic. The residual window when using this function is sub-millisecond and requires attacker-controlled DNS.
INTEGRATION
This module is consumed by the following classes:
Net::BitTorrent::Tracker::WebSeed - validates web seed URLs before HTTP fetch
Net::BitTorrent::Tracker::HTTP - validates tracker announce/scrape URLs
Net::BitTorrent::Tracker::UDP - validates UDP tracker host at construction
Net::BitTorrent::DHT - validates resolved DHT node addresses before sending
Net::BitTorrent::Peer - validates HP_CONNECT addresses (BEP 55)
All tracker and DHT classes accept a ssrf_bypass constructor parameter for testing. This parameter defaults to 0 (protection enabled) and should never be set to 1 in production.
SPECIFICATIONS
RFC 1918 - Address Allocation for Private Internets
RFC 3927 - Dynamic Configuration of IPv4 Link-Local Addresses
RFC 4193 - Unique Local IPv6 Unicast Addresses
BEP 55 - Holepunching via UDP (SSRF vector via
HP_CONNECT)
AUTHOR
Sanko Robinson - https://github.com/sanko
COPYRIGHT
Copyright (C) 2008-2026 by Sanko Robinson.
This library is free software; you can redistribute it and/or modify it under the terms of the Artistic License 2.0.