ループバックパケットを除くパケットの取得
プログラムの方で最近、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"); } } } }