码迷,mamicode.com
首页 > 其他好文 > 详细

网络知识点大杂烩

时间:2015-08-29 00:36:43      阅读:258      评论:0      收藏:0      [点我收藏+]

标签:

  本文是个大杂烩,集中记述个人平时学习或遇到的关于网络的知识点。

SYN Flood

   我们先来看一下TCP/IP三次握手的过程:

   技术分享

  1)Host A 发送一个TCP SYNchronize 包到 Host B
  2)Host B 收到 Host A的SYN
  3)Host B 发送一个 SYNchronize-ACKnowledgement
  4)Host A 接收到Host B的 SYN-ACK
  5)Host A 发送ACKnowledge
  6)Host B 接收到ACK
  7)TCP socket 连接建立ESTABLISHED

  在三次握手过程中,Host B发送SYN-ACK之后,收到Host A的ACK之前的TCP连接称为半连接(half-open connect)。此时Host B处于SYN_RECV状态。当收到ACK后,Host B转入ESTABLISHED状态。
  SYN攻击就是攻击端Host A在短时间内伪造大量不存在的伪IP地址,向Host B不断地发送SYN包,Host B回复确认包,并等待Host A的确认。由于源地址是不存在的,Host B需要不断的重发包直至超时。这些伪造的SYN包将长时间占用未连接队列,正常的SYN请求被丢弃,目标系统运行缓慢,严重者引起网络堵塞甚至系统瘫痪。
  SYN flood攻击是一种典型的DDos攻击。检测SYN攻击非常的方便,当我们在服务器上看到大量的半连接状态时,特别是源IP地址是随机的,基本上可以断定这是一次SYN攻击。

  更详细的请参考:

  Linux下分析SYN flood攻击案例

  TCP洪水攻击(SYN Flood)的诊断和处理

  TCP SYN Flood攻击的原理机制/检测与防范及防御方法

几种TCP连接中出现RST的情况 

  这部分摘自博文几种TCP连接中出现RST的情况。 

  在TCP协议中RST表示复位,用来异常的关闭连接,在TCP的设计中它是不可或缺的。发送RST包关闭连接时,不必等缓冲区的包都发出去,直接就丢弃缓存区的包发送RST包。而接收端收到RST包后,也不必发送ACK包来确认。

  其实在网络编程过程中,各种RST错误其实是比较难排查和找到原因的。下面列出几种会出现RST的情况。

端口未打开

  服务器程序端口未打开而客户端来连接。这种情况是最为常见和好理解的一种了。去telnet一个未打开的TCP的端口可能会出现这种错误。这个和操作系统的实现有关。在某些情况下,操作系统也会完全不理会这些发到未打开端口请求。

  比如在下面这种情况下,主机241向主机114发送一个SYN请求,表示想要连接主机114的40000端口,但是主机114上根本没有打开40000这个端口,于是就向主机241发送了一个RST。这种情况很常见。特别是服务器程序core dump之后重启之前连续出现RST的情况会经常发生。

  技术分享

  当然在某些操作系统的主机上,未必是这样的表现。比如向一台WINDOWS7的主机发送一个连接不存在的端口的请求,这台主机就不会回应。

请求超时

  曾经遇到过这样一个情况:一个客户端连接服务器,connect返回-1并且error=EINPROGRESS。 直接telnet发现网络连接没有问题。ping没有出现丢包。用抓包工具查看,客户端是在收到服务器发出的SYN之后就莫名其妙的发送了RST。

  比如像下面这样:

  技术分享

有89、27两台主机。主机89向主机27发送了一个SYN,表示希望连接8888端口,主机27回应了主机89一个SYN表示可以连接。但是主机89却很不友好,莫名其妙的发送了一个RST表示我不想连接你了。

  后来经过排查发现,在主机89上的程序在建立了socket之后,用setsockopt的SO_RCVTIMEO选项设置了recv的超时时间为100ms。而我们看上面的抓包结果表示,从主机89发出SYN到接收SYN的时间多达110ms。(从15:01:27.799961到15:01:27.961886, 小数点之后的单位是微秒)。因此主机89上的程序认为接收超时,所以发送了RST拒绝进一步发送数据。

提前关闭

  关于TCP,我们在教科书里都读到过一句话,‘TCP是一种可靠的连接‘。 而这可靠有这样一种含义,那就是操作系统接收到的来自TCP连接中的每一个字节,我都会让应用程序接收到。如果应用程序不接收怎么办?你猜对了,RST。

  看两段程序:

技术分享
 1 //server.c
 2  
 3 int main(int argc, char** argv)  
 4 {  
 5     int listen_fd, real_fd;  
 6     struct sockaddr_in listen_addr, client_addr;  
 7     socklen_t len = sizeof(struct sockaddr_in);  
 8     listen_fd = socket(AF_INET, SOCK_STREAM, 0);  
 9     if(listen_fd == -1)  
10     {  
11         perror("socket failed   ");  
12         return -1;  
13     }  
14     bzero(&listen_addr,sizeof(listen_addr));  
15     listen_addr.sin_family = AF_INET;  
16     listen_addr.sin_addr.s_addr = htonl(INADDR_ANY);  
17     listen_addr.sin_port = htons(SERV_PORT);  
18     bind(listen_fd,(struct sockaddr *)&listen_addr, len);  
19     listen(listen_fd, WAIT_COUNT);  
20     while(1)  
21     {  
22         real_fd = accept(listen_fd, (struct sockaddr*)&client_addr, &len);  
23         if(real_fd == -1)  
24         {  
25             perror("accpet fail  ");  
26             return -1;  
27         }  
28         if(fork() == 0)  
29         {  
30             close(listen_fd);  
31             char pcContent[4096];
32             read(real_fd,pcContent,4096);
33             close(real_fd);  
34             exit(0);              
35         }  
36         close(real_fd);  
37     }     
38     return 0;  
39 }
server.c

  这一段是server的最简单的代码。逻辑很简单,监听一个TCP端口然后当有客户端来连接的时候fork一个子进程来处理。注意看的是这一段fork里面的处理:

