PF型ファイアウォール ーJavaライブラリ作成編ー



関連ソースコード
WinPacketFiltering\FILTER_DESCRIPTOR.java
WinPacketFiltering\INTERFACE_HANDLE.java
WinPacketFiltering\PacketFiltering.java
WinPacketFiltering\PacketFilteringException.java


Cライブラリが完成したら次はJavaでフィルタリングに必要な機能群を実装します。このJavaライブラリではJNIによるネイティブメソッドを実装す る と共に外部(他クラス)からフィルタリングを実行できるようにしてありますが、最低限の機能しかないため、アプリケーションを作成したい場合はいろいろと 機能を追加する必要があります。


フィルタ定義

 フィルタ定義 (フィルタ記述子、フィルタディスクリプタ)は Packet Filtering ReferencePF_FILTER_DESCRIPTOR をほぼ移植したものです。ただし、あまり重要でないいくつかのパラメータは削除してありま す。フィルタ定義は直列化されているのでファイルに保存できます。また、IPアドレスはInetAddress型に変更してあるのでIPv4かIPv6の 形式かどうか代入時にチェックできます(C側ではbyte配列なので値を渡す際に変換します)。
 フィルタに記述した内容に当てはまるパケットがフィルタリングの対象となります。

フィルタ定義のパラメータ
/*22*/      public int              AddrType;       // IPアドレスのバージョン
/*23*/      public InetAddress      SrcAddr;        // 送信元IPアドレス
/*24*/      public InetAddress      SrcMask;        // 送信元サブネットマスク
/*25*/      public InetAddress      DstAddr;        // 送信先IPアドレス
/*26*/      public InetAddress      DstMask;        // 送信先サブネットマスク
/*27*/      public int              SrcPort;        // 送信元ポート番号
/*28*/      public int              DstPort;        // 送信先ポート番号
/*29*/      public int              CeilingSrcPort; // 送信元ポート番号上限
/*30*/      public int              CeilingDstPort; // 送信先ポート番号上限
/*31*/      public int              Protocol;       // プロトコル (TCP・UDP・ICMP・ANY)	


インタフェースハンドル

  インタフェースハンドルにはフィルタディスクリプタを登録できます。インタフェースハンドルに登録されたどのフィルタにも当てはまらないパケットはインタ フェースハンドルの基本ルールに従って処理されます。インタフェースハンドルの基本ルールは原則許可と原則禁止が選択できます。
 基本ルールが原則許可の場合、ブラックリスト方式と呼ばれ、登録されたフィルタ定義に当てはまるパケットだけ破棄されます。基本ルールが原則禁止の場 合、ホワイトリスト方式と呼ばれ、ブラックリスト方式の逆で、登録されたフィルタに当てはまるパケットは通過します。
  インタフェースハンドルにフィルタディスクリプタを登録するのに、ArrayListによる可変長配列を利用しています。また、インタフェースハンドルの 基本ルールはブール型で定義されていますが、これはネイティブの方でも、その前提で記述されていますので、変更する場合はCソースも変更する必要がありま す。
 インタフェースハンドルは実行時にインバウンド側、アウトバウンド側の2種類セットする必要があります。もし同じルールのハンドルを両方で使いたい場合 は送信元IPアドレスと送信先IPアドレスなどの入れ替えを行わなければなりません


パケットフィルタリングを行うメソッド群


 パケットフィルタリングは基本的にこのクラスのメソッドだけを呼び出して行いますが、このクラスには最低限の機能しかありません。
 このクラスから行えるメソッドは、フィルタリングの開始・停止とフィルタリングできる4種類のフィルタの作成だけです。フィルタの保存機能やフィルタの 整合性チェック機能などは必要に応じて別に用意しなければなりません。
