cybersecurity · advanced · ~15 min · safe pentest lab

Validate IPv4 address against CIDR subnet allowlist

Parse network addresses and apply bitwise subnet masking to implement IP allowlisting.

Challenge

Defensive API gateways and bastion hosts restrict internal microservice access by verifying client IP addresses against CIDR subnet allowlists (e.g. 10.0.0.0/8, 192.168.1.0/24).

Your Task

Implement:

int ip_matches_cidr(const char *ip_str, const char *cidr_str);

Parse ip_str and check if it falls within cidr_str.

Rules

  1. If ip_str == NULL or cidr_str == NULL, return -1.
  2. Parse dotted-decimal IP (A.B.C.D, where each octet is 0-255).
  3. Parse CIDR (A.B.C.D/prefix, where prefix is 0-32).
  4. If either string has invalid formatting, extra characters, octets > 255, or prefix > 32, return -1.
  5. Return 1 if ip_str is within the CIDR subnet.
  6. Return 0 if ip_str is outside the CIDR subnet.

Example

ip_matches_cidr("192.168.1.50", "192.168.1.0/24"); // returns 1 (inside subnet)
ip_matches_cidr("192.168.2.1", "192.168.1.0/24");  // returns 0 (outside)
ip_matches_cidr("bad.ip", "10.0.0.0/8");          // returns -1 (malformed)

Input format

ip_str: dotted decimal IPv4; cidr_str: IPv4 CIDR string.

Output format

Returns 1 if matching, 0 if not matching, -1 on malformed input.

Constraints

Freestanding C11. IPv4 only. Subnet mask range /0 to /32.

Starter code

/* Check if ip_str falls within cidr_str (e.g. "192.168.1.5" in "192.168.1.0/24").
   Return 1 if matching, 0 if not matching, or -1 on malformed strings. */
int ip_matches_cidr(const char *ip_str, const char *cidr_str) {
    (void)ip_str; (void)cidr_str;
    return -1;
}

Common mistakes

Undefined behavior shifting 32 bits when prefix is 0 (~0U << 32); accepting invalid octets.

Edge cases to handle

prefix == 0 matches all IPs; prefix == 32 matches exact host; octet 256 is rejected; negative octets rejected.

Background lessons

Solve this exercise in the browser editor — compile and run against the test harness, no setup required.