91

I know regex is dangerous for validating IP addresses because of the different forms an IP address can take.

I've seen similar questions for C and C++, and those were resolved with a function that doesn't exist in C# inet_ntop()

The .NET solutions I've found only handle the standard "ddd.ddd.ddd.ddd" form. Any suggestions?

Josh
  • 2,740
  • 3
  • 27
  • 41

7 Answers7

171

You can use this to try and parse it:

 IPAddress.TryParse

Then check AddressFamily which

Returns System.Net.Sockets.AddressFamily.InterNetwork for IPv4 or System.Net.Sockets.AddressFamily.InterNetworkV6 for IPv6.

EDIT: some sample code. change as desired:

    string input = "your IP address goes here";

    IPAddress address;
    if (IPAddress.TryParse(input, out address))
    {
        switch (address.AddressFamily)
        {
            case System.Net.Sockets.AddressFamily.InterNetwork:
                // we have IPv4
                break;
            case System.Net.Sockets.AddressFamily.InterNetworkV6:
                // we have IPv6
                break;
            default:
                // umm... yeah... I'm going to need to take your red packet and...
                break;
        }
    }
Erich Mirabal
  • 9,860
  • 3
  • 34
  • 39
  • 4
    No problem. The BCL is massive, as you know. I try to read through it every once in a while just to see what is out there. – Erich Mirabal Apr 28 '09 at 18:46
  • 2
    This method returns a valid IP4 address even if the user input is "192.169.1". – Alexandru Dicu Jun 27 '12 at 00:58
  • 4
    Yes, because that's a valid ip address and is exactly what the original asker meant by matching via regex is dangerous... See this post http://stackoverflow.com/questions/12566664/ipaddress-tryparse-parses-192-168-to-192-0-0-168 for how tryparse works – claudekennilol Mar 07 '13 at 18:23
  • 1
    Just a note: When running on localhost, the address returned from `HttpContext.Current.Request.UserHostAddress` is successfully parsed as an `InterNetworkV6` address (the address in question is `::1` for myself, running IIS Express on Windows 10). Probably won't affect much since it's a localhost thing, but I wanted people to know. – Doctor Blue Nov 03 '15 at 12:04
34

Just a warning about using System.Net.IpAddress.TryParse():

If you pass it an string containing an integer (e.g. "3") the TryParse function will convert it to "0.0.0.3" and, therefore, a valid InterNetworkV4 address. So, at the very least, the reformatted "0.0.0.3" should be returned to the user application so the user knows how their input was interpreted.

Aaronster
  • 1,764
  • 2
  • 14
  • 11
21
string myIpString = "192.168.2.1";
System.Net.IPAddress ipAddress = null;

bool isValidIp = System.Net.IPAddress.TryParse(myIpString, out ipAddress);

If isValidIp is true, you can check ipAddress.AddressFamily to determine if it's IPv4 or IPv6. It's AddressFamily.InterNetwork for IPv4 and AddressFamily.InterNetworkV6 for IPv6.

Tamas Czinege
  • 118,853
  • 40
  • 150
  • 176
9

You could check out System.Uri.CheckHostName( value ) that returns Unknown , Dns, IPv4, IPv6.

if( Uri.CheckHostName( value ) != UriHostNameType.Unknown)
    //then 'value' is a valid IP address or hostname
Daniel
  • 1,225
  • 2
  • 15
  • 31
6

If you don't want to parse every integer, but only IPs, just check . for IPv4 and : for IPv6.

        if (input.Contains(".") || input.Contains(":"))
        {
            IPAddress address;
            if (IPAddress.TryParse(input, out address))
            {
                switch (address.AddressFamily)
                {
                    case AddressFamily.InterNetwork:
                        return Ip4Address;
                    case AddressFamily.InterNetworkV6:
                        return Ip6Address;
                }
            }
        }
King_SaGo
  • 251
  • 3
  • 6
1

You may use the IPAddress.GetAddressBytes().Length property

        IPAddress someIP;

        if (someIP.GetAddressBytes().Length == 4)
        {
            // IPV4
        }
        else if (someIP.GetAddressBytes().Length == 16)
        {
            // IPV6
        }
        else
        {
            // Unknown
        }

I guess should work

BlyZe
  • 43
  • 1
  • 10
Mc_Topaz
  • 31
  • 1
1

A combination of tests applied to a string or IPAddress, works for me..

        /// <summary>
    /// Test string for valid ip address format
    /// </summary>
    /// 
    /// <param name="Address">The ip address string</param>
    /// 
    /// <returns>Returns true if address is a valid format</returns>
    public static bool IsValidIP(IPAddress Ip)
    {
        byte[] addBytes = Ip.GetAddressBytes();

        switch (Ip.AddressFamily)
        {
            case AddressFamily.InterNetwork:
                if (addBytes.Length == 4)
                    return true;
                break;
            case AddressFamily.InterNetworkV6:
                if (addBytes.Length == 16)
                    return true;
                break;
            default:
                break;
        }

        return false;
    }

    /// <summary>
    /// Test string for valid ip address format
    /// </summary>
    /// 
    /// <param name="Address">The ip address string</param>
    /// 
    /// <returns>Returns true if address is a valid format</returns>
    public static bool IsValidIP(string Address)
    {
        IPAddress ip;
        if (IPAddress.TryParse(Address, out ip))
        {
            switch (ip.AddressFamily)
            {
                case System.Net.Sockets.AddressFamily.InterNetwork:
                    if (Address.Length > 6 && Address.Contains("."))
                    {
                        string[] s = Address.Split('.');
                        if (s.Length == 4 && s[0].Length > 0 &&  s[1].Length > 0 &&  s[2].Length > 0 &&  s[3].Length > 0)
                            return true;
                    }
                    break;
                case System.Net.Sockets.AddressFamily.InterNetworkV6:
                    if (Address.Contains(":") && Address.Length > 15)
                        return true;
                    break;
                default:
                    break;
            }
        }

        return false;
    }
JGU
  • 879
  • 12
  • 14