1 char pcContent[4096];
2 read(real_fd,pcContent,4096);
3 close(real_fd);

  每次只是读socket的前4096个字节,然后就关闭掉连接。

  然后再看一下client的代码:

技术分享
 1 //client.c
 2 int main(int argc, char** argv)  
 3 {  
 4     int send_sk;  
 5     struct sockaddr_in s_addr;  
 6     socklen_t len = sizeof(s_addr);  
 7     send_sk = socket(AF_INET, SOCK_STREAM, 0);  
 8     if(send_sk == -1)  
 9     {  
10         perror("socket failed  ");  
11         return -1;  
12     }  
13     bzero(&s_addr, sizeof(s_addr));  
14     s_addr.sin_family = AF_INET;  
15  
16     inet_pton(AF_INET,SER_IP,&s_addr.sin_addr);  
17     s_addr.sin_port = htons(SER_PORT);  
18     if(connect(send_sk,(struct sockaddr*)&s_addr,len) == -1)  
19     {  
20         perror("connect fail  ");  
21         return -1;  
22     }  
23     char pcContent[5000]={0};
24     write(send_sk,pcContent,5000);
25     sleep(1);
26     close(send_sk);
27 }
client.c

  这段代码更简单,就是打开一个socket然后连接一个服务器并发送5000个字节。刚才我们看服务器的代码,每次只接收4096个字节,那么就是说客户端发送的剩下的4个字节服务端的应用程序没有接收到,服务器端的socket就被关闭掉,这种情况下会发生什么状况呢,还是抓包看一看。

  技术分享

  前三行就是TCP的3次握手,从第四行开始看,客户端的49660端口向服务器的9877端口发送了5000个字节的数据,然后服务器端发送了一个ACK进行了确认,紧接着服务器向客户端发送了一个RST断开了连接。和我们的预期一致。

在一个已关闭的socket上收到数据

  如果某个socket已经关闭,但依然收到数据也会产生RST。

  服务端和客户端代码如下:

技术分享
 1 int main(int argc, char** argv)  
 2 {  
 3     int listen_fd, real_fd;  
 4     struct sockaddr_in listen_addr, client_addr;  
 5     socklen_t len = sizeof(struct sockaddr_in);  
 6     listen_fd = socket(AF_INET, SOCK_STREAM, 0);  
 7     if(listen_fd == -1)  
 8     {  
 9         perror("socket failed   ");  
10         return -1;  
11     }  
12     bzero(&listen_addr,sizeof(listen_addr));  
13     listen_addr.sin_family = AF_INET;  
14     listen_addr.sin_addr.s_addr = htonl(INADDR_ANY);  
15     listen_addr.sin_port = htons(SERV_PORT);  
16     bind(listen_fd,(struct sockaddr *)&listen_addr, len);  
17     listen(listen_fd, WAIT_COUNT);  
18     while(1)  
19     {  
20         real_fd = accept(listen_fd, (struct sockaddr*)&client_addr, &len);  
21         if(real_fd == -1)  
22         {  
23             perror("accpet fail  ");  
24             return -1;  
25         }  
26         if(fork() == 0)  
27         {  
28             close(listen_fd);  
29             char pcContent[4096];
30             read(real_fd,pcContent,4096);
31             close(real_fd);  
32             exit(0);              
33         }  
34         close(real_fd);  
35     }     
36     return 0;  
37 }  
server.c
技术分享
 1 int main(int argc, char** argv)  
 2 {  
 3     int send_sk;  
 4     struct sockaddr_in s_addr;  
 5     socklen_t len = sizeof(s_addr);  
 6     send_sk = socket(AF_INET, SOCK_STREAM, 0);  
 7     if(send_sk == -1)  
 8     {  
 9         perror("socket failed  ");  
10         return -1;  
11     }  
12     bzero(&s_addr, sizeof(s_addr));  
13     s_addr.sin_family = AF_INET;  
14  
15     inet_pton(AF_INET,SER_IP,&s_addr.sin_addr);  
16     s_addr.sin_port = htons(SER_PORT);  
17     if(connect(send_sk,(struct sockaddr*)&s_addr,len) == -1)  
18     {  
19         perror("connect fail  ");  
20         return -1;  
21     }  
22     char pcContent[4096]={0};
23     write(send_sk,pcContent,4096);
24     sleep(1);
25     write(send_sk,pcContent,4096);
26     close(send_sk);
27 }  
client.c

  客户端在服务端已经关闭掉socket之后,仍然在发送数据。这时服务端会产生RST。

  技术分享

 

网络知识点大杂烩

标签:

原文地址:http://www.cnblogs.com/xiehongfeng100/p/4768209.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!