/* 81*/     private static final int iNULL = 0;
/* 82*/     private static final String NO_ERROR = "NO_ERROR";
/* 83*/     private static final String NATIVE   = "NATIVE : ";
81行目はC言語でのNULLを表す為の定数です。ネイティブメソッドにiNullを渡すとCではNULLとして扱われます。(C言語ではNULLは整数 0 か0Lの場合が殆んどですが(void *)0の場合も稀にあります。)
82行目はネイティブメソッド実行時に成功した場合に返される値です。失敗した場合はNO_ERROR以外の値が返されます。
83行目は例外処理で例外内容を記述する時に例外がCコード内で起こったことを表すために付加する文字列です。
/* 86*/     public static void BindInterfaceToIPAddress(InetAddress adrs,
/* 87*/             int adrsType, INTERFACE_HANDLE inbound, INTERFACE_HANDLE outbound)
/* 88*/             throws PacketFilteringException
/* 89*/     {
/* 90*/         String result;
/* 91*/         
/* 92*/         // Netive: インタフェースの生成
/* 93*/         result = PfCreateInterface(
/* 94*/                 iNULL, inbound.rule, outbound.rule, false, true);
/* 95*/         
/* 96*/         if(DEBUG) System.out.println("CreateInterface : "+result); // デバッグ
/* 97*/         
/* 98*/         failureProcessor(result);
/* 99*/         
/*100*/         if(DEBUG) // デバッグ
/*101*/         {
/*102*/             System.out.println("filter num");
/*103*/             System.out.println("in  : "+inbound.getSize());
/*104*/             System.out.println("out : "+outbound.getSize());
/*105*/         }
/*106*/         
/*107*/         // Native: インバウンドフィルタの追加
/*108*/         for(int i=0;i<inbound.getSize();i++)
/*109*/         {
/*110*/             FILTER_DESCRIPTOR filter = (FILTER_DESCRIPTOR)inbound.getFilter(i);
/*111*/             
/*112*/             result = PfAddFiltersToInterfaceIN(
/*113*/                     filter.AddrType,
/*114*/                     filter.SrcAddr.getAddress(),
/*115*/                     filter.SrcMask.getAddress(),
/*116*/                     filter.DstAddr.getAddress(),
/*117*/                     filter.DstMask.getAddress(),
/*118*/                     filter.SrcPort,
/*119*/                     filter.DstPort,
/*120*/                     filter.CeilingSrcPort,
/*121*/                     filter.CeilingDstPort,
/*122*/                     filter.Protocol
/*123*/             );
/*124*/             
/*125*/             failureProcessor(result);
/*126*/         }
/*127*/         
/*128*/         if(DEBUG) // デバッグ
/*129*/         {
/*130*/             System.out.println("AddFiltersToInterfaceIN : "+result);
/*131*/         }
/*132*/         
/*133*/         // Native: アウトバウンドフィルタの追加
/*134*/         for(int i=0;i<outbound.getSize();i++)
/*135*/         {
/*136*/             FILTER_DESCRIPTOR filter = (FILTER_DESCRIPTOR)outbound.getFilter(i);
/*137*/             
/*138*/             result = PfAddFiltersToInterfaceOUT(
/*139*/                     filter.AddrType,
/*140*/                     filter.SrcAddr.getAddress(),
/*141*/                     filter.SrcMask.getAddress(),
/*142*/                     filter.DstAddr.getAddress(),
/*143*/                     filter.DstMask.getAddress(),
/*144*/                     filter.SrcPort,
/*145*/                     filter.DstPort,
/*146*/                     filter.CeilingSrcPort,
/*147*/                     filter.CeilingDstPort,
/*148*/                     filter.Protocol
/*149*/             );
/*150*/             
/*151*/             failureProcessor(result);
/*152*/         }
/*153*/         
/*154*/         if(DEBUG) System.out.println("AddFiltersToInterfaceOUT : "+result); // デバッグ
/*155*/         
/*156*/         // IPアドレスにバインド
/*157*/         result = PfBindInterfaceToIPAddress(adrsType, adrs.getAddress());
/*158*/         failureProcessor(result);
/*159*/         
/*160*/         if(DEBUG) System.out.println("BindInterfaceToIPAddress : "+result); // デバッグ
/*161*/     }
フィルタリング実行メソッドです。フィルタリング実行は次の流れで行われます。
(ネイティブ側で行われます)
1, インタフェースハンドルの作成
2, インバウンドハンドルにフィルタを登録
3, アウトバウンドハンドルにフィルタを登録
4, IPアドレスにハンドルをバインド

93、94行目は上の1を行うネイティブメソッドを呼び出しています。いくつかの引数は固定されています。
98行目はネイティブメソッドの成否を調べ、失敗した場合は専用の例外PacketFilteringExceptionをスローします。
108〜126行目は上の2を行っています。フィルタは先頭から1つずつ順次追加されていきますが、途中で例外が発生すると、その時点で中断します。
134〜152行目は上の3を行っています。
157行目は上の4を行っています。この時点でフィルタリングが開始されます。
フィルタリング実行中は停止しない限りフィルタリングが出来ないようにしてあります。つまりC側では最大2つのインタフェースハンドルしか同時に作成でき ません。もし実行中に再度実行した場合は例外が発生します。

/*164*/     public static void UnBindInterface() throws PacketFilteringException
/*165*/     {
/*166*/         String result;
/*167*/         
/*168*/         result = PfUnBindInterface();
/*169*/         failureProcessor(result);
/*170*/         
/*171*/         result = PfDeleteInterface();
/*172*/         failureProcessor(result);
/*173*/     }
フィルタリング停止メソッドです。フィルタリング停止は次の流れで行われま す。
(ネイティブ側で行われます)
1, バインドされたハンドルを解除
2, 作成したハンドルを削除

