2011-08-16 49 views
6

我見過很多很棒的C# examples,它演示瞭如何將CIDR表示法(例如192.168.0.1/25)中提供的IPv4地址轉換爲它們的相關範圍(192.168.0.1 - 192.168 .0.126)。我的程序需要能夠做到這一點(計算我的本地子網內的所有地址),但我也想支持IPv6。計算一個子網內的所有地址...對於IPv6

如果我的C#程序具有我所有典型的ipconfig信息(IPv4地址,子網掩碼,IPv6地址,本地鏈接v6地址,默認網關) - 我將如何生成所有IPv6地址列表我的本地子網並將它們輸出到控制檯?

+2

你可能需要重新考慮你的功能。按照設計,幾乎你會在IPv6上看到的任何子網都是/ 64,或(2^64)-1主機大。 – Joe

+2

這是正確的,我想要所有的18,446,744,073,709,551,616個IP地址;) – DaveUK

+8

你會怎麼做?即使是每秒1000萬,你也需要58000年時間才能完成。 – Joe

回答

9

您可以使用eExNetworkLibrary中的eExNetworkLibrary.IP.IPAddressAnalysis類。

以下代碼適用於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網絡範圍可能是一項非常耗費內存/ CPU的任務。

+0

這幾乎爲我工作。需要將iIndex更改爲相等(iMaskLength - iC1 - 1)。這是編輯前的代碼,所以我不確定它爲什麼被改變。 –

1

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); 
    } 
1

我會建議使用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 

玩得開心!

+0

第一個和最後一個可用地址的輸出不正確。與IPv4不同,IPv6可以使用子網中的所有地址。一個標準的IPv6子網是/ 64(一些特殊情況下使用其他掩碼長度),可用地址從' ::'到':ffff:ffff:ffff:ffff'。子網沒有預留(' ::'),並且IPv6沒有廣播的概念,因此在':ffff:ffff:ffff:ffff'處不存在廣播地址。 –

+1

感謝您指出這一點。示例已更正。 – LukeSkywalker

0

我知道這篇文章是5年前的,但考慮到Google的功能,它可能已經在今天早上更新了。所以,我會從網絡工程的角度加入一些澄清。

這取決於什麼樣的地址。如果你指的是範圍內的每一個地址,那麼上面的討論是正確的。如果您指的是可以唯一分配給子網節點(「單播」地址)的地址,請注意,在IPv6(a)中不存在廣播,並且(b)存在大量的多播範圍。

基本上:[subnet]:ff ::保留給組播。如果你沒有使用/ 64作爲子網掩碼,你真的要小心,因爲它違背了一個基本的假設,就是很多IPv6相關的RFC。還有其他一些RFC告誡不要使用全零主機地址(但我不知道具體的要求)。

因此,對於一個/ 64子網,這意味着單播地址範圍是:: 0:0:0:1到:: feff:ffff:ffff:ffff。

看到這裏的討論: http://www.tcpipguide.com/free/t_IPv6MulticastandAnycastAddressing.htm

weylin

+0

全零位主機地址是爲子網路由器保留的,它必須在這個地址上作出響應。參見[RFC 4291第2.6.1節](https://tools.ietf.org/html/rfc4291#section-2.6.1)。儘管有這種要求,但許多網絡上的路由器都不會對此地址做出響應,但如果您嘗試在路由器正常工作的網絡上使用此地址,那麼您將會遇到糟糕的一天。 –