cybersecurity · intermediate · ~15 min · safe pentest lab
Classify an IPv4 address against CIDR-defined private ranges using octet arithmetic, and apply deny-by-default reasoning to block SSRF pivots to internal, loopback, and cloud-metadata hosts.
Server-Side Request Forgery (SSRF) happens when a service fetches a URL supplied by an attacker. If your fetcher does not classify the destination address, an attacker can point it at 169.254.169.254 (cloud metadata), 127.0.0.1 (loopback), or an internal 10.x/192.168.x host and pivot into infrastructure that was never meant to be reachable from the outside.
The insecure assumption is "any address the resolver returned is safe to connect to." A hardened fetcher must deny by default: only allow the request after it has confirmed the resolved address is a routable, public destination.
Implement is_private_ipv4. It receives a resolved IPv4 address as a fixed 4-byte array (ip[0] is the most significant octet). Return 1 if and only if the address falls in one of these private / non-routable ranges, otherwise return 0:
10.0.0.0/8172.16.0.0/12192.168.0.0/16127.0.0.0/8 (loopback)169.254.0.0/16 (link-local, includes cloud metadata)The caller uses your 1 result to reject the outbound request. The array is a fixed in-harness buffer; you never touch the network or filesystem.
172.15.x and 172.32.x are public — only the second octet range 16..31 is private for the /12.192.167.x is public; only 192.168.x is private.0.0.0.0 and 255.255.255.255 are not in the listed private ranges, so they return 0 here.is_private_ipv4(metadata_ip) -> 1 // metadata_ip = {169,254,169,254}
is_private_ipv4(google_dns) -> 0 // google_dns = {8,8,8,8}
A read-only array of exactly 4 unsigned char octets, most-significant octet first (ip[0].ip[1].ip[2].ip[3]).
int: 1 if the address is in a private/non-routable range listed above, 0 otherwise.
Each octet is 0..255. Read only the 4 provided bytes; never index past the fixed buffer. No network, filesystem, or dynamic allocation. Pure classification of the passed-in address.
int is_private_ipv4(const unsigned char ip[4]){
/* TODO: return 1 only for the private/non-routable ranges:
10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16,
127.0.0.0/8, 169.254.0.0/16. Deny by default.
This stub is not implemented. */
(void)ip;
return -1;
}Treating the whole 172.0.0.0/8 as private instead of only the /12 (second octet 16..31); checking 192.x instead of 192.168.x; forgetting loopback (127/8) or link-local (169.254/16); comparing signed values so a byte >127 misbehaves; reading ip[4] or beyond the 4-byte buffer.
172.15.255.255 and 172.32.0.0 are public (only 172.16-172.31 are private); 192.167.x is public while 192.168.x is private; 169.253.x is public while 169.254.x is link-local; 10.255.255.255 is still private; 0.0.0.0 and 255.255.255.255 return 0 for this list.
Solve this exercise in the browser editor — compile and run against the test harness, no setup required.