IP address validation

44,545

Solution 1

It looks like the docs for IPAddress.Parse rationalize this behavior by pointing out that entering fewer parts is convenient for entering class A and B addresses. If you want to force a four-part address, you might just want to check that there are three periods in the address before feeding it to IPAddress.TryParse, I guess.

Some code for your reference:

// verify that IP consists of 4 parts
if (value.Split(new char[] { '.' }, StringSplitOptions.RemoveEmptyEntries).Length == 4)
{
    IPAddress ipAddr;
    if (IPAddress.TryParse(value, out ipAddr))
    {
        // IP is valid
    }
    else
        // invalid IP
}
else
    // invalid IP

Solution 2

The job of IPAddress.TryParse() is not to check if the string is a valid IP address, but whether or not the content of the string can be parsed (i.e.; converted) to a valid IP address.

All of the options in your test cases can in fact be parsed to represent and IP. What it comes down to is that your test cases are valid. The issue is that the data for your test cases are not valid, or you're not using the right tool(s) in your test case to get the expected result.

If you're specifically testing for a valid IPv4, with exactly 4 quads (each being an integer between 0 - 255), and want to avoid regex your could instead split then parse and validate.

public static bool IsIPv4(string value)
{
    var octets = value.Split('.');

    // if we do not have 4 octets, return false
    if (octets.Length!=4) return false;

    // for each octet
    foreach(var octet in octets) 
    {
        int q;
        // if parse fails 
        // or length of parsed int != length of octet string (i.e.; '1' vs '001')
        // or parsed int < 0
        // or parsed int > 255
        // return false
        if (!Int32.TryParse(octet, out q) 
            || !q.ToString().Length.Equals(octet.Length) 
            || q < 0 
            || q > 255) { return false; }

    }

    return true;
}

Solution 3

If you want to be very strict about your input, then you can compare the ToString() version of the parsed IPAddress, and reject the input if they are different.

The all-zero address, and other such things, would have to be handled as special cases.

Solution 4

I suggest:

    public bool IsValidIp(string addr)
    {
        IPAddress ip;
        bool valid = !string.IsNullOrEmpty(addr) && IPAddress.TryParse(addr, out ip);
        return valid;
    }

Solution 5

    public static bool IsIPv4(string ipAddress)
    {
        return Regex.IsMatch(ipAddress, @"^\d{1,3}(\.\d{1,3}){3}$") &&
            ipAddress.Split('.').SingleOrDefault(s => int.Parse(s) > 255) == null;
    }

Other answers either allow IPv6 or allow input like "1.-0.1.1".

Share:
44,545
Martin Buberl
Author by

Martin Buberl

Updated on December 30, 2020

Comments

  • Martin Buberl
    Martin Buberl over 3 years

    I'm refactoring my code and wanted to use the IPAddress.TryParse method to validate if a string is a valid IPv4 address instead of using regular expressions:

    public static bool IsIPv4(string value)
    {
        IPAddress address;
    
        if (IPAddress.TryParse(value, out address))
        {
            if (address.AddressFamily == AddressFamily.InterNetwork)
            {
                return true;
            }
        }
    
        return false;
    }
    

    My unit test is now failing because these input values return true and get parsed to the following IPAddress objects:

    value = "0.0.0.0"      ->  address = {0.0.0.0}
    value = "255.255.255"  ->  address = {255.255.0.255}
    value = "65536"        ->  address = {0.1.0.0}
    

    Does this make sense? I can see that 0.0.0.0 is technically a valid IPv4 address, even if it makes no sense for the user to enter that. What about the other two? Why are they converted in the way they are and should I treat them as valid even if it might not be transparent for the user, who maybe just forgot to enter the periods (65536 instead of 6.5.5.36).

    Any help is most appreciated.