PatternRegex

Match a CIDR block

Find CIDR notation like 10.0.0.0/24 in routing tables, firewall rules and infra-as-code, with the prefix limited to the valid 0–32 range.

Last updated

Patterng
\b(?:\d{1,3}\.){3}\d{1,3}/(?:3[0-2]|[12]?\d)\b
Open in Regex Tester & Builder

Matches

  • The subnet 10.0.0.0/24 covers 256 addresses
  • 192.168.0.0/16 is a private range
  • 0.0.0.0/0 is the default route

Doesn’t match

  • 10.0.0.0/33 is not a valid prefix
  • 192.168.1.1 has no prefix at all

Why it’s written this way

The address side reuses the dotted-quad shape from the IP:port pattern above. What makes this one worth writing separately is the prefix: (?:3[0-2]|[12]?\d) is a genuine alternation rather than a lazy \d{1,2}, so it accepts exactly 0 through 32 — 3[0-2] covers 30–32, and [12]?\d covers 0–9, 10–19 and 20–29.

Without that alternation, a plain digit-count pattern would happily accept /45 or /99, which are not valid prefix lengths and would silently corrupt anything downstream that trusts the match.

Edge cases to know

  • →Octets in the address portion are still unchecked, exactly as in the plain IP pattern — 999.999.999.999/24 matches the shape.
  • →It only covers IPv4 CIDR; IPv6 prefixes (/64, /128 on a colon-separated address) need a different pattern.
  • →Zero-padded prefixes are rejected, not accepted: /05 fails, because [12]?\d matches a single digit here and the trailing \b then blocks the leftover. Normalise zero-padded source data before matching.

Part by part

(?:\d{1,3}\.){3}
The first three octets of the network address, each followed by a dot.
/
The literal slash introducing the prefix length. This is the character that distinguishes CIDR notation from a bare address.
(?:3[0-2]|[12]?\d)
The prefix length, 0 to 32, spelled as branches: 30-32 first, then any one or two digit number up to 29. Ordering matters — see the mistakes.

Common mistakes

  • (?:[12]?\d|3[0-2])

    Reversing the branch order breaks /32, because alternation takes the first branch that matches: [12]?\d consumes the 3, leaving the 2 unmatched. Longest or most specific branch must come first.

    (?:3[0-2]|[12]?\d)
  • \b(?:\d{1,3}\.){3}\d{1,3}/\d{1,2}\b

    Two unrestricted digits accept /99, which is meaningless for IPv4. The alternation exists specifically to cap the prefix at 32.

  • \b(?:\d{1,3}\.){3}\d{1,3}/(?:3[0-2]|[12]?\d)

    Dropping the trailing boundary lets /24 match the start of /245, silently truncating a malformed prefix into a valid-looking one.

Questions

Does it check the address is a valid network address for that prefix?

No. 10.0.0.5/24 matches even though the network address is 10.0.0.0 — host bits are set where the prefix says they should be zero. Some tools accept that and normalise; others reject it. The pattern has no opinion.

How many addresses does a prefix cover?

Two to the power of thirty-two minus the prefix. A /24 covers 256 addresses, a /30 covers four, and a /32 is a single host. Subtract two from the usable count on a conventional subnet for the network and broadcast addresses.

Does it handle IPv6 CIDR?

No. IPv6 prefixes run to /128 and the address itself is colon-separated hexadecimal, so both halves of the pattern would need replacing rather than extending.

Why does /0 match?

Because it is legitimate: 0.0.0.0/0 means every address, and it appears in routing tables and firewall rules as the default route. Accepting it is correct, though seeing it in a security rule is worth a second look.

Related in Patterns