2010-11-13 168 views
17

如何迭代用戶提供的一系列IP地址?C#:枚舉範圍內的IP地址

我很靈活的格式,只要它允許指定所有範圍。也許類似nmap的風格:

'192.0.2.1'     # one IP address 

'192.0.2.0-31'    # one block with 32 IP addresses. 

'192.0.2-3.1-254'   # two blocks with 254 IP addresses. 

'0-255.0-255.0-255.0-255' # the whole IPv4 address space 

例如,如果用戶輸入192.0.2-3.1-254,我想知道如何在這個範圍內產生的所有有效IP地址的列表,以便我能遍歷它們。

回答

19

例如:

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
using System.Net; 
using System.Text.RegularExpressions; 

namespace IpRanges 
{ 
    public class IPRange 
    { 
     public IPRange(string ipRange) 
     { 
      if (ipRange == null) 
       throw new ArgumentNullException(); 

      if (!TryParseCIDRNotation(ipRange) && !TryParseSimpleRange(ipRange)) 
       throw new ArgumentException(); 
     } 

     public IEnumerable<IPAddress> GetAllIP() 
     { 
      int capacity = 1; 
      for (int i = 0; i < 4; i++) 
       capacity *= endIP[i] - beginIP[i] + 1; 

      List<IPAddress> ips = new List<IPAddress>(capacity); 
      for (int i0 = beginIP[0]; i0 <= endIP[0]; i0++) 
      { 
       for (int i1 = beginIP[1]; i1 <= endIP[1]; i1++) 
       { 
        for (int i2 = beginIP[2]; i2 <= endIP[2]; i2++) 
        { 
         for (int i3 = beginIP[3]; i3 <= endIP[3]; i3++) 
         { 
          ips.Add(new IPAddress(new byte[] { (byte)i0, (byte)i1, (byte)i2, (byte)i3 })); 
         } 
        } 
       } 
      } 

      return ips; 
     } 

     /// <summary> 
     /// Parse IP-range string in CIDR notation. 
     /// For example "12.15.0.0/16". 
     /// </summary> 
     /// <param name="ipRange"></param> 
     /// <returns></returns> 
     private bool TryParseCIDRNotation(string ipRange) 
     { 
      string[] x = ipRange.Split('/'); 

      if (x.Length != 2) 
       return false; 

      byte bits = byte.Parse(x[1]); 
      uint ip = 0; 
      String[] ipParts0 = x[0].Split('.'); 
      for (int i = 0; i < 4; i++) 
      { 
       ip = ip << 8; 
       ip += uint.Parse(ipParts0[i]); 
      } 

      byte shiftBits = (byte)(32 - bits); 
      uint ip1 = (ip >> shiftBits) << shiftBits; 

      if (ip1 != ip) // Check correct subnet address 
       return false; 

      uint ip2 = ip1 >> shiftBits; 
      for (int k = 0; k < shiftBits; k++) 
      { 
       ip2 = (ip2 << 1) + 1; 
      } 

      beginIP = new byte[4]; 
      endIP = new byte[4]; 

      for (int i = 0; i < 4; i++) 
      { 
       beginIP[i] = (byte) ((ip1 >> (3 - i) * 8) & 255); 
       endIP[i] = (byte)((ip2 >> (3 - i) * 8) & 255); 
      } 

      return true; 
     } 

     /// <summary> 
     /// Parse IP-range string "12.15-16.1-30.10-255" 
     /// </summary> 
     /// <param name="ipRange"></param> 
     /// <returns></returns> 
     private bool TryParseSimpleRange(string ipRange) 
     { 
      String[] ipParts = ipRange.Split('.'); 

      beginIP = new byte[4]; 
      endIP = new byte[4]; 
      for (int i = 0; i < 4; i++) 
      { 
       string[] rangeParts = ipParts[i].Split('-'); 

       if (rangeParts.Length < 1 || rangeParts.Length > 2) 
        return false; 

       beginIP[i] = byte.Parse(rangeParts[0]); 
       endIP[i] = (rangeParts.Length == 1) ? beginIP[i] : byte.Parse(rangeParts[1]); 
      } 

      return true; 
     } 

     private byte [] beginIP; 
     private byte [] endIP; 
    } 
} 
11

查看片段here。如果你使用這個請保持信用到位。

using System; 
using System.Collections.Generic; 
using System.ComponentModel; 
using System.Linq; 
using System.Net; 

