raw socket (续)
来源:互联网 发布:网络渗透测试工程师 编辑:程序博客网 时间:2024/06/05 11:17
最近在学习raw socket,上一篇文章也成功发送了SYN,使得服务端的状态变为SYN_RECV。
http://blog.csdn.net/lizhia1221/article/details/51946592
因此,就想尝试去模拟TCP三次握手,无非就是发送三个数据包嘛,想想好像挺简单的,然后瞬间打脸了。
下面是测试代码:
/* 模拟tcp三次握手,然后收到syn+ack之后,内核也会处理包, 自动发送rst,因此目前虽然可以模拟三次握手,但是提前被内 核结束了,无法建立连接 */#include <unistd.h>#include <stdio.h>#include <stdlib.h>#include <string.h>#include <sys/socket.h>#include <errno.h>#include <netinet/ip.h>#include <netinet/tcp.h>#include <arpa/inet.h>#define DEST_PORT 8888#define SRC_PORT 9999#define SRC_ADDRESS "192.168.0.174"#define DEST_ADDRESS "192.168.0.174"//tcp 伪首部struct pseudo_header{ u_int32_t source_address; u_int32_t dest_address; u_int8_t placeholder; u_int8_t protocol; u_int16_t tcp_length;};/* Generic checksum calculation function*/unsigned short csum(unsigned short *ptr,int nbytes){ register long sum; unsigned short oddbyte; register short answer; sum=0; while(nbytes>1) { sum+=*ptr++; nbytes-=2; } if(nbytes==1) { oddbyte=0; *((u_char*)&oddbyte)=*(u_char*)ptr; sum+=oddbyte; } sum = (sum>>16)+(sum & 0xffff); sum = sum + (sum>>16); answer=(short)~sum; return(answer);}int get_ack_seq(unsigned char* buffer,int size,unsigned int &seq);int fill_packet(char *datagram,int dsize,unsigned char* buffer,int bsize,unsigned int ack_seq);int connect(){ int fd=socket(PF_INET,SOCK_RAW,IPPROTO_TCP); if(fd==-1) { perror("Failed to create socket"); exit(1); } //Datagram to represent the packet char datagram[4096],source_ip[32],*pseudogram; memset(datagram,0,sizeof(datagram)); //IP Header struct iphdr *iph=(struct iphdr*)datagram; //TCP Header struct tcphdr *tcph=(struct tcphdr*)(datagram+sizeof(struct iphdr)); struct pseudo_header psh; //socket address struct sockaddr_in sin; strcpy(source_ip,SRC_ADDRESS); sin.sin_family=AF_INET; sin.sin_port=htons(DEST_PORT); sin.sin_addr.s_addr=inet_addr(DEST_ADDRESS); //Fill in the IP Header iph->ihl=5;// 20 byte iph->version=4;//ipv4 iph->tos=0; iph->tot_len=sizeof(struct iphdr)+sizeof(struct tcphdr); iph->id=htonl(54321);//ID iph->frag_off=0; iph->ttl=255; iph->protocol=IPPROTO_TCP; iph->check=0; iph->saddr=inet_addr(source_ip); iph->daddr=sin.sin_addr.s_addr; //IP checksum iph->check=csum((unsigned short*)datagram,sizeof(struct iphdr)); //TCP header tcph->source = htons(SRC_PORT); tcph->dest = htons(DEST_PORT); tcph->seq = htonl(1); tcph->ack_seq = htonl(0); tcph->doff = 5; //tcp header size tcph->fin=0; tcph->syn=1; tcph->rst=0; tcph->psh=0; tcph->ack=0; tcph->urg=0; tcph->window = htons (5840); /* maximum allowed window size */ tcph->check = 0; //leave checksum 0 now, filled later by pseudo header tcph->urg_ptr = 0; //Now the TCP checksum psh.source_address = inet_addr(source_ip); psh.dest_address = sin.sin_addr.s_addr; psh.placeholder = 0; psh.protocol = IPPROTO_TCP; psh.tcp_length = htons(sizeof(struct tcphdr)); int psize=sizeof(struct pseudo_header)+sizeof(struct tcphdr); pseudogram=(char*)malloc(psize); memcpy(pseudogram,(char*)&psh,sizeof(struct pseudo_header)); memcpy(pseudogram+sizeof(struct pseudo_header),tcph,sizeof(struct tcphdr)); tcph->check=csum((unsigned short*)pseudogram,psize); //TP_HDRINCL to tell the kernel that headers are included in the pakcet int one=1; const int *val=&one; if(setsockopt(fd,IPPROTO_IP,IP_HDRINCL,val,sizeof(int))<0) { perror("Error setting IP_HDRINCL\n"); exit(0); } //send SYN if(sendto(fd,datagram,iph->tot_len,0,(struct sockaddr*)&sin,sizeof(sin))<0) { perror("SYN send to failed\n"); } else { printf("SYN Packet seq=%u \n",1); } //recv SYN+ACK struct sockaddr_in saddr; unsigned char buffer[4096]; unsigned int ack_seq,seq,data_size,saddr_len; while(1) { data_size=recvfrom(fd,buffer,4096,0,(struct sockaddr*)&saddr,(socklen_t*)&saddr_len); //printf("%d %s\n",saddr_len,inet_ntoa(saddr.sin_addr)); if(data_size<0) continue; //为什么saddr返回的端口号为0 if(/*saddr.sin_port!=sin.sin_port ||*/saddr.sin_addr.s_addr!=sin.sin_addr.s_addr) continue; ack_seq=get_ack_seq(buffer,data_size,seq); if(ack_seq==-1||ack_seq!=2)//syn seq=1 continue; else { printf("SYN+ACK Packet Get seq=%u ack=%u port=%u\n",seq,ack_seq,ntohs(saddr.sin_port)); break; } } //send ACK fill_packet(datagram,iph->tot_len,buffer,data_size,seq+1); if(sendto(fd,datagram,iph->tot_len,0,(struct sockaddr*)&sin,sizeof(sin))<0) { perror("ACK send to failed\n"); } else { printf("ACK Packet ack=%u \n",seq+1); }}int get_ack_seq(unsigned char* buffer,int size,unsigned int &seq){ struct iphdr *iph=(struct iphdr*)buffer; struct tcphdr *tcph=(struct tcphdr*)(buffer+iph->ihl*4); if(iph->protocol!=6) return -1; if(tcph->syn!=1||tcph->ack!=1) return -1; // printf("sp=%d\n",ntohs(tcph->source)); seq=ntohl(tcph->seq); return ntohl(tcph->ack_seq);}int fill_packet(char *datagram,int dsize,unsigned char* buffer,int bsize,unsigned int ack_seq){ struct iphdr *iph=(struct iphdr*)datagram; struct tcphdr *tcph=(struct tcphdr*)(datagram+iph->ihl*4); struct iphdr *b_iph=(struct iphdr*)buffer; struct tcphdr *b_tcph=(struct tcphdr*)(buffer+b_iph->ihl*4); char *pseudogram; struct pseudo_header psh; //IP Header iph->id=htonl(54322);//ID iph->check=0; iph->saddr=b_iph->daddr; iph->daddr=b_iph->saddr; //IP checksum iph->check=csum((unsigned short*)datagram,sizeof(struct iphdr)); //TCP Header tcph->source = b_tcph->dest; tcph->dest = b_tcph->source; tcph->seq = htonl(2); tcph->ack_seq = htonl(ack_seq); tcph->syn=0; tcph->ack=1; tcph->check = 0; //leave checksum 0 now, filled later by pseudo header //Now the TCP checksum psh.source_address = b_tcph->dest; psh.dest_address = b_tcph->source; psh.placeholder = 0; psh.protocol = IPPROTO_TCP; psh.tcp_length = htons(sizeof(struct tcphdr)); int psize=sizeof(struct pseudo_header)+sizeof(struct tcphdr); pseudogram=(char*)malloc(psize); memcpy(pseudogram,(char*)&psh,sizeof(struct pseudo_header)); memcpy(pseudogram+sizeof(struct pseudo_header),tcph,sizeof(struct tcphdr)); tcph->check=csum((unsigned short*)pseudogram,psize);}int main(){ connect();}
服务端测试代码:
#include <stdio.h>#include <string.h>#include <stdlib.h>#include <sys/socket.h>#include <arpa/inet.h>#include <errno.h>#include <unistd.h>#define PORT 8888int main(){ int fd = socket(PF_INET,SOCK_STREAM,0); if(fd<0) { perror("create socket error"); exit(0); } struct sockaddr_in sin; sin.sin_family=AF_INET; sin.sin_port=htons(PORT); sin.sin_addr.s_addr=INADDR_ANY; if(bind(fd,(struct sockaddr*)&sin,sizeof(struct sockaddr))<0) { perror("socket bind error"); exit(0); } if(listen(fd,100)<0) { perror("socket listen error"); exit(0); } printf("start listening\n"); int clifd; struct sockaddr_in client; socklen_t len; while(1) { if((clifd=accept(fd,(struct sockaddr*)&client,&len))<0) { perror("accept error"); } else { printf("accept success\n"); } }}
运行结果:
wireshark抓包如下:
结果意外的多出了一个从9999端口到8888端口的RST包,导致TCP握手提前被终止。
百思不得其解,google查资料咯。大概意思是tcp协议栈也会处理三次握手,当内核收到SYN+ACK时并不知道raw socket发送了SYN包,因此响应RST终止连接。
目前没有找到解决方案,下面是有关该问题的一些参考资料:
http://bbs.csdn.net/topics/320208382
http://blog.chinaunix.net/uid-795807-id-3206853.html
http://forums.codeguru.com/showthread.php?320739-Visual-C-Network-Why-do-my-machine-send-an-RST-packet-in-reply-to-a-SYN-ACK-pac
0 0
- raw socket (续)
- Raw Socket源代码(C#)
- Raw Socket
- raw socket
- raw socket
- RAW SOCKET
- raw socket
- raw socket
- RAW SOCKET
- Raw Socket
- raw socket
- raw socket
- Raw Socket
- raw socket
- raw socket
- Linux socket编程(TCP,UDP,RAW)
- raw socket 编程资料(linux环境)
- Raw Socket(原始套接字)
- 生活中的常识(二)
- CF698A. Vacations【DP】
- HDU-2824- The Euler function 解题报告
- 提取URL地址中的域名与端口
- Android进程与线程
- raw socket (续)
- 多线程并发、同步,线程之间通信,主、子线程的一些问题(CountDownLatch、CyclicBarrier和Semaphore)
- apache 根目录修改+mac 启动server命令
- iOS开发中多项选择demo
- maven打包排除指定文件(jar包)
- TI的TCP/IP协议栈---NDK
- 数据恢复设备
- JS正则表达式速查
- Codeforces Round #363 (Div. 2) D DFS