首先回忆下R3的socket编程。
windows防火墙有TDI,NDIS,后来进化成WFP,从难到易。
简述什么是防火墙
就是通过hook ,过滤,回调监控,对网络数据进行管理
比如TDI就是一套hook(ARPhook),一套过滤。
NDIS,WFP都通过回调过滤。
网络防火墙可以实现传输数据加解密。流量查看。
//tcp
//服务器端
int fd,fd_client;
struct sockaddr_in addr_server;
struct sockaddr_in addr_client;
fd =socket(AF_INET,SOCK_STREAM,0);//建立socket
memset(&addr_server,0,sizeof(addr_server));
addr_server.sin_family=AF_INET;/*该属性表示接收本机或其他机器传输*/
addr_server.sin_port=htos(1234);//"Host to Network Short"
addr_server.sin_addr.s_addr=inet_addr(INADDRANY);/*IP,括号内容表示本机IP*/
bind(fd,(struct sockaddr*)&addr_server,sizeof(addr_server));
listen(fd,5);//开启监听 ,第二个参数是最大监听数
while(1)
{
fd_client=accept(fd,(struct sockaddr_in*)&addr_client,sizeof(addr_client));
read(fd_client,buff,100);
write(fd_client,buff,100);
}
close(fd);
//客户端
int fd,fd_client;
struct sockaddr_in addr_server;
struct sockaddr_in dest_addr;
fd =socket(AF_INET,SOCK_STREAM,0);//建立socket
memset(&addr_server,0,sizeof(addr_server));
addr_server.sin_family=AF_INET;/*该属性表示接收本机或其他机器传输*/
addr_server.sin_port=htos(1234);//"Host to Network Short"
addr_server.sin_addr.s_addr=inet_addr(127.0.0.1);/*IP,括号内容表示本机IP*/
connect(fd,(struct sockaddr*)&dest_addr,sizeof(dest_addr));
write(fd,buff,100);
read(fd,buff,100);
防火墙对应着IRP有三个,IRP_MJ_CREATE,IRP_MJ_DEVICECONTROL,IRP_MJ_INTERNORLDEVICECONTROL.
读写等都属于IRP_MJ_DEVICECONTROL。
其次windows服务器端网络IO模型有,选择(Select),异步选择(WSAAsyncSelect),事件选择(WSAEventSelect),重叠I/O(OverLapped I/O),完成端口(Completion Port)Linux使用epoll模型。
网络打洞,P2P原理
NAT(Network Address Translation)网络地址转换
只有NAT确信内部想与外部通信,NAT才会让外部的数据包进入内部。由防火墙进行内网外网IP地址转换
比如下面的网络环境
Client A-》Nat A-》internet《-Nat B《-Client B
UDP打洞,有一定的失败率。
A--FA--SERVER--FB--B
A,B为主机,FA,FB为防火墙,SERVER为服务器
1.如果A想与B通信
2.A首先连接SERVER SERVER得到A的外网FA的地址和端口
3.B也要连接SERVER,SERVER得到B的外网FB的地址和端口
4.A告诉SERVER要与B通信
5.SERVER通过FB翻书消息给B,告诉B,Ad外网和FA的地址和端口
6.B向FA发送数据包(肯定会被FA抛弃,因为FA上并没有A->FB的合法SEESSION)但是FB上就建立了有B->FA的合法SEESSION了。
7.B发送数据包给SERVER让SERVER通知A我已经把洞打好了。
8.A接到通知后,向B的外网发送FB数据包,就不会被抛弃掉了,因为对于FB来说,它看到的是AFA的地址,通过6,B已经让FA成FB内何方,所以到FA发送数据包给FB时,FB就会接受并转发给B
注意路由器防火墙的UDP打洞端口有时间现在,超时没有数据通信就会自动关闭。
另外网络传输数据就是在传输层打上传输层的头比如TCP里面有端口,然后网络层打上IP头里面有IP地址,在物理层打上MAC头。注意IP头里报头长度可以确定TCP长度,里面协议就是传输层的头的类型。
另外TCP连接3次握手,4次挥手,因为不一定服务器端已经发送完数据,所以要把客户端发来的FIN的ACK和FIN包分开。
TCP里面有7个定时器
- 建立连接定时器(connection-establishment timer)
- 重传定时器(retransmission timer)
- 延迟应答定时器(delayed ACK timer)
- 坚持定时器(persist timer)
- 保活定时器(keepalive timer)
- FIN_WAIT_2定时器(FIN_WAIT_2 timer)
- TIME_WAIT定时器 (TIME_WAIT timer, 也叫2MSL timer)
https://blog.csdn.net/u013929635/article/details/82623611
建立连接定时器(connection-establishment timer)
顾名思义,这个定时器是在建立连接的时候使用的, 我们知道, TCP建立连接需要3次握手, 如下图所示:
建立连接的过程中,在发送SYN时, 会启动一个定时器(默认应该是3秒),如果SYN包丢失了, 那么3秒以后会重新发送SYN包的(当然还会启动一个新的定时器, 设置成6秒超时),当然也不会一直没完没了的发SYN包, 在/proc/sys/net/ipv4/tcp_syn_retries 可以设置到底要重新发送几次SYN包。
重传定时器(retransmission timer)
重传定时器在TCP发送数据时设定,在计时器超时后没有收到返回的确认ACK,发送端就会重新发送队列中需要重传的报文段。使用RTO重传计时器一般有如下规则:
- 当TCP发送了位于发送队列最前端的报文段后就启动这个RTO计时器;
- 如果队列为空则停止计时器,否则重启计时器;
- 当计时器超时后,TCP会重传发送队列最前端的报文段;
- 当一个或者多个报文段被累计确认后,这个或者这些报文段会被清除出队列
重传计时器保证了接收端能够接收到丢失的报文段,继而保证了接收端交付给接收进程的数据始终的有序完整的。因为接收端永远不会把一个失序不完整的报文段交付给接收进程。
延迟应答定时器(delayed ACK timer)
延迟应答也被成为捎带ACK, 这个定时器是在延迟应答的时候使用的。 为什么要延迟应答呢? 延迟应答是为了提高网络传输的效率。
举例说明,比如服务端收到客户端的数据后, 不是立刻回ACK给客户端, 而是等一段时间(一般最大200ms),这样如果服务端要是有数据需要发给客户端,那么这个ACK就和服务端的数据一起发给客户端了, 这样比立即回给客户端一个ACK节省了一个数据包。
坚持定时器(persist timer)
我们已经知道TCP通过让接收方指明希望从发送方接收的数据字节数(即窗口大小)来进行流量控制。如果窗口大小为 0会发生什么情况呢?这将有效地阻止发送方传送数据,直到窗口变为非0为止。接收端窗口变为非0后,就会发送一个确认ACK指明需要的报文段序号以及窗口大小。
如果这个确认ACK丢失了,则双方就有可能因为等待对方而使连接终止:接收方等待接收数据(因为它已经向发送方通告了一个非0的窗口),而发送方在等待允许它继续发送数据的窗口更新。为防止这种死锁情况的发生,发送方使用一个坚持定时器 (persist timer)来周期性地向接收方查询,以便发现窗口是否已增大。这些从发送方发出的报文段称为窗口探查 (window probe)。
保活定时器(keepalive timer)
在TCP连接建立的时候指定了SO_KEEPALIVE,保活定时器才会生效。如果客户端和服务端长时间没有数据交互,那么需要保活定时器来判断是否对端还活着,但是这个其实很不实用,因为默认是2小时没有数据交互才探测,时间实在是太长了。如果你真的要确认对端是否活着, 那么应该自己实现心跳包,而不是依赖于这个保活定时器。
FIN_WAIT_2定时器(FIN_WAIT_2 timer)
主动关闭的一端调用完close以后(即发FIN给被动关闭的一端, 并且收到其对FIN的确认ACK)则进入FIN_WAIT_2状态。如果这个时候因为网络突然断掉、被动关闭的一段宕机等原因,导致主动关闭的一端不能收到被动关闭的一端发来的FIN,主动关闭的一段总不能一直傻等着,占着资源不撒手吧?这个时候就需要FIN_WAIT_2定时器出马了, 如果在该定时器超时的时候,还是没收到被动关闭一端发来的FIN,那么不好意思, 不等了, 直接释放这个链接。FIN_WAIT_2定时器的时间可以从/proc/sys/net/ipv4/tcp_fin_timeout中查看和设置。
TIME_WAIT定时器 (TIME_WAIT timer, 也叫2MSL timer)
TIME_WAIT是主动关闭连接的一端最后进入的状态, 而不是直接变成CLOSED的状态, 为什么呢?第一个原因是万一被动关闭的一端在超时时间内没有收到最后一个ACK, 则会重发最后的FIN,2MSL(报文段最大生存时间)等待时间保证了重发的FIN会被主动关闭的一段收到且重新发送最后一个ACK;另外一个原因是在2MSL等待时间时,任何迟到的报文段会被接收并丢弃,防止老的TCP连接的包在新的TCP连接里面出现。不可避免的,在这个2MSL等待时间内,不会建立同样(源IP, 源端口,目的IP,目的端口)的连接。
ARP协议
https://www.cnblogs.com/csguo/p/7527303.html
,