/* ==================================================================================== 
        C# IP address range finder helper class (C) Nahum Bazes 
* Free for private & commercial use - no restriction applied, please leave credits. 
*        DO NOT REMOVE THIS COMMENT 
* ==================================================================================== */ 


namespace IPAddressTools 
{ 
    public class RangeFinder 
    { 
     public IEnumerable<string> GetIPRange(IPAddress startIP, 
      IPAddress endIP) 
     { 
      uint sIP = ipToUint(startIP.GetAddressBytes()); 
      uint eIP = ipToUint(endIP.GetAddressBytes()); 
      while (sIP <= eIP) 
      { 
       yield return new IPAddress(reverseBytesArray(sIP)).ToString(); 
       sIP++; 
      } 
     } 


     /* reverse byte order in array */ 
     protected uint reverseBytesArray(uint ip) 
     { 
      byte[] bytes = BitConverter.GetBytes(ip); 
      bytes = bytes.Reverse().ToArray(); 
      return (uint)BitConverter.ToInt32(bytes, 0); 
     } 


     /* Convert bytes array to 32 bit long value */ 
     protected uint ipToUint(byte[] ipBytes) 
     { 
      ByteConverter bConvert = new ByteConverter(); 
      uint ipUint = 0; 

      int shift = 24; // indicates number of bits left for shifting 
      foreach (byte b in ipBytes) 
      { 
       if (ipUint == 0) 
       { 
        ipUint = (uint)bConvert.ConvertTo(b, typeof(uint)) << shift; 
        shift -= 8; 
        continue; 
       } 

       if (shift >= 8) 
        ipUint += (uint)bConvert.ConvertTo(b, typeof(uint)) << shift; 
       else 
        ipUint += (uint)bConvert.ConvertTo(b, typeof(uint)); 

       shift -= 8; 
      } 

      return ipUint; 
     } 
    } 
} 
3

我想這應該這樣做。

static void TestFunc() 
{ 
    byte[,] range = ParseRange("192.0.2-5.14-28"); 

    foreach (IPAddress addr in Enumerate(range)) 
    { 
     Console.WriteLine(addr); 
    } 
} 

static byte[,] ParseRange(string str) 
{ 
    if (string.IsNullOrEmpty(str)) throw new ArgumentException("str"); 

    string[] partStr = str.Split('.'); 
    if (partStr.Length != 4) throw new FormatException(); 

    byte[,] range = new byte[4, 2]; 
    for (int i = 0; i < 4; i++) 
    { 
     string[] rangeStr = partStr[i].Split('-'); 
     if (rangeStr.Length > 2) throw new FormatException(); 

     range[i, 0] = byte.Parse(rangeStr[0]); 
     range[i, 1] = byte.Parse(rangeStr[Math.Min(rangeStr.Length - 1, 1)]); 

     // Remove this to allow ranges to wrap around. 
     // For example: 254-4 = 254, 255, 0, 1, 2, 3, 4 
     if (range[i, 1] < range[i, 0]) throw new FormatException(); 
    } 

    return range; 
} 

static IEnumerable<IPAddress> Enumerate(byte[,] range) 
{ 
    if (range.GetLength(0) != 4) throw new ArgumentException("range"); 
    if (range.GetLength(1) != 2) throw new ArgumentException("range"); 

    for (byte a = range[0, 0]; a != (byte)(range[0, 1] + 1); a++) 
    { 
     for (byte b = range[1, 0]; b != (byte)(range[1, 1] + 1); b++) 
     { 
      for (byte c = range[2, 0]; c != (byte)(range[2, 1] + 1); c++) 
      { 
       for (byte d = range[3, 0]; d != (byte)(range[3, 1] + 1); d++) 
       { 
        yield return new IPAddress(new byte[] { a, b, c, d }); 
       } 
      } 
     } 
    } 
} 
2

我遲到的遊戲,但你的問題是在重複提及,所以我剛纔添加的答案在這裏。使用IPAddressRange庫,你可以列舉你的IP地址這樣的:

var start = IPAddress.Parse("192.168.0.2"); 
var end = IPAddress.Parse("192.168.0.254"); 

var range = new IPAddressRange(start, end); 

foreach (var ip in range) 
{ 
    Console.WriteLine(ip); 
} 

該庫還支持CIDR標記和範圍的字符串