168行目は上の1を行っています。
171行目は上の2を行っています。

/*176*/     private static void failureProcessor(String result)
/*177*/         throws PacketFilteringException
/*178*/     {
/*179*/         if(!result.equals(NO_ERROR))
/*180*/         {
/*181*/             PfDeleteInterface();
/*182*/             throw new PacketFilteringException(NATIVE+result);
/*183*/         }
/*184*/     }
フィルタリング実行・停止で使うネイティブメソッドの返り値判定用メソッドです。返り値が NO_ERRORでない場合は、ハンドルを(あれば)削除し、例外を返します。

/*187*/     // (Native) フィルタリングインタフェースの作成
/*188*/     private static native String PfCreateInterface(
/*189*/             int         dwName,
/*190*/             // PFFORWARD_ACTION
/*191*/             boolean inAction,
/*192*/             // PFFORWARD_ACTION
/*193*/             boolean outAction,
/*194*/             boolean bUseLog,
/*195*/             boolean bMustBeUnique
/*196*/     );
/*197*/     
/*198*/     // (Native) フィルタをインバウンド・インタフェースに加える
/*199*/     private static native String PfAddFiltersToInterfaceIN( 
/*200*/             int     addrType,
/*201*/             byte[]  SrcAddr,
/*202*/             byte[]  SrcMask,
/*203*/             byte[]  DstAddr,
/*204*/             byte[]  DstMask,
/*205*/             int     srcPort,
/*206*/             int     dstPort,
/*207*/             int     ceilingSrcPort,
/*208*/             int     ceilingDstPort,
/*209*/             int     protocol
/*210*/     );
/*211*/     
/*212*/     // (Native) フィルタをアウトバウンド・インタフェースに加える
/*213*/     private static native String PfAddFiltersToInterfaceOUT(    
/*214*/             int     addrType,
/*215*/             byte[]  SrcAddr,
/*216*/             byte[]  SrcMask,
/*217*/             byte[]  DstAddr,
/*218*/             byte[]  DstMask,
/*219*/             int     srcPort,
/*220*/             int     dstPort,
/*221*/             int     ceilingSrcPort,
/*222*/             int     ceilingDstPort,
/*223*/             int     protocol
/*224*/     );
/*225*/     
/*226*/     // (Native) フィルタリングインタフェースをIPアドレスにバインド
/*227*/     private static native String PfBindInterfaceToIPAddress(
/*228*/             int     pfatType,
/*229*/             byte[]  IPAddress
/*230*/     );
/*231*/     
/*232*/     // (Native) フィルタリングインタフェースのアンバインド
/*233*/     private static native String PfUnBindInterface();
/*234*/     
/*235*/     // (Native) フィルタリングインタフェースの除去
/*236*/     private static native String PfDeleteInterface();
これらのメソッドはネイティブメソッドで、それぞれPacket Filtering Reference の同名メソッドを呼び出します。外部からは呼び出さず、フィルタリングの実行、停止に分けて、まとめて別メソッドから一括して呼び出さ れます。

固定パラメータ群
/*248*/     // AddrType
/*249*/     public static final int IPv4_FLAG       = 4;
/*250*/     public static final int IPv6_FLAG       = 6;
/*251*/     // SrcMask, DstMask
/*252*/     private static final byte[] ALL_FFv4
/*253*/                     = {(byte)255, (byte)255, (byte)255, (byte)255};
/*254*/     public static InetAddress NO_MASKv4;// = InetAddress.getByAddress(ALL_FFv4);
/*255*/     private static final byte[] ALL_00v4
/*256*/                     = {(byte)0, (byte)0, (byte)0, (byte)0};
/*257*/     public static InetAddress ALL_IPv4;// = InetAddress.getByAddress(ALL_00v4);
/*258*/     private static final byte[] ALL_FFv6
/*259*/         = { (byte)255, (byte)255, (byte)255, (byte)255,
/*260*/             (byte)255, (byte)255, (byte)255, (byte)255,
/*261*/             (byte)255, (byte)255, (byte)255, (byte)255,
/*262*/             (byte)255, (byte)255, (byte)255, (byte)255};
/*263*/     public static InetAddress NO_MASKv6;// = InetAddress.getByAddress(ALL_FFv6);
/*264*/     private static final byte[] ALL_00v6
/*265*/         = { (byte)0, (byte)0, (byte)0, (byte)0, (byte)0, (byte)0, (byte)0, (byte)0,
/*266*/             (byte)0, (byte)0, (byte)0, (byte)0, (byte)0, (byte)0, (byte)0, (byte)0};
/*267*/     public static InetAddress ALL_IPv6;// = InetAddress.getByAddress(ALL_00v6);
/*268*/     // SrcPort, DstPort
/*269*/     public static final int NO_SET   = -1;
/*270*/     public static final int ANY_PORT = 0;
/*271*/     // CeilingSrcPort, CeilingDstPort
/*272*/     public static final int ONLY_1_PORT = -1;
/*273*/     // Protocol
/*274*/     public static final int ANY_PROTOCOL = 1;
/*275*/     public static final int ICMP         = 2;
/*276*/     public static final int TCP          = 3;
/*277*/     public static final int UDP          = 4;
/*278*/     
/*279*/     public static InetAddress   LOCAL_HOST;// = InetAddress.getLocalHost();
これらのフィールドはフィルタ定義(FILTER_DESCRIPTOR型)のパラメータの特別な値です。
249、250行目はAddrTypeに代入できます。 それぞれIPアドレスのバージョンを指定します。
252〜267
行目はIPアドレスパラメータ に代入できます。NO_MASKv4はIPv4のサブネットマスク無し(255.255.255.255)、ALL_IPv4は IPv4の全てのアドレス(0.0.0.0)を表します。 ALL_IPv4はIPアドレスとサブネットマスクの両方にセットします。 〜v6はIPv6版 です。
269、270行目はSrcPort、DstPortに代入できます。NO_SETは初期設定に用いられ ますので、TCPかUDPのフィルタでは他の値を代入する必要があります。ICPMフィルタではNO_SET のままにしておかなければなりません。ANY_PORTは全てのポートを意味します。(使うことは無いと思いますが)0番ポートを指定することは出来ませ ん。
272行目はCeilingSrcPort、CeilingDstPortに代入できます。 ONLY_1_PORTを設定するとSrcPort、DstPortに指定し たポート番号1つだけをフィルタに設定します。
274〜277行目は Protocolに代入できます。これらの値によってフィルタの種類を設定できます。
279行目はローカルホストのIPアドレスを自動取得します。

