raw socket (续)
2016-07-20 13:05
363 查看
最近在学习raw socket,上一篇文章也成功发送了SYN,使得服务端的状态变为SYN_RECV。
http://blog.csdn.net/lizhia1221/article/details/51946592
因此,就想尝试去模拟TCP三次握手,无非就是发送三个数据包嘛,想想好像挺简单的,然后瞬间打脸了。
下面是测试代码:
服务端测试代码:
运行结果:
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
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,si 4000 zeof(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 8888 int 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
相关文章推荐
- spark 集群搭建 详细步骤
- js页面跳转
- ServletConfig&ServletContext对比
- 国内一线互联网公司内部面试题库
- Java(Android)编程思想笔记03:在Android开发中使用MVP模式
- vs2015配置opencv2.4.9问题解决
- 系统运行步骤
- Codeforces-Round-#363-Fix-a-Tree
- java基于TCP的socket数据包拆分方法
- NYOJ_123_士兵杀敌(四)插线问点
- Qualcomm平台camera调试移植入门
- Qualcomm平台camera调试移植入门
- Python读取写入TXT正确姿势
- 报到!初开博客
- redis数据类型Set的常用命令
- uboot的启动流程
- maven打包排除指定文件(jar包)
- HDU1394 Minimum Inversion Number(线段树)
- 第五部分:UI基本布局 & 引入布局(LinearLayout、RelativeLayout、FrameLayout、TableLayout)
- linux内核的编译过程