DOBON.NETプログラミング道掲示板

■34656 / 親記事)  .NetでのIPv6の比較
  
□投稿者/ あばば無人君 一般人(30回)-(2021/02/26(Fri) 14:39:28)
  • アイコン環境/言語:[Windows10(2004) 64bit、.Net 5.0、VS2019(16.8.5)Com版、C#] 
    分類:[.NET] 

    いつも本掲示板でお勉強させていただいております。

    さてタイトルの件ですが、ご存知の通りIPv6は同じアドレスでも
    以下の様に複数の表記が可能です。
    2001:db8:0:0:1:0:0:1
    2001:0db8:0:0:1:0:0:1
    2001:db8::1:0:0:1
    2001:db8::0:1:0:0:1
    2001:0db8::1:0:0:1
    2001:db8:0:0:1::1
    2001:db8:0000:0:1::1
    2001:DB8:0:0:1::1

    そこで質問なのですが.Netのライブラリで表記(文字列)の異なる
    IPv6アドレスが等しいかチェックできる様なクラスなどあったり
    しませんでしょうか?

    普通にありそうな機能かと思ってネットを検索したのですが、
    私の見た限りでは発見できませんでした。

    理想としては
    XXXClass addPattern1 = new XXXClass("2001:db8:0:0:1:0:0:1");
    XXXClass addPattern2 = new XXXClass("2001:DB8:0:0:1::1");
    if (addPattern1.Equals(addPattern2)) { Debug.WriteLine("等しい"); }
    的な感じです。

    自分でも作れはしますが、もし.Netにあったら勿体ないので
    どなたかご存知の方がいらっしゃいましたら教えて下さい。

    以上です。宜しくお願い致します。

マルチポストを報告
違反を報告
引用返信 削除キー/
■34657 / ResNo.1)  Re[1]: .NetでのIPv6の比較
□投稿者/ Hongliang 大御所(597回)-(2021/02/26(Fri) 14:51:53)
  • アイコンSystem.Net名前空間のIPAddressクラスを使えばいいのではないでしょうか。
    文字列からはIPAddress.Parse静的メソッド(またはTryParse静的メソッド)でインスタンス化できます。
違反を報告
引用返信 削除キー/
■34658 / ResNo.2)  Re[2]: .NetでのIPv6の比較
□投稿者/ あばば無人君 一般人(32回)-(2021/02/26(Fri) 15:30:29)
  • アイコンHongliangさん、ご返信ありがとうございます。

    IPAddressクラスでのIPv6アドレス比較、できちゃいました…。

    以前このクラスで以下の様にIPv4アドレスで
    文字列比較とインスタンス比較した時に

    IPAddress add1 = IPAddress.Parse("172.17.22.100");
    IPAddress add2 = IPAddress.Parse("172.017.022.100");
    if (add1.Equals(add2)) { Debug.WriteLine($"等しい"); }
    if (add1.ToString().Equals(add2.ToString())) { Debug.WriteLine($"等しい"); }

    「等しくない」判定されたのでIPv6でも同じかと思っていました。
    まさかIPv6だと「等しい」判定になるとは…。

    何故IPv4だと等しくないのかは分かりませんが、
    ひとまずタイトルの件は解決したので解決済みと
    させていただきます。

    迅速な回答、ありがとうございました。

解決み!
違反を報告
引用返信 削除キー/
■34659 / ResNo.3)  Re[3]: .NetでのIPv6の比較
□投稿者/ Hongliang 大御所(598回)-(2021/02/26(Fri) 15:40:50)
  • アイコン2021/02/26(Fri) 15:52:43 編集(投稿者)

    IPv4において、0プリフィクスがついている桁は8進数を意味します。
    Trace.WriteLine(IPAddress.Parse("172.017.022.100"));
    => 172.15.18.100

    // ただし0プリフィクスがあっても普通に10進数で扱う流儀もあるのでいかんともしがたいですが。

    ちなみに0xプリフィクスで16進数表記もできます。

解決み!
違反を報告
引用返信 削除キー/
■34660 / ResNo.4)  Re[4]: .NetでのIPv6の比較
□投稿者/ あばば無人君 一般人(33回)-(2021/02/26(Fri) 17:18:20)
  • アイコンHongliangさん、再度返信ありがとうございます。

    > IPv4において、0プリフィクスがついている桁は8進数を意味します。
    > Trace.WriteLine(IPAddress.Parse("172.017.022.100"));
    > => 172.15.18.100

    おぉ!
    int i = 0x01;
    の様な数値リテラルだけでなく、上記の様な文字列
    (しかも.で区切られた途中のオクテットに対して)でも
    プレフィックスが有効になるのですね。
    等しくない扱いになるのは当然だったと(^_^;)

    細かい部分のフォローまでありがとうございました。

