Validates_ip_of


#1

Hello all

After being told of a funky date validator I will ask again for another
validator :slight_smile: Does anyone know of a plugin that validates that a field is
the correct syntax for an IP Address?

Thanks

Jeff


#2

A good start is to use validates_format_of. This is probably close to
what
you need:

validates_format_of :ip_address, :with => /^(\d{1,3}.){3}\d{1,3}$/

You could do more validation to check that it’s a valid ip, it shouldn’t
be
too hard.

-Jonny.


#3

Jonathan V. wrote:

A good start is to use validates_format_of. This is probably close to
what
you need:

validates_format_of :ip_address, :with => /^(\d{1,3}.){3}\d{1,3}$/

You could do more validation to check that it’s a valid ip, it shouldn’t
be
too hard.

-Jonny.

Hmm good point. My regexp-fu is non-existant but I suppose I have to
learn it sooner or later.

Cheers

Jeff


#4

Jeff J. wrote:

Jonathan V. wrote:

A good start is to use validates_format_of. This is probably close to
what
you need:

validates_format_of :ip_address, :with => /^(\d{1,3}.){3}\d{1,3}$/

You could do more validation to check that it’s a valid ip, it shouldn’t
be
too hard.

-Jonny.

Hmm good point. My regexp-fu is non-existant but I suppose I have to
learn it sooner or later.

Cheers

Jeff

Or I could be a cheezy bugger and scrib around the net for an example:

