'IP Address regex with netmasks

the format goal: require a.b.c.d/x where >>

  • a is 1-3 digit num btw 1-223
  • b, c, and d are 1-3 digit num btw 0-255 and *required
  • x is 1 or 2 digit num btw 8-32 and the (/x) group is optional

here's the full regex I have now:

^(((?:22[0-3]|2([0-1])?\d?|([1-9][0-9]?|1[0-9]{2}))\.)((?:25[0-5]|2[0-4]\d|[01]?(\d{0,2}))\.){2}((25[0-5]|2[0-4]\d|[01]?(\d{0,2}))(\/([89]|[12]\d|3[0-2]))?),?\s?){1,50}$

**The problem I'm running into is: if "1.1.1." is entered (aka no 'd' group), it's passing validation. I want it to fail without the 'd' group **

here is the monstrosity broken into groups and w/ added spaces for my own sanity/readability: // start string, full group

^(

// a group, 1-223 with "."

((?:22[0-3]|2([0-1])?\d?|([1-9][0-9]?|1[0-9]{2}))\.)

// b and c groups 0-255 with "."

((?:25[0-5]|2[0-4]\d|[01]?(\d{0,2}))\.){2}

// d group, ends with optional netmask instead of "." // i tried making this non-optional as a group to solve my problem.

((25[0-5]|2[0-4]\d|[01]?(\d{0,2}))

// netmask

(\/([89]|[12]\d|3[0-2]))?)

// allow comma separated, optional space between, up to 50 IPs

,?\s?){1,50}$

(I'm realizing now that this comma is optional so they could split with only a space. Maybe I can prevent that too).



Solution 1:[1]

It is easier to see what your regex does if you format the pattern and add in-pattern comments.

Here is your current regex demo:

^(
  ((?:22[0-3]|2([0-1])?\d?|([1-9][0-9]?|1[0-9]{2}))\.) # a group, 1-223 with "."
   ((?:25[0-5]|2[0-4]\d|[01]?(\d{0,2}))\.){2} # b and c groups 0-255 with "."
((25[0-5]|2[0-4]\d|[01]?(\d{0,2})) # d group, ends with optional netmask instead of "." // i tried making this non-optional as a group to solve my problem.
(\/([89]|[12]\d|3[0-2]))?) # netmask
,?\s?){1,50}$ # allow comma separated, optional space between, up to 50 IPs

However, this regex is not only imprecise, it also leads to catastrophic backtracking with some long non-matching strings.

Your netmask pattern is fine. It seems you had issues with creating a numeric range regex. You can always resort to online utilities that can generate these patterns for you, I wrote one and shared on SO here.

So, a pattern for 1-223 range is (?:[1-9]|[1-9][0-9]|1[0-9]{2}|2[01][0-9]|22[0-3]) (you can manually reduce it to (?:[1-9]\d?|1\d{2}|2[01]\d|22[0-3])) and a pattern for 0-255 range is (?:[0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5]) (reduced to (?:[1-9]?\d|1\d{2}|2[0-4]\d|25[0-5]))

You can see that using these patterns fixes the issue and makes the pattern CA-resistent:

^(?:
   (?:[1-9]\d?|1\d{2}|2[01]\d|22[0-3])\.         # a group, 1-223 with "."
   (?:(?:[1-9]?\d|1\d{2}|2[0-4]\d|25[0-5])\.){2} # b and c groups 0-255 with "."
   (?:[1-9]?\d|1\d{2}|2[0-4]\d|25[0-5])          # d group, ends with optional netmask instead of "."
   (?:\/(?:[89]|[12]\d|3[0-2]))?                 # netmask
   ,?\s?                                         # allow comma separated, optional space between
){1,50}$                                         # up to 50 IPs

See this regex demo.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Wiktor Stribiżew