スキップしてメイン コンテンツへ

 none
WFPでIPv6のフィルタをかけたい RRS feed

  • 質問

  • お世話になっております。

    開発環境:VisualStudio2012

    対応OS:Windows7 & 8

    WFPフィルタで、IPv6形式のIPアドレスを指定してフィルタをかけたいと考えております。

    IPv4に関しては実装することができました。

    [IPv4のソース例]

    FWPM_FILTER0   filter0 = {0};

    FWPM_FILTER_CONDITION0 *pFilterCondition0 = NULL;

    FwpmEngineOpen0(...);     //エンジンオープン

    pFilterCondition0 = new FWPM_FILTER_CONDITION0[3];

    // インターフェース(NIC)を指定

    pFilterCondition0[0].fieldKey = FWPM_CONDITION_INTERFACE_INDEX;
    pFilterCondition0[0].matchType = FWP_MATCH_EQUAL;
    pFilterCondition0[0].conditionValue.type = FWP_UINT32; 
    pFilterCondition0[0].conditionValue.uint32 = dwIfIndex;   //←NICのインターフェースインデックス

    // IPアドレスを指定

    ULONG ulIPv4 = inet_addr(szIpAddr);   // szIpAddrには、「192.168.1.11」などの文字列のIPアドレスが格納されている

    pFilterCondition0[1].fieldKey = FWPM_CONDITION_IP_REMOTE_ADDRESS;
    pFilterCondition0[1].matchType = FWP_MATCH_EQUAL;

    pFilterCondition0[1].conditionValue.type = FWP_UINT32;
    pFilterCondition0[1].conditionValue.uint32 = ntohl(ulIPv4);    // ホストバイトオーダーに変換して格納(※)

    //ポート番号を指定

    pFilterCondition0[2].fieldKey = FWPM_CONDITION_IP_REMOTE_PORT;
    pFilterCondition0[2].matchType = FWP_MATCH_EQUAL;
    pFilterCondition0[2].conditionValue.type = FWP_UINT16; 
    pFilterCondition0[2].conditionValue.uint16 = (UINT16)3389;    // RDPを例として許可ポートにする

    //WFPフィルタをかける

    filter0.displayData.name = L"WfpSample";
    filter0.action.type = FWP_ACTION_PERMIT;
    filter0.numFilterConditions = 3;
    filter0.filterCondition = pFilterCondition0;
    filter0.layerKey = FWPM_LAYER_ALE_AUTH_CONNECT_V4;

    dwError = FwpmFilterAdd0(hEngine,
           &filter0,
           NULL,
           pFilterId);

     

    //後処理は省略

    上記のように実装することで、IPv4はフィルタをかけ、許可することができました。

    テストの際には、まず全禁止のフィルタをかけ、最低限のポートのみ許可する(DHCP、DNS、NetBios)フィルタをかけ、

    そのうえで上記のフィルタでRDPのみ許可し、該当のIPアドレスへRDP接続できることを確認しました。

    次に、IPv6を許可するフィルタを作成したいのですが、FwpmFilterAdd0()APIは0(成功)を返すのですが、

    思った通りのフィルタがかからず、RDP接続できません。

    問題は、pFilterCondition0[1]にIPアドレスを指定している個所ではないかと推測しており、

    以下のようにしています。

    FWP_BYTE_ARRAY16  *pArray16 =new FWP_BYTE_ARRAY16;

    inet_pton(AF_INET6, szIpAddr, pArray16->byteArray16);   // szIpAddrに、IPv6形式のIPアドレスが文字列で格納されている

    pFilterCondition0[1].conditionValue.type = FWP_BYTE_ARRAY16_TYPE;
    // エンディアンを逆転し、ホストバイトオーダーにする
    reverse_endian(pArray16->byteArray16, sizeof(pArray16->byteArray16));   //配列をreverseする自作の関数
    pFilterCondition0[1].conditionValue.byteArray16 = pArray16;

    ・・・

    filter0.layerKey = FWPM_LAYER_ALE_AUTH_CONNECT_V6;

    デバッグ実行したところ、inet_pton()でバイナリ変換も正常な値であり、reverse_endian()関数終了時に、

    配列が逆転していることは確認できております。

    IPv6をホストバイトオーダーにするというのが、どういう風にすればいいのか、調べても見つかりませんでした。

    in6_addr 構造体をMSDNで調べたところ、構造体の要素としてu_short型も定義されていたため、

    pArray16->byteArray16配列をu_short単位で入れ替えてみることも試しましたが、結果は同じでした。

    まとめますと、以下のようなIPv6アドレスがあったとします。

    fe80:38d0::288a:1fc0:0001:10ee

    以下の変換は試しました。

    完全逆転パターン:

    ee,10,01,00,c0,1f,8a,28,00,00,00,00,d0,38,80,fe

    u_short単位で逆転パターン:

    80,fe,d0,38,00,00,00,00,8a,28,c0,1f,01,00,ee,10

    IPv4の場合は、4バイトのLONGだったため、単純にntohlで変換すればよかったのですが、

    IPv6は16バイトのバイナリとなるため、ホストバイトオーダーへの変換方法が間違っているような気がしています。

    なにか原因は考えられますでしょうか?



    • 編集済み ofen 2013年9月11日 7:09
    • 移動 星 睦美 2013年9月11日 7:16 Visual C++
    2013年9月11日 6:52

