2011年10月29日土曜日

php でパケットキャプチャを行う2

今更ながら、pcaplibを使った方が、
うまくいくパケットキャプチャできるのでは?


libpcap - 私的メモ

libpcapリファレンス

tcpdumpにおけるlibpcapの使われ方


※1、コンパイルオプションに、「-lpcap」を加える必要がある。


典型的なlibpcap利用の流れ。
(細かい引数とかは、リファレンスを参考にする)

1,deviceをプロミスキャスモードでオープンする。


   // get device
   if (argc != 2) {
      dev = pcap_lookupdev(errbuf);
      if (dev == NULL) {
              fprintf(stderr, "no device\n",errbuf);
              exit(1);
      }
   }else if(argc == 2){
      dev = argv[1];
   }
   printf("dev: %s\n",dev);

   // open device
   handle = pcap_open_live(dev, BUFSIZ, 1, 1000, errbuf);
   if (handle == NULL) {
           fprintf(stderr, "cannot open device\n",errbuf);
           exit(1);
   }else {
           printf("open device : %s\n",dev);
   }


2,フィルタをコンパイルしてセットする。


   // compile filter
   if(pcap_compile(handle, &fp, filter_exp, 0, net)==-1){
           fprintf(stderr, "cannot compile filter\n",errbuf);
           exit(1);
   }else{
           printf("compile filer success\n");
   }

   // setting filter
   if (pcap_setfilter(handle, &fp) == -1) {
           fprintf(stderr, "cannot set filter\n",errbuf);
           exit(1);
   }


※ filter_expにセットする文字列は、tcpdumpのオプションと一致する。たぶん。

3,パケットを取得する。
方法1 : pcap_next
パケットを1個取得して、返却する。


   packet = pcap_next(handle, &header);
   if(packet == NULL){    
      return;
   }
   // read packet
   pkt = packet_read(NULL,handle,packet);

※ packet_readは、方法2のコールバック関数をちょっと修正したもの。
基本やることは同じ。



方法2 : pcap_loop
パケットを受け取ったらコールバック関数を実行する。

   cnt = 1;
   //if (pcap_loop(handle, cnt, printer, NULL) < 0) {
   if (pcap_loop(handle, cnt, got_packet, NULL) < 0) {
           fprintf(stderr, "pcap_loop error: %s\n",pcap_geterr(handle));
           exit(1);
   }



【現在の問題点メモ】

1,srcipとdstipが同じになってしまう。
inet_ntoaの落とし穴で対応する。

2,HTTPヘッダ情報からうまく欲しい情報を抽出できていない。
PHP側で対処可能だとおもう。

3,長時間実行すると(多くのパケットを取ると)落ちる。
たぶんメモリを開放してないとかそういうのだと思う。

4,パケットの量が多いと取りこぼす。
コールバックの形をトラずPHPに送っているから仕方ないのか。
PHPから使うとき、filterの設定をしっかりして、
対象範囲を限定すればなんとかなるか。






0 件のコメント:

コメントを投稿