Расчет всех адресов в подсети...для IPv6
Я видел много великих Примеры C# которые демонстрируют, как конвертировать IPv4 - адреса, предоставленные в нотации CIDR (например, 192.168.0.1/25) в их соответствующие диапазоны (192.168.0.1-192.168.0.126). Моя программа должна иметь возможность сделать это (вычислить все адреса в моей локальной подсети), но я также хочу поддерживать IPv6.
Если моя программа c# имеет всю мою типичную информацию ipconfig (IPv4-адрес, маска подсети, IPv6-адрес, ссылка-локальный адрес v6, по умолчанию gateway) - как я могу создать список всех адресов IPv6 в моей локальной подсети и вывести их на консоль?
4 ответов
вы можете использовать eExNetworkLibrary.ИНТЕЛЛЕКТУАЛЬНАЯ СОБСТВЕННОСТЬ.Класс IPAddressAnalysis из eExNetworkLibrary.
следующий код работает с IPv4 и IPv6 (только что проверил).
string strIn = "2001:DB8::/120";
//Split the string in parts for address and prefix
string strAddress = strIn.Substring(0, strIn.IndexOf('/'));
string strPrefix = strIn.Substring(strIn.IndexOf('/') + 1);
int iPrefix = Int32.Parse(strPrefix);
IPAddress ipAddress = IPAddress.Parse(strAddress);
//Convert the prefix length to a valid SubnetMask
int iMaskLength = 32;
if(ipAddress.AddressFamily == System.Net.Sockets.AddressFamily.InterNetworkV6)
{
iMaskLength = 128;
}
BitArray btArray = new BitArray(iMaskLength);
for (int iC1 = 0; iC1 < iMaskLength; iC1++)
{
//Index calculation is a bit strange, since you have to make your mind about byte order.
int iIndex = (int)((iMaskLength - iC1 - 1) / 8) * 8 + (iC1 % 8);
if (iC1 < (iMaskLength - iPrefix))
{
btArray.Set(iIndex, false);
}
else
{
btArray.Set(iIndex, true);
}
}
byte[] bMaskData = new byte[iMaskLength / 8];
btArray.CopyTo(bMaskData, 0);
//Create subnetmask
Subnetmask smMask = new Subnetmask(bMaskData);
//Get the IP range
IPAddress ipaStart = IPAddressAnalysis.GetClasslessNetworkAddress(ipAddress, smMask);
IPAddress ipaEnd = IPAddressAnalysis.GetClasslessBroadcastAddress(ipAddress, smMask);
//Omit the following lines if your network range is large
IPAddress[] ipaRange = IPAddressAnalysis.GetIPRange(ipaStart, ipaEnd);
//Debug output
foreach (IPAddress ipa in ipaRange)
{
Console.WriteLine(ipa.ToString());
}
Console.ReadLine();
Я не совсем уверен, что я сделал преобразование из длины префикса в массив байтов, содержащий маску подсети, но этот код должен дать вам хорошую отправную точку.
редактировать: обновлена битовая часть кода. Может быть уродливо, но работает для этого примера. Я думаю, вы сможете найти лучшее решение, если понадобится. Эти BitArrays-боль в шее.
имейте в виду, что создание сетевого диапазона IPv6 может быть очень утомительной задачей памяти/процессора, если сеть большая.
exNetworkLibrary - отличный инструмент, но если вы не можете использовать его в своем проекте, вы можете просто увидеть эту статью:
http://www.codeproject.com/Articles/112020/IP-Address-Extension
Он описывает, как маски адресов рассчитываются для использования в IPv4.
Ваш вопрос связан с IPv6, который я вижу, и с .Net 4.5 есть IPAddress.MapToIPv6
метод.
https://msdn.microsoft.com/en-us/library/system.net.ipaddress.maptoipv6(v=vs. 110).aspx
Вы можете использовать это с проверками в статье для создания этого кода:
private static IPAddress empty = IPAddress.Parse("0.0.0.0");
private static IPAddress intranetMask1 = IPAddress.Parse("10.255.255.255");
private static IPAddress intranetMask2 = IPAddress.Parse("172.16.0.0");
private static IPAddress intranetMask3 = IPAddress.Parse("172.31.255.255");
private static IPAddress intranetMask4 = IPAddress.Parse("192.168.255.255");
/// <summary>
/// Retuns true if the ip address is one of the following
/// IANA-reserved private IPv4 network ranges (from http://en.wikipedia.org/wiki/IP_address)
/// Start End
/// 10.0.0.0 10.255.255.255
/// 172.16.0.0 172.31.255.255
/// 192.168.0.0 192.168.255.255
/// </summary>
/// <returns></returns>
public static bool IsOnIntranet(this IPAddress ipAddress)
{
if (empty.Equals(ipAddress))
{
return false;
}
bool onIntranet = IPAddress.IsLoopback(ipAddress);
if (false == onIntranet)
{
//Handle IPv6 by getting the IPv4 Mapped Address.
if (ipAddress.AddressFamily == AddressFamily.InterNetworkV6)
{
onIntranet = ipAddress.Equals(ipAddress.And(intranetMask1.MapToIPv6())); //10.255.255.255
onIntranet = onIntranet || ipAddress.Equals(ipAddress.And(intranetMask4.MapToIPv6())); ////192.168.255.255
onIntranet = onIntranet || (intranetMask2.Equals(ipAddress.And(intranetMask2.MapToIPv6()))
&& ipAddress.Equals(ipAddress.And(intranetMask3.MapToIPv6())));
}
else
{
onIntranet = ipAddress.Equals(ipAddress.And(intranetMask1)); //10.255.255.255
onIntranet = onIntranet || ipAddress.Equals(ipAddress.And(intranetMask4)); ////192.168.255.255
onIntranet = onIntranet || (intranetMask2.Equals(ipAddress.And(intranetMask2))
&& ipAddress.Equals(ipAddress.And(intranetMask3)));
}
}
return onIntranet;
}
private static void CheckIPVersion(IPAddress ipAddress, IPAddress mask, out byte[] addressBytes, out byte[] maskBytes)
{
if (mask == null)
{
throw new ArgumentException();
}
addressBytes = ipAddress.GetAddressBytes();
maskBytes = mask.GetAddressBytes();
if (addressBytes.Length != maskBytes.Length)
{
throw new ArgumentException("The address and mask don't use the same IP standard");
}
}
public static IPAddress And(this IPAddress ipAddress, IPAddress mask)
{
byte[] addressBytes;
byte[] maskBytes;
CheckIPVersion(ipAddress, mask, out addressBytes, out maskBytes);
byte[] resultBytes = new byte[addressBytes.Length];
for (int i = 0, e = addressBytes.Length; i < e; ++i)
{
resultBytes[i] = (byte)(addressBytes[i] & maskBytes[i]);
}
return new IPAddress(resultBytes);
}
Я бы рекомендовал использовать библиотеку IPNetwork https://github.com/lduchosal/ipnetwork. Начиная с версии 2, он также поддерживает IPv4 и IPv6.
протокол IPv6
IPNetwork ipnetwork = IPNetwork.Parse("2001:0db8::/64");
Console.WriteLine("Network : {0}", ipnetwork.Network);
Console.WriteLine("Netmask : {0}", ipnetwork.Netmask);
Console.WriteLine("Broadcast : {0}", ipnetwork.Broadcast);
Console.WriteLine("FirstUsable : {0}", ipnetwork.FirstUsable);
Console.WriteLine("LastUsable : {0}", ipnetwork.LastUsable);
Console.WriteLine("Usable : {0}", ipnetwork.Usable);
Console.WriteLine("Cidr : {0}", ipnetwork.Cidr);
выход
Network : 2001:db8::
Netmask : ffff:ffff:ffff:ffff::
Broadcast :
FirstUsable : 2001:db8::
LastUsable : 2001:db8::ffff:ffff:ffff:ffff
Usable : 18446744073709551616
Cidr : 64
перечисление
IPNetwork network = IPNetwork.Parse("::/124");
IPNetworkCollection ips = IPNetwork.Subnet(network, 128);
foreach (IPNetwork ip in ips) {
Console.WriteLine("{0}", ip);
}
выход
::/128
::1/128
::2/128
::3/128
::4/128
::5/128
::6/128
::7/128
::8/128
::9/128
::a/128
::b/128
::c/128
::d/128
::e/128
::f/128
удачи !
Я знаю, что этот пост 5yr старый, но, учитывая возможности Google, он также мог быть обновлен сегодня утром. Итак, я добавлю немного разъяснений с точки зрения инженерных сетей.
Это зависит от того, какие адреса. Если вы имеете в виду каждый адрес в диапазоне, то приведенное выше обсуждение является правильным. Если вы имеете в виду адреса, которые могут быть однозначно назначены узлу в подсети ("одноадресные" адреса), имейте в виду, что в IPv6 (a) нет широковещательной передачи и (b) есть существенный диапазон многоадресной рассылки.
в основном: [подсеть]: ff:: зарезервирован для многоадресной рассылки. Если вы не используете /64 для маски подсети, вы действительно хотите быть осторожными, потому что это противоречит фундаментальному предположению, что многие связанные с IPv6 RFCs. Есть и другие RFCs, которые предостерегают от использования адреса хоста всех нулей (но я не знаю конкретного требование на этот счет).
Итак, для подсети /64 это означает, что диапазон одноадресных адресов ::0: 0:0: 1 через:: feff:ffff:ffff.
см. здесь для обсуждения: http://www.tcpipguide.com/free/t_IPv6MulticastandAnycastAddressing.htm
weylin