すべての返信

  • フォーラム オペレーターの星 睦美です。
    ofen さん、投稿ありがとうございます。

    MSDN フォーラムにはWindows フィルタリング プラットフォーム に関する話題を扱うフォーラムがありませんが、
    私のほうで情報が集まりやすそうなWindows クライアント開発 - 全般 フォーラムに質問を移動させていただきますね。

    また、英語のMSDN Windows Filtering Platform (WFP) フォーラムで何か情報を得ることができるかも知れません。
    ご参考までにIPv6 で検索した結果をリンクしておきます。

    ※フォーラムで役立つ情報がありましたら、投稿者から[回答としてマーク]をお願いします。


    フォーラム オペレーター 星 睦美 - MSDN Community Support


    • 編集済み 星 睦美 2013年9月11日 7:21 修正
    2013年9月11日 7:20
  • # 知らずに書いてます。

    深く考えずにここで使用されるデータ型FWP_BYTE_ARRAY16でググったところ、IPv6アドレスでフィルタリングするサンプルが見つかりました。IPv4についてはin_addrの値をntohl()していますが、IPv6についてはin6_addrをそのまま渡しているようです。
    詳しくはサンプルを確認ください。

    2013年9月11日 8:00
  • 星さん、佐祐理さん、回答ありがとうございます。

    To星さん

    掲示板のリンク先で調査中ですが、まだこれといった情報が見つかっていません。。。

    To佐祐理さん

    貴重な情報ありがとうございます。

    ソースを確認してみたところ、確かにIPv6はそのまま格納されていますね。

    こちらでも再度そのまま格納してみましたが、結果は同じでした。

    そこで、IPアドレスの範囲を指定して通信を通すフィルタをかけて試してみました。

    IPアドレス指定部分だけソースを記載します。

    LPCSTR     szIPv6Low = "::";       // IPアドレスの下限
    LPCSTR     szIPv6High = "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff";    // IPアドレスの上限

    FWP_RANGE0    *pRange = new FWP_RANGE0;

    // IPアドレス指定の下限を格納

    inet_pton(AF_INET6, szIPv6Low, pArray16->byteArray16);

    pRange->valueLow.type = FWP_BYTE_ARRAY16_TYPE;
    pRange->valueLow.byteArray16 = pArray16;

    // IPアドレス指定の上限を格納

    pArray16 =NULL;

    pArray16 = new  FWP_RANGE0;

    inet_pton(AF_INET6, szIPv6High, pArray16->byteArray16);

    pRange->valueHigh.type = FWP_BYTE_ARRAY16_TYPE;
    pRange->valueHigh.byteArray16 = pArray16;

    pFilterCondition0[1].fieldKey = FWPM_CONDITION_IP_REMOTE_ADDRESS;
    pFilterCondition0[1].matchType = FWP_MATCH_RANGE;
    pFilterCondition0[1].conditionValue.type = FWP_RANGE_TYPE;
    pFilterCondition0[1].conditionValue.rangeValue = pRange;

    上記のように、RANGEで範囲指定すると、RDP接続できました。

    この検証を行った際は、「全禁止フィルタ→最低限のポートだけ許可→全IPアドレス許可」の順でフィルタをかけています。

    このことから、他の箇所の記述は正しく、やはりIPv6の指定の仕方が間違っているのではないかと推測しています。

    引き続き、よろしくお願いいたします。

    2013年9月11日 9:59
  • IPv6に未対応とは考えにくいので、別の視点で。

    指定しているIPv6アドレスは正しいものですか? IPv6アドレスは複数あるので、違うアドレスで接続している可能性もありますが、そこは確認できていますか?

    2013年9月11日 13:12
  • 指定している有線のNICですが、ipconfig /allコマンドで調べたところ、IPc6アドレスは1つしか割り当てられていませんでした。

    フィルタアプリを終了させた状態(WFPフィルタがかかっていない)状態でのRDP接続は、

    IPv4,IPv6ともに成功することは確認済なのです・・・

    ソースコード中のIPv6は直書きしているのですが、RDPクライアントに入力している値をコピペし、

    一致していることは3回ほど確認しました。

    2013年9月11日 23:57