Once more, I come to you for assistance! I have written a significant bit of code that converts IP Addresses from strings to minimal byte-arrays. (So that you can store them in a binary format instead of as a wasteful string.)
It currently works with IPv4 and IPv6 addresses, saving both to a 16-element byte-array. (The IPv4 addresses are padded with 0's at the beginning as per this RFC.
It currently is only capable of converting an IPv4 or IPv6 address to a byte-array, though I am going to be adding the reverse conversion soon as well.
I've omitted XML documentation from it to shorten it up to the relevant code, but you can view the code (as of this version) in it's entirety on GitHub.
As usual I appreciate all comments on anything you see here.
public class IpHelpers
{
public static string IpToHex(string ip, bool padIp)
{
if (ip.Contains('.'))
{
return Ip4ToHex(ip, padIp);
}
else
{
return Ip6ToHex(ip, padIp);
}
}
public static string Ip4ToHex(string ip, bool padIp) => Ip6ToHex(Ip4ToIp6(ip), padIp);
public static string Ip4ToIp6(string ip)
{
string[] ipv4Strings = ip.Split('.');
if (ipv4Strings.Length == 4)
{
string[] ipv4Bytes = StringArrayToHexArray(ipv4Strings);
return "::" + ipv4Bytes[0] + ipv4Bytes[1] + ":" + ipv4Bytes[2] + ipv4Bytes[3];
}
throw new ArgumentException($"The provided IP of {ip} is not a valid IP address.");
}
public static string[] StringArrayToHexArray(string[] input) => input.ToList().Select(x => Convert.ToByte(x, 10).ToString("x")).ToArray();
public static string Ip6ToHex(string ip, bool padIp)
{
string result = "0x";
ip = ExpandIp6(ip);
string[] ipv6Words = ip.Split(':');
for (int i = 0; i < ipv6Words.Length; i++)
{
result += ipv6Words[i].PadLeft(4, '0');
}
if (!padIp)
{
result = StripLeadingZeroes(result);
}
return result;
}
public static string ExpandIp6(string ip)
{
string result = "";
if (!ip.Contains("::"))
{
return ip;
}
int wordsRead = 0;
string[] ipv6Sections = ip.Split(new string[] { "::" }, StringSplitOptions.None);
string[] ipv6Section0Words = ipv6Sections[0].Split(':');
string[] ipv6Section1Words = ipv6Sections[1].Split(':');
if (ipv6Sections[0].Length > 0)
{
wordsRead += ipv6Section0Words.Length;
}
if (ipv6Sections[1].Length > 0)
{
wordsRead += ipv6Section1Words.Length;
}
for (int i = wordsRead; i <= 7; i++)
{
if (result != "")
{
result += ':';
}
result += '0';
}
if (ipv6Sections[1] != "")
{
result += ':' + ipv6Sections[1];
}
return result;
}
public static string StripLeadingZeroes(string input)
{
string result = "0x";
if (input.StartsWith("0x", StringComparison.OrdinalIgnoreCase))
{
input = input.Substring(2);
}
bool inIp = false;
for (int i = 0; i < input.Length; i+=2)
{
if (input[i] != '0' || input[i+1] != '0')
{
inIp = true;
}
if (inIp)
{
result += input[i];
result += input[i + 1];
}
}
return result;
}
public static byte[] HexToByteArray(string hex)
{
if (hex[0] == '0' && (hex[1] == 'x' || hex[1] == 'X'))
{
hex = hex.Substring(2);
}
byte[] result = new byte[hex.Length / 2];
for (int i = 0; i < result.Length; i++)
{
result[i] = Convert.ToByte(hex.Substring(i * 2, 2), 16);
}
return result;
}
}
I only have a few relevant Unit Tests, so feel free to comment on them as well.
[TestClass]
public class IpHelpersTests
{
[TestMethod]
public void IPv4ToHex_192_168_0_1()
{
var expected = "0x000000000000000000000000c0a80001";
var input = "192.168.0.1";
var actual = Framework.Utilities.IpHelpers.IpToHex(input, true);
Assert.AreEqual(expected, actual);
}
[TestMethod]
public void HexToByteArray_0x000000000000000000000000c0a80001()
{
var expected = new byte[] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0xA8, 0x00, 0x01 };
var input = "0x000000000000000000000000c0a80001";
var actual = Framework.Utilities.IpHelpers.HexToByteArray(input);
CollectionAssert.AreEqual(expected, actual);
}
[TestMethod]
public void IPv6ToHex_1()
{
var expected = "0x00000000000000000000000000000001";
var input = "0000:0000:0000:0000:0000:0000:0000:0001";
var actual = Framework.Utilities.IpHelpers.IpToHex(input, true);
Assert.AreEqual(expected, actual);
}
[TestMethod]
public void ExpandIPv6_CC1()
{
var expected = "0:0:0:0:0:0:0:1";
var input = "::1";
var actual = Framework.Utilities.IpHelpers.ExpandIp6(input);
Assert.AreEqual(expected, actual);
}
[TestMethod]
public void StripLeadingZeroes_0x00000000000000000000000000000001()
{
var expected = "0x01";
var input = "0x00000000000000000000000000000001";
var actual = Framework.Utilities.IpHelpers.StripLeadingZeroes(input);
Assert.AreEqual(expected, actual);
}
[TestMethod]
public void StripLeadingZeroes_0x000000000000000000000000c0a80001()
{
var expected = "0xc0a80001";
var input = "0x000000000000000000000000c0a80001";
var actual = Framework.Utilities.IpHelpers.StripLeadingZeroes(input);
Assert.AreEqual(expected, actual);
}
}