ループバックパケットを除くパケットの取得

プログラムの方で最近、L2でパケットをキャプチャし、DST_MACアドレスの値を変更し送信するものを作成している。
まあ、ARPスプーフィング関係のツールですな・・・


で、問題発生。
L2でパケットの送受信をするため、ループバックのパケットを受信してしまう問題に直面した。
普通なら、DST_MACアドレスが自分なら落とせば問題ないのだが、DST_MACアドレスを書き換えているのでそれはできない。
と言うわけでいろいろ試行錯誤した結果、「続きを見る」のようなプログラムで何とかなることが解った。


話としては
Socket_Handle = socket( PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
で、L2のソケットを作成し、


RecvBufferLen = recvfrom(Socket_Handle, (char *)RecvBuffer, sizeof(RecvBuffer), 0, (struct sockaddr *) &sll,&lngAPIReVal);
で、パケットを受信し、sllにパケットの情報を設定、


if ( sll.sll_pkttype != PACKET_OUTGOING ){
  ...
}
で、ループバックかどうか調べて落とす。
と言った形になる。


しかし、ここで注意が必要、L2でパケットを受信する場合は↓のようで問題ない。
Socket_Handle = socket( PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));

が、L2でパケットを送信する場合は↓の様にしないと問題が出る場合がある。
Socket_Handle = socket( PF_PACKET, SOCK_PACKET, htons(ETH_P_ALL));


#include <stdio.h>
#include <linux/sockios.h>
#include <netpacket/packet.h>
#include <net/if.h>
#include <netinet/if_ether.h>

#define	_ETH_MAX_LEN	1500
#define	SOCKET		int	//ソケットを定義

void AnalyzeDump(char *RecvBuffer, int RecvBufferLen, int BufferOffSet){
  int	i;
  int	j;
  int	addr;
  char	*Dump;
  int	DumpLen;

  //解析する領域の確定
  Dump = (char *)(RecvBuffer + BufferOffSet);
  DumpLen = RecvBufferLen - BufferOffSet;

  if (DumpLen == 0){
    printf("  No Data\n");
    return;
  }
  printf("  DataSize:   0x%04X (%u)\n", DumpLen, DumpLen );
  printf("         +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 +A +B +C +D +E +F\n");
  for( i = 0; i <= DumpLen; i = i + 16 ){
  printf("  %04X : ",i );
    for ( j = 0; j < 16; j++){
      addr = i + j;
      if ( DumpLen >= addr ){
        printf("%02X ", ( 0xFF & *(Dump + addr)) );
      }else{
        printf("   ");
      }
    }
    printf("| ");
    for ( j = 0; j < 16; j++){
      addr = i + j;
      if ( DumpLen >= addr ){
        if (*(Dump + addr) >= 32 && *(Dump + addr) <= 126 ){
          printf("%c",*(Dump + addr));
        }else{
          printf(".");
        }
      }else{
        printf(" ");
      }
    }
    printf(" |\n");
  }
}

int main(int argc, char *argv[]){
  SOCKET	Socket_Handle;
  struct	sockaddr_ll sll;
  struct	ifreq ifr;
  fd_set	FD_Handle;
  char 	RecvBuffer[_ETH_MAX_LEN];
  int 	RecvBufferLen = 0;
  int	BufferOffSet = 0;
  int	lngAPIReVal;
  int	Filter;

  //ソケット作成
  if ((Socket_Handle = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL))) < 0){
    fprintf(stderr, "Create PACKET Socket Error(%d)\n",Socket_Handle);
    exit(-1);
  }
  //インターフェースのIndexの取得
  memset(&ifr, 0, sizeof(ifr));
  strncpy(ifr.ifr_name, "eth0", IFNAMSIZ);
  ioctl(Socket_Handle, SIOCGIFINDEX, &ifr);

  //インターフェースの固定準備
  memset(&sll, 0xff, sizeof(sll));
  sll.sll_family = AF_PACKET;
  sll.sll_protocol = htons(ETH_P_ALL);
  sll.sll_ifindex = ifr.ifr_ifindex;

  //インターフェースの固定
  lngAPIReVal = bind(Socket_Handle, (struct sockaddr *) &sll, 
                    sizeof(struct sockaddr_ll));

  memset(RecvBuffer, 0, sizeof(RecvBuffer));
  FD_ZERO( &FD_Handle );
  FD_SET( Socket_Handle, &FD_Handle );
  select( FD_SETSIZE, &FD_Handle, NULL, NULL, NULL );
  while(1) {
    if ( FD_ISSET( Socket_Handle, &FD_Handle ) ){

      //パケットの受信
      lngAPIReVal= sizeof(struct sockaddr);
      RecvBufferLen = recvfrom(Socket_Handle, 
        (char *)RecvBuffer, sizeof(RecvBuffer), 
        0, (struct sockaddr *) &sll,&lngAPIReVal);
			
      //ループバックパケットを除くパケットをダンプ
      if ( sll.sll_pkttype != PACKET_OUTGOING ){
        AnalyzeDump(RecvBuffer, RecvBufferLen, BufferOffSet);
      }else{
        printf("loopback packet\n");
      }
    }
  }
}