質問者
WFPでIPv6のフィルタをかけたい

質問
-
お世話になっております。
開発環境: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 さん、投稿ありがとうございます。MSDN フォーラムにはWindows フィルタリング プラットフォーム に関する話題を扱うフォーラムがありませんが、
私のほうで情報が集まりやすそうなWindows クライアント開発 - 全般 フォーラムに質問を移動させていただきますね。また、英語のMSDN Windows Filtering Platform (WFP) フォーラムで何か情報を得ることができるかも知れません。
ご参考までにIPv6 で検索した結果をリンクしておきます。
※フォーラムで役立つ情報がありましたら、投稿者から[回答としてマーク]をお願いします。
フォーラム オペレーター 星 睦美 - MSDN Community Support
- 編集済み 星 睦美 2013年9月11日 7:21 修正
-
# 知らずに書いてます。
深く考えずにここで使用されるデータ型FWP_BYTE_ARRAY16でググったところ、IPv6アドレスでフィルタリングするサンプルが見つかりました。IPv4についてはin_addrの値をntohl()していますが、IPv6についてはin6_addrをそのまま渡しているようです。
詳しくはサンプルを確認ください。 -
星さん、佐祐理さん、回答ありがとうございます。
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の指定の仕方が間違っているのではないかと推測しています。
引き続き、よろしくお願いいたします。