\b(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?).(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?).(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?).(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\b


#5

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Hi Jeff,

Or I could be a cheezy bugger and scrib around the net for an example:

\b(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?).(25[0-5]|2[0-4][0-9]|[01]?
[0-9][0-9]?).(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?).(25[0-5]|2
[0-4][0-9]|[01]?[0-9][0-9]?)\b

Here’s a shorter regexp that validates an IP:

/\A(?:25[0-5]|(?:2[0-4]|1\d|[1-9])?\d)(?:.(?:25[0-5]|(?:2[0-4]|1
\d|[1-9])?\d)){3}\z/

It looks kinda crazy, but you’ll notice that its basically the same
segment twice. The
second time the segment is seen, it ensures that there is a leading
“.” in front, and
that the segment should be repeated {3} times. The (?: and ) are
basically the same
as ( and ), the difference is they just group stuff together without
capturing the
matching strings into $1, $2, $3, etc, which saves a bit of memory.

Its also slightly stricter in that it won’t allow a “segment” to
start with a leading
0 (like 10.0.01.0) as the longer one above allows, although it will
allow IPs with
zeros “on their own”, like 10.0.0.0

You may even want to see if the IP address falls into one of the
“special” address
blocks that are reserved for specific usage as defined in RFC 3330:

http://rfc.net/rfc3330.html

Depending on your app it might make sense to disallow some (all?) of
these IPs.


Thanks,

Dan


Dan K.
Autopilot Marketing Inc.

Email: removed_email_address@domain.invalid
Phone: 1 (604) 820-0212
Web: http://autopilotmarketing.com/
vCard: http://autopilotmarketing.com/~dan.kubb/vcard


-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.2.2 (Darwin)

iD8DBQFERRF44DfZD7OEWk0RAhtJAKCcTel3Nawie/atJrlQHDuGiXt3TgCglKbv
d9CPfWWC0vdwKy//kVSLpuY=
=sHod
-----END PGP SIGNATURE-----


#6

Hmm, trying to plug that into the validation produces the following
error, with a REGEXP this complex I wouldn’t know where to start, sorry
if I am missing something very basic:

vendor/rails/activesupport/lib/active_support/dependencies.rb:140:in
`load’: ./app/models/server.rb:6: premature end of regular expression:
/^(/
app/models/server.rb:6: parse error, unexpected $undefined., expecting
kEND
validates_format_of :ipaddress, :with =>
/^(/\A(?:25[0-5]|(?:2[0-4]|1\d|[1-9])?\d)(?:.(?:25[0-5])|(?:2[0-4]|1\d|[1-9])?\d)){3}\z/)$/i
^
app/models/server.rb:6: parse error, unexpected tINTEGER, expecting ‘)’
validates_format_of :ipaddress, :with =>
/^(/\A(?:25[0-5]|(?:2[0-4]|1\d|[1-9])?\d)(?:.(?:25[0-5])|(?:2[0-4]|1\d|[1-9])?\d)){3}\z/)$/i
^
app/models/server.rb:6: parse error, unexpected tINTEGER, expecting ‘)’
validates_format_of :ipaddress, :with =>
/^(/\A(?:25[0-5]|(?:2[0-4]|1\d|[1-9])?\d)(?:.(?:25[0-5])|(?:2[0-4]|1\d|[1-9])?\d)){3}\z/)$/i
^
app/models/server.rb:6: parse error, unexpected $undefined., expecting
‘)’
validates_format_of :ipaddress, :with =>
/^(/\A(?:25[0-5]|(?:2[0-4]|1\d|[1-9])?\d)(?:.(?:25[0-5])|(?:2[0-4]|1\d|[1-9])?\d)){3}\z/)$/i
^
app/models/server.rb:6: parse error, unexpected $undefined.
validates_format_of :ipaddress, :with =>
/^(/\A(?:25[0-5]|(?:2[0-4]|1\d|[1-9])?\d)(?:.(?:25[0-5])|(?:2[0-4]|1\d|[1-9])?\d)){3}\z/)$/i
^
app/models/server.rb:6: parse error, unexpected ‘)’, expecting kEND
validates_format_of :ipaddress, :with =>
/^(/\A(?:25[0-5]|(?:2[0-4]|1\d|[1-9])?\d)(?:.(?:25[0-5])|(?:2[0-4]|1\d|[1-9])?\d)){3}\z/)$/i
^
app/models/server.rb:6: parse error, unexpected $undefined., expecting
‘)’
validates_format_of :ipaddress, :with =>
/^(/\A(?:25[0-5]|(?:2[0-4]|1\d|[1-9])?\d)(?:.(?:25[0-5])|(?:2[0-4]|1\d|[1-9])?\d)){3}\z/)$/i
^
app/models/server.rb:6: parse error, unexpected $undefined.
validates_format_of :ipaddress, :with =>
/^(/\A(?:25[0-5]|(?:2[0-4]|1\d|[1-9])?\d)(?:.(?:25[0-5])|(?:2[0-4]|1\d|[1-9])?\d)){3}\z/)$/i


#7

Here’s a shorter regexp that validates an IP:

/\A(?:25[0-5]|(?:2[0-4]|1\d|[1-9])?\d)(?:.(?:25[0-5]|(?:2[0-4]|1
\d|[1-9])?\d)){3}\z/

It looks kinda crazy, but you’ll notice that its basically the same
segment twice. The
second time the segment is seen, it ensures that there is a leading
“.” in front, and
that the segment should be repeated {3} times. The (?: and ) are
basically the same
as ( and ), the difference is they just group stuff together without
capturing the
matching strings into $1, $2, $3, etc, which saves a bit of memory.

Its also slightly stricter in that it won’t allow a “segment” to
start with a leading
0 (like 10.0.01.0) as the longer one above allows, although it will
allow IPs with
zeros “on their own”, like 10.0.0.0

You may even want to see if the IP address falls into one of the
“special” address
blocks that are reserved for specific usage as defined in RFC 3330:

Thanks very much for the more efficient regexp (I am suprised that this
along with date validation isn’t included as part of Activerecord::Base
validation types).

I don’t need to validate down to the “Is it one of the special IP
blocks” as network pros (hopefully) will be entering this data and it is
only for display, not processing so I just wanted to avoid the most
basic problems (typos and the like)

Thank yo very much! (Gawd I love this forum. )

Jeff


#8

Hi Jeff,

Hmm, trying to plug that into the validation produces the following
error, with a REGEXP this complex I wouldn’t know where to start,
sorry
if I am missing something very basic:

I forgot that I’m using an alternate Regexp engine to get a slightly
richer set of matching options. I’ll rework the Regexp to work with
all versions of Ruby and get back to you.

Dan


#9

I am not sure this will work in ruby, but it works for me with
libpcre. This regex validates both IPv4 and IPv6 ipaddresses. Some
tweaking may be needed.

((([0-9a-fA-F]+:){7}[0-9a-fA-F]+)|(([0-9a-fA-F]+:)[0-9a-fA-F]+)?::(([0-9a-fA-F]+:)[0-9a-fA-F]+)?)|((25[0-5]|2[0-4][\d]|[0-1]?\d?\d)(.(25[0-5]|2[0-4]\d|[0-1]?\d?\d)){3})


#10

Hi Jeff,

validates_format_of :ipaddress, :with =>
/^(/\A(?:25[0-5]|(?:2[0-4]|1\d|[1-9])?\d)(?:.(?:25[0-5])|(?:2[0-4]|
1\d|[1-9])?\d)){3}\z/)$/i

I just tested the Regexp out on another machine with a “stock” version
of Ruby, and the Regexp did work. I think you might’ve added a few
things to the Regexp that caused it to be invalid – you’ve missed
the purpose behind “\A” and “\z”. Here’s a snippet from my favorite
regexp reference, perl’s “perlre” (yeah I know its not a ruby document,
but I think the documentation on Regexps is better in perl than ruby,
and while there are small differences, they are fairly similar in
the simple cases):

The “\A” and “\Z” are just like “^” and “$”, except that they won’t
match multiple times when the “/m” modifier is used, while “^” and
“$”
will match at every internal line boundary. To match the actual end
of the string and not ignore an optional trailing newline, use “\z”.

IMHO most of the time people use “^” and “$” when they really mean “\A”
and “\z”, but they just don’t know about them.

Can you try the following on your machine and see if it works for you:

validates_format_of :ipaddress, :with => /\A(?:25[0-5]|(?:2[0-4]|1
\d|[1-9])?\d)(?:.(?:25[0-5]|(?:2[0-4]|1\d|[1-9])?\d)){3}\z/

If this doesn’t work, what version of ruby are you using?

Dan


#11

Can you try the following on your machine and see if it works for you:

validates_format_of :ipaddress, :with => /\A(?:25[0-5]|(?:2[0-4]|1
\d|[1-9])?\d)(?:.(?:25[0-5]|(?:2[0-4]|1\d|[1-9])?\d)){3}\z/

If this doesn’t work, what version of ruby are you using?

Dan

That line of code works (I am on Rails 1.1.2). Thanks very much.