Beefy Boxes and Bandwidth Generously Provided by pair Networks
go ahead... be a heretic
 
PerlMonks  

Valid IP?

by Monolith-0 (Beadle)
on Jul 30, 2001 at 06:14 UTC ( #100761=perlquestion: print w/ replies, xml ) Need Help??
Monolith-0 has asked for the wisdom of the Perl Monks concerning the following question:

Ok, this should be a simple question (well.. for you guys at least, but not me. Otherwise I wouldn't be asking it).

How could you check a string to see if it is a valid IP number (in format). The possible input strings could be anything from "123.456.789" to "O?vH`qEBkpA>ZMcsylriR" or even "".

Help much apreciated.

- Monolith

Comment on Valid IP?
Re: Valid IP?
by mitd (Curate) on Jul 30, 2001 at 06:40 UTC
    $ip =~ m/^([01]?\d\d?|2[0-4]\d|25[0-5])\.([01]?\d\d?|2[0-4]\d|25[0-5])\. ([01]?\d\d?|2[0-4]\d|25[0-5])\.([01]?\d\d?|2[0-4]\d|25[0-5])$/x;

    should do the trick.

    Update

    Thanks to tadman for more thorough testing. Regex updated to correct transcription error. Should work on Quad dotted IP's but sadly it still does not support base10 IP's :(.

    Update 2 tadman does it again '/x' added to prevent line-break well ... breaking it. Also could some one get me a mop I seem to be bleeding all over the floor.

    mitd-Made in the Dark
    'My favourite colour appears to be grey.'

      An impressive regex, to be sure, but a little oblique, and a little lacking in the functionality department, no offense intended. Here's a quick test that I performed with some numbers that are quite normal:
      1.2.3.4 invalid
      10.1.1.1 invalid
      192.168.1.1 invalid
      207.233.0.41 invalid
      192.168.20.41 valid
      As I mentioned before there are alternate representations of IP addresses apart from N.N.N.N, such as NN.NN, NNN.N or even NNNN. On a binary level, each byte does not have to be separated by a dot. They are for readability only. Those formats are all valid, and work, such as http://3625994804/.
      use Socket; sub IsValidIP { return ($_[0] =~ /^[\d\.]*$/) && inet_aton($_[0]); }
      Note that the inet_aton function, if given half a chance, will try and convert "www.foo.com" into a number. Since this can take some time, I have included the additional check that the input is purely numerical. When given that kind of input, inet_aton will merely compact the number into the proper internal representation, which is pack type 'N'.

      If I am being oblique then tadman is being pedantic. Yes an IP address is 32 bit unsigned int and yes thanks to the use of old BSD (inet_addr(3)) libraries you can pass a decimal equivilent for translation to uint32.

      I of course presumed our friend wished to verify a dotted quad.

      Note tadman's approach breaks in IPV6.(well maybe break is the wrong word, 'is impudent' is probably better).

      mitd-Made in the Dark
      'My favourite colour appears to be grey.'

        To preface this: in case this is mistaken for a personal attack of some sort, I'm not trying to do anything of the sort. All I want to do is promote a sensible, concise, and correct way of doing something, though this is not to say that I'm not open to new ideas.

        There are a few things that set my hair on fire, not unlike the way that people rolling their own "CGI" routines does to others, and IP address and e-mail address parsing using oversimplified and/or overcomplicated regexes is one of them. It is often because the programmer is applying a superficial understanding of some concept, which only creates problems for users later.

        An example is someone who writes a routine to verify postal codes, the sort of thing you see on Web sites all the time. For some reason, it is assumed that no sensible postal code would have letters in it:
        if ($zip !~ /^\d+(\-\d{4})?$/) { $error{zip} = "Invalid postal code."; }
        So I pound in something like 'M6K3J8' and I'm chastised, even though I can choose both country and province from a drop-down which lists them explicitly.

        To bring this back to the task at hand, inet_aton is tough to match in terms of both accuracy and ease-of-use. Stuff goes in, and if it passes the mustard, a packed number comes out. No messy stuff, and no magic.

        Further, if inet_aton can't figure out what to do with the address, it is virtually guaranteed that no other program will be able to either since the vast majority of Internet software uses that very function, or a functionally similar equivalent. On the other hand, even if something passes through a user constructed regex, there is still opportunity for that to fail later on when the inet_aton has a crack at it, which it most surely will if the address is ever used for a connection.

        That being said, if, for whatever reason, you absolutely had to use a regex, then I would submit that an improved version would be:
        sub valid_ip { my $bit = '[01]?\d\d?|2[0-4]\d|25[0-5]'; return $_[0] =~ /^($bit)(\.($bit)){3}/; }
        However, it still suffers from the same problems as the original.

        Another method, though this is really not an improvement on the regex method in terms of being easier to understand, goes about it quite literally:
        sub valid_ip { my $bits = 0; foreach (split (/\./, $_[0])) { return unless /^\d+$/ && $_ >= 0 && $_ < 256; $bits++; } return $bits == 4; }
        I'm not sure what your remark about IPv6 compatibility implies. Obviously the standard inet_aton function will not handle IPv6 addresses. Not that the regex proposed could handle them either.

        The IPv6 Address Specification is even more "open to interpretation" than IPv4, such that writing a regex for that would be considerably more difficult, and consequently, more likely to fall short of the mark.

        It would, however, be easy to upgrade the inet_aton approach to IPv6. When Perl adds native support for the IPv6 equivalent method for inet_aton, or now by using a simple module written by Tony Monroe available on CPAN:
        use Net::IPv6Addr; sub valid_ipv6 { return Net::IPv6Addr::ipv6_parse($_[0]); }

Log In?
Username:
Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://100761]
Approved by root
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others musing on the Monastery: (4)
As of 2014-07-26 15:08 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    My favorite superfluous repetitious redundant duplicative phrase is:









    Results (178 votes), past polls