Ruby Forum Ruby on Rails > Validates_ip_of

Posted by Jeff Jones (rurounijones)
on 18.04.2006 13:54
Hello all

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

Thanks

Jeff
Posted by Jonathan Viney (Guest)
on 18.04.2006 15:37
(Received via mailing list)
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.
Posted by Jeff Jones (rurounijones)
on 18.04.2006 15:59
Jonathan Viney 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
Posted by Jeff Jones (rurounijones)
on 18.04.2006 16:15
Jeff Jones wrote:
> Jonathan Viney 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
Posted by Dan Kubb (Guest)
on 18.04.2006 18:19
(Received via mailing list)
-----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 Kubb
Autopilot Marketing Inc.

Email: dan.kubb@autopilotmarketing.com
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-----
Posted by Jeff Jones (rurounijones)
on 19.04.2006 11:46
> 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
Posted by Jeff Jones (rurounijones)
on 19.04.2006 11:55
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
Posted by Dan Kubb (Guest)
on 19.04.2006 15:04
(Received via mailing list)
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
Posted by Wijnand Wiersma (Guest)
on 19.04.2006 15:17
(Received via mailing list)
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})
Posted by Dan Kubb (Guest)
on 19.04.2006 15:26
(Received via mailing list)
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
Posted by Jeff Jones (rurounijones)
on 19.04.2006 16:34
> 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.