6

検索可能にするサブネットであるアドレスを含む IP アドレス リストを正しく保存するにはどうすればよいですか?

次の 2 つの例があります。

  1. 私の IP アドレスは 1.2.3.4 で、私の C# リストには 1.2.3.4 エントリがあるので、ここでは問題ありません。

  2. IP アドレスは 3.4.5.6 で、C# リストにはサブネット 3.4.0.0/24 があります。これが私の問題です。

2番目の例をカバーするためにIPサブネットをリストに保存する方法は?

4

5 に答える 5

4

この回答の最後に、IPV4 アドレスを表す構造の完全な実装があります。

これは本当に簡単な使用例です:-

List<IPV4Address> list = new List<IPV4Address>();
list.Add(IPV4Address.FromString("3.4.0.0", 24));
var x = IPV4Address.FromString("3.4.0.6");
foreach (var addr in list.Where(a => a.Contains(x)))
  Console.WriteLine(addr);

3.4.0.0/24 サブネットで 3.4.0.6 が検出されるため、値「3.4.0.0/255.255.255.0」がコンソールに表示されます。listさまざまなサブネットでいっぱいでx、任意のアドレスを含めることができると仮定すると、次のようになります:-

var result = list.Where(a => a.Contains(x))
    .OrderByDescending(a => a.Mask)
    .FirstOrDefault();

を含む最も具体的なサブネットを選択しますx

public struct IPV4Address
{
  private UInt32 _Value;
  private UInt32 _Mask;

  public UInt32 Value
  {
    get { return _Value; }
    private set { _Value = value; }
  }

  public UInt32 Mask
  {
    get { return _Mask; }
    private set { _Mask = value; }
  }

  public static IPV4Address FromString(string address)
  {
    return FromString(address, 32);
  }

  public static IPV4Address FromString(string address, int maskLength)
  {
    string[] parts = address.Split('.');
    UInt32 value = ((UInt32.Parse(parts[0]) << 24) +
      ((UInt32.Parse(parts[1])) << 16) +
      ((UInt32.Parse(parts[2])) << 8) +
      UInt32.Parse(parts[3]));

    return new IPV4Address(value, maskLength);
  }

  public IPV4Address(UInt32 value)
  {
    _Value = value;
    _Mask = int.MaxValue;
  }

  public IPV4Address(UInt32 value, int maskLength)
  {
    if (maskLength < 0 || maskLength > 32)
      throw new ArgumentOutOfRangeException("maskLength", "Must be 0 to 32");

    _Value = value;
    if (maskLength == 32)
      _Mask = UInt32.MaxValue;
    else
      _Mask = ~(UInt32)((1 << (32 - maskLength))-1);

    if ((_Value & _Mask) != _Value)
      throw new ArgumentException("Address value must be contained in mask");
  }

  public bool Contains(IPV4Address address)
  {
    if ((Mask & address.Mask) == Mask)
    {
      return (address.Value & Mask) == Value;
    }
    return false;
  }

  public override string ToString()
  {
    string result = String.Format("{0}.{1}.{2}.{3}", (_Value >> 24), 
      (_Value >> 16) & 0xFF, 
      (_Value >> 8) & 0xFF, 
      _Value & 0xFF);

    if (_Mask != UInt32.MaxValue)
      result += "/" + String.Format("{0}.{1}.{2}.{3}", (_Mask >> 24),
      (_Mask >> 16) & 0xFF,
      (_Mask >> 8) & 0xFF,
      _Mask & 0xFF);

    return result;
  }
}
于 2009-09-06T21:47:27.870 に答える
1

IPAddressとプレフィックス長を格納するクラスを定義します。

public class IPAddressWithPrefixLength
{
    public IPAddress IPAddress { get; }
    public int PrefixLength { get; }
}

次に、 をオーバーライドEqualsGetHashCodeて、 の最初のPrefixLengthビットのみIPAddress.GetAddressBytes()が考慮されるようにします (もちろん、IPAddress 型も考慮されます)。

次に、このクラスを使用して、サブネット プレフィックスを に格納しList<T>たり、それらを のキーとして使用したりできますDictionary<K,V>

var subnets = new List<IPAddressWithPrefixLength>
{
    new IPAddressWithPrefixLength(IPAddress.Parse("1.2.3.4"), 32),
    new IPAddressWithPrefixLength(IPAddress.Parse("3.4.0.0"), 16),
};

var ipawpl = new IPAddressWithPrefixLength(IPAddress.Parse("3.4.5.6"), 16);

Console.WriteLine(subnets.Contains(ipawpl)); // prints "True"

これは IPv6 アドレスでも機能します。

于 2009-09-06T20:46:18.063 に答える
0

これらすべての情報をまとめて格納するために、特殊な構造 (クラス) を作成したいと考えています。おそらく近い将来、ipv4 のほかに ipv6 を格納するように拡張し、さらにいくつかのデータ (メトリック、ゲートウェイなど) を格納したいと思うでしょう。

于 2009-09-06T20:32:42.790 に答える
0

ノードにブール値のラベルが付いたバイナリ ツリーを使用できます。0 が左の子で 1 が右の子である標準的な表記法を使用すると、1.2.3.4 は、ツリーにtrueat 00000001000000100000001100000100(そのアドレスのバイナリ表現) を配置することで格納され、ルートと this の間のすべてのノードで false になります。逆に、3.4.0.0/ 16 はtrueat 0000001100000100(3.4.0.0 のバイナリ表現の最初の 16 ビット) と共に格納されます。

テストするアドレスが与えられたら、そのアドレスのビットに従ってツリーを下ります。ノード a に到達するtrueと、アドレスがリストに含まれます。分岐の終わりに達した場合、アドレスはリストにありません。

たとえば、3.4.123.48 を検索する場合、true に到達する前にツリーの 16 レベルを下ります。これは、このアドレスがリストにあることを意味します。しかし、129.199.195.13 を調べると、そのアドレスの最初の 1 ビットから、それがリストの一部ではないことがわかります。

タイプを使用してこれらのアドレスを保存することがどれほど重要かはわかりませListん。したがって、これは役に立たないかもしれません。OTOH、ラベル付きの基本的なバイナリ ツリーを実装すると、.Net よりも漸近的なパフォーマンス特性が向上するはずListです。

于 2009-09-06T21:26:51.150 に答える
-1

リストに保存しないでください。代わりに、辞書などの構造に保存してください。キーは IP アドレスで、値はサブネット アドレスです。

于 2009-09-06T20:10:20.640 に答える