/*282*/     // フィルタディスクリプタの基本設定
/*283*/     private static FILTER_DESCRIPTOR setBasicDescriptor(FILTER_DESCRIPTOR descriptor)
/*284*/     {
/*285*/         descriptor.AddrType         = IPv4_FLAG;
/*286*/         descriptor.SrcAddr          = null;
/*287*/         descriptor.SrcMask          = NO_MASKv4;
/*288*/         descriptor.DstAddr          = null;
/*289*/         descriptor.DstMask          = NO_MASKv4;
/*290*/         descriptor.SrcPort          = NO_SET;
/*291*/         descriptor.DstPort          = NO_SET;
/*292*/         descriptor.CeilingSrcPort   = ONLY_1_PORT;
/*293*/         descriptor.CeilingDstPort   = ONLY_1_PORT;  
/*294*/         descriptor.Protocol         = ANY_PROTOCOL;
/*295*/         
/*296*/         return descriptor;
/*297*/     }
/*298*/     
/*299*/     // ICMPフィルタを新規作成する
/*300*/     public static FILTER_DESCRIPTOR getICMPfilter()
/*301*/     {
/*302*/         FILTER_DESCRIPTOR descriptor = setBasicDescriptor(new FILTER_DESCRIPTOR());
/*303*/         descriptor.Protocol = ICMP;
/*304*/         
/*305*/         return descriptor;
/*306*/     }
/*307*/     
/*308*/     // IPフィルタを新規作成する
/*309*/     public static FILTER_DESCRIPTOR getIPfilter()
/*310*/     {
/*311*/         FILTER_DESCRIPTOR descriptor = setBasicDescriptor(new FILTER_DESCRIPTOR());
/*312*/         descriptor.SrcPort = ANY_PORT;
/*313*/         descriptor.DstPort = ANY_PORT;
/*314*/         descriptor.CeilingSrcPort = ANY_PORT;
/*315*/         descriptor.CeilingDstPort = ANY_PORT;
/*316*/         
/*317*/         return descriptor;
/*318*/     }
/*319*/     
/*320*/     // TCPフィルタを新規作成する
/*321*/     public static FILTER_DESCRIPTOR getTCPfilter()
/*322*/     {
/*323*/         FILTER_DESCRIPTOR descriptor = setBasicDescriptor(new FILTER_DESCRIPTOR());
/*324*/         descriptor.Protocol = TCP;
/*325*/         
/*326*/         return descriptor;
/*327*/     }
/*328*/     
/*329*/     // UDPフィルタを新規作成する
/*330*/     public static FILTER_DESCRIPTOR getUDPfilter()
/*331*/     {
/*332*/         FILTER_DESCRIPTOR descriptor = setBasicDescriptor(new FILTER_DESCRIPTOR());
/*333*/         descriptor.Protocol = UDP;
/*334*/         
/*335*/         return descriptor;
/*336*/     }
これらのメソッドは各種フィルタの基本設定をした状態で得られます。


メニューに戻る inserted by FC2 system