解決み!
違反を報告
引用返信 削除キー/
■34661 / ResNo.5)  Re[5]: .NetでのIPv6の比較
□投稿者/ あばば無人君 一般人(34回)-(2021/02/26(Fri) 18:17:53)
  • アイコン本件、微妙なオチまでつきました。

    Hongliangさんに教えて頂いたIPAddressクラスによる比較と、
    その他ネットを見ていたらNetworkInterfaceクラスから
    アダプタに設定されているIPアドレスをIPAddressクラスで
    取得できることを知り、以下の様なパソコンのNICに引数の
    IPアドレスが存在するかチェックする関数を作成しました。


    public bool ExistIpAddress(string ipAddress)
    {
      // 戻り値(初期値:存在しない)
      bool result = false;

      try
      {
        // 引数IPアドレス文字列からIPAddressクラスを生成
        IPAddress ipObj = IPAddress.Parse(ipAddress);

        // IPアドレスリストを生成
        List<IPAddress> addList = new List<IPAddress>();

        StringBuilder logStr = new StringBuilder();
        logStr.AppendLine($"有効なネットワークインターフェースカードとそのIPアドレス");

        // 全てのネットワークインターフェース(アダプタ)の数だけ繰り返す
        foreach (NetworkInterface adapter in NetworkInterface.GetAllNetworkInterfaces())
        {
          // 有効(=稼働中)なアダプタでなければ次へ
          if (adapter.OperationalStatus != OperationalStatus.Up) { continue; }

          logStr.AppendLine($"{adapter.Name}({adapter.OperationalStatus})");

          // アダプタに設定された全IPアドレス情報を取得
          // ※1つのアダプタに複数のIPアドレスを設定できる点に注意!
          IPInterfaceProperties ifProperties = adapter.GetIPProperties();

          // 全IPアドレス情報をリストに追加
          foreach (UnicastIPAddressInformation info in ifProperties.UnicastAddresses)
          {
            // IPアドレス情報がIPv4かIPv6の場合
            if (info.Address.AddressFamily == AddressFamily.InterNetwork
            || info.Address.AddressFamily == AddressFamily.InterNetworkV6)
            {
              // そのままIPアドレスリストに追加
              addList.Add(info.Address);
              logStr.AppendLine($"  {info.Address}");
            }
          }
        }

        // 引数IPアドレスが存在するかチェック
        result = addList.Any(a => a.Equals(ipObj));

        // 存在しなかった場合だけログを出す
        if (!result)
        {
          logStr.AppendLine($"IPアドレス[{ipAddress}]は存在しません");
          Debug.WriteLine(logStr.ToString());
        }
      }
      catch (Exception ex)
      {
        Debug.WriteLine(ex.ToString());
      }

      return result;
    }


    試しにこの関数の引数にローカルPCのIPv6アドレス文字列を
    渡して動作確認してみたところ、「存在しない」となりました。

    原因を調べたところ、NetworkInterfaceクラスから取得できる
    IPAddressクラスにはIPアドレスの末尾に「スコープID」という
    NICを識別するコードが付いており、その情報まで込みで
    比較を行うために「存在しない」判定となっておりました。

    よってIPv6アドレスの場合は以下の様に再度IPAddressクラスを
    生成し直して比較することになりました。※修正箇所のみ記載


            // IPアドレス情報がIPv4の場合
            if (info.Address.AddressFamily == AddressFamily.InterNetwork)
            {
              // そのままIPアドレスリストに追加
              addList.Add(info.Address);
              logStr.AppendLine($"  {info.Address}");
            }
            // IPアドレス情報がIPv6の場合
            else if (info.Address.AddressFamily == AddressFamily.InterNetworkV6)
            {
              // NetworkInterfaceクラスから取得できるIPv6アドレスの場合は末尾にスコープIDが付加されており
              // スコープIDが付加された状態のIPAddressクラスだと↓のEquals関数による存在チェックで
              // 等しいと判定されないので、スコープIDを除去したIPアドレスで再度IPAddressクラスを生成した!
              // ※スコープIDは「%」より後ろに記述されている
              string[] addScope = info.Address.ToString().Split("%".ToCharArray());
              addList.Add(IPAddress.Parse(addScope[0]));
              logStr.AppendLine($"  {addScope[0]}");
            }

    結局泥臭いコードが入ってしまいました。
    ちゃんちゃん。

    では、長くなりましたがこの辺で。

解決み!
違反を報告
引用返信 削除キー/



スレッド内ページ移動 / << 0 >>

このスレッドに書きこむ

Mode/  Pass/


- Child Tree -