主页

PKI

2022-10-12
信息安全

PKI概述 #

  • PKI(public key infrastructure)公钥基础设施,指为了有效运用公钥而制定一系列规范和规格的总称。

  • PKI组成:

    • 用户:使用证书的人。
    • 认证机构:颁发证书。
    • 仓储:保存证书。
  • 证书:全称是公钥证书,包括此人的一些信息、此人的公钥,并由认证机对公钥施加的数字签名。

  • 数字签名(假设Alice要发送一条消息给Bob):

    1. Alice用单向散列函数计算消息的散列值。
    2. Alice用自己的私钥对散列值进行加密。
    3. Alice将消息和签名发送给Bob。
    4. Bob用Alice的公钥对接收到的签名进行解密。
    5. Bob将签名解密后得到的散列值和Alice直接发送的消息的散列值进行对比。
  • CA(Certification Authority)认证机构,管理证书,包括如下功能:

    • 生成密钥对(也可以由用户生成)
    • 对个人身份进行认证
    • 生成并颁发证书
    • 作废证书
  • RA(Registration Authority)注册机构,生成密钥对和个人身份认证可以交给RA来做,这样CA就只用颁发证书。

  • 仓库是保存证书的数据库,PKI用户需要的时候从中获取证书。仓库也叫证书目录。

认证机构的工作 #

  • 在认证机构生成证书密钥对的情况下,认证机构需要将私钥发送给用户。
  • 在用户自行生成密钥对的情况下,用户会请求认证机构生成证书。认证机构会用私钥进行数字签名来生成证书,证书的格式由X.509定义。
  • 如果认证机构要作废证书,即使从仓库中删除证书也无法作废,因为用户会保存证书的副本,而认证机构又不能入侵用户电脑删除副本。
    • 如果需要作废证书,认证机构需要制作一张证书作废清单(Certificate Revocation List),简称CRL。
    • PKI用户需要从认证机构获取最新的CRL,查询证书是否已经作废。
    • 假如我由Bob的证书,该证书有合法的认证机构签名,而且也在有效期内,仅凭这些不能说明该证书是有效的,还需要查询认证机构最新的CRL,来确认该证书是否有效(但很多软件并没有及时更新CRL)。

证书的层级关系 #

  • 认证机构使用私钥对用户的公钥进行数字签名,并生成了证书。用户需要使用认证机构的公钥,对数字签名进行验证。用来验证数字签名的认证机构的公钥的合法性可以由其他的认证机构施加以数字签名,从而形成了一个证书链。证书链的终点是根CA。根机构一般给自己颁发证书,叫做自签名(self-signature)。
  • 浏览器可以保存根机构的证书。

TLS流程 #

网络层 数据平面

2022-09-06
计算机网络

概述 #

  • 网络中的每一台主机和路由器中都有一个网络层部分。
  • 网络层能被分解为两个相互作用的部分,即数据平面和控制平面,数据平面的功能时决定到达路由器输入链路的数据报如何转发到该路由器的输出链路之一。控制平面讲述网络范围的逻辑,控制平面控制数据报沿着从源主机到目的主机的端到端路径中路由器之间的路由方式。
  • 传统网络层控制平面路由选择协议和数据平面转发功能已被时限为一个整体,位于一台路由器中。SDN(软件定义网络)将控制平面作为一种单独服务,明确的分离数据平面和控制平面,控制平面通常置于一台远程“控制器”中。
  • 转发:是将分组从一个输入链路接口转移到适当的输出链路接口的路由器本地动作。转发通常使用硬件实现。
  • 路由选择:指确定分组从源到目的地所采取的端到端路径的网络范围处理过程。
  • 每台网络路由器中有一个关键元素是它的转发表,路由器检查到达分组首部的一个或多个字段值,进而使用这些首部值在其转发表中索引,通过这种方式来转发分组。
  • 网络服务模型(network service model)定义了分组在发送与接收端系统之间的端到端的运输特性。
  • 因特网的网络层提供了尽力而为服务(best-effort service)。

路由器的工作原理 #

  • 路由器架构
  • 输入端口包含物理层、链路层和网络层转发的作用。通过查询转发表来决定分组的输出端口。分组会通过路由器的交换结构到达输出端口,当到达分组的速率大于转发速率,分组会存储在队列中。
  • 路由器架构
  • 交换结构将路由器的输入端口连接到它的输出端口。
  • 输出端口存储从交换结构接收到的分组,并通过执行必要的链路层和物理层功能在输出链路上传输这些分组。
  • 路由选择处理器处于控制平面,在传统路由器中,执行路由选择协议,维护路由选择表与关联链路状态信息,并为该路由器计算转发表。在SDN路由器中,路由选择处理器负责与远程控制器通信,接收远程控制器计算的转发表项。

输入端口处理和基于目的地的转发 #

  • 路由器在输入端口使用转发表来查找输出端口,使得到达的分组通过交换结构转发到输出端口。转发表是由路由选择处理器计算和更新的或者是接收来自远程的SDN控制器的内容。转发决策在每个输入端口本地做出。
  • 路由器使用分组目的地址的前缀和转发表的表项进行匹配,如果存在一个匹配项,则路由器向该匹配项相关联的链路转发分组。当存在多个匹配时,路由器使用最长前缀匹配规则,寻找表中的最长的匹配项,并向与最长前缀匹配相关联的链路接口转发分组。
  • 转发表
  • 查找转发表要求很快,实践中常常使用三态内容可寻址存储器(TCAM),查询时间通常为常数级。
  • 当有其他输入端口在使用交换结构时,一个分组可能会在进入交换结构时被暂时阻塞,因此,一个被阻塞的分组必须要在输入端口排队,并等待稍后被调度以通过交换结构。输入端口除了查找和发送外,还需要①检查分组的版本号、检验和寿命字段,并且重写后两个字段;②更新用于网络管理的计数器;③要有物理层和链路层处理。

交换 #

  • 经内存交换:在CPU的控制下进行交换,包会从输入端口拷贝到内存中,在从内存中拷贝到输出端口。速度受限于内存带宽。
  • 经总线交换:数据报经过bus总线从输入端口到输出端口。速度受限于bus带宽。
  • 经互联网络交换:克服了总线的带宽限制。纵横式交换机是一种由2N条总线组成的互联网络,连接N条输入端口和N个输出端口。当某个分组到达输入端口A,要到达输出端口Y时,交换结构闭合A和Y之间的交叉点,然后A就可以传递数据报。此时如果B向Z传输分组,则闭合B和Z之间的交叉点即可。因为A到Y和B到X使用了不同的输入输出总线。但同一时刻只能有一个数据报发给Y。

输出端口处理 #

网际协议 #

  • TCP/IP首部中的所有二进制整数再网络中传输都要求大端(最高位在左边,最低为在右边),这种字节序又叫网络字节序。
  • 协议版本号是4。
  • 首部长度通常为20个字节。所以这里的值一般是0101
  • 服务类型包括一个3bit的优先权子字段,4bit的TOS字段和1bit未用的字段。4bit的TOS分别代表:最小时延、最大吞吐量、最高可靠性和最小费用。
  • 总长度字段是指整个IP数据报的长度(首部加上数据)。
  • 标识、标志和偏移量和IP分片有关。
  • TTL(time-to-live)生存时间字段设置了数据报可以经过最多的路由器数。它指定了数据报的生存时间。初始值由源主机设置(通常为32或64),一旦经过一个处理它的路由器,它的值就减去1。当该字段的值为1时,数据报就被丢弃,并发送ICMP报文通知源主机。
  • 协议指要把分组交给哪个传输层协议。
  • 首部检验和字段是根据ip首部计算的检验和码。
  • 每一份IP数据报都包含源ip和目的ip。
  • 任选项是数据报中一个可变长的可选信息,IPv6中去掉了选项。

IPv4数据报分片 #

  • 链路层能承载的网络层分组长度是有限的,比如以太网能承载不超过1500字节的数据。一个链路层能承载的最大数据量叫MTU(最大传输单元,Maximum Transmission Unit)。
  • 为了传输超出MTU的IP数据报,将IP数据报中的数据分片成多个较小的IP数据报,用单独的链路帧来封装这些较小的IP数据报。每个这些较小的IP数据报被称为片(fragment)。
  • IP分片可发生在发送端和路由器上。而重新组装是在端系统中,路由器不会组装分片。
  • 为了让接收端确定收到的数据报是一些较大数据报的片还是单独的数据报,IP将标识、标志和片偏移字段放到IP数据报的首部中。
  • 发送主机通常将发送的每个数据报的标识位加1,如果多个片来源于同一个数据报,那么它们的标识位是相同的,为了让目的主机确认收到了数据报的最后一片,最后一片的标志置为0,其他的标志置为1,同时还使用片偏移量来确认片在数据报里的位置。

IP路由选择 #

  • IP层在内存中有一个路由表,当收到一份数据报并进行发送时,他都要对该表搜索一次。
    • 路由表的每一项都包含:①目的IP地址;②下一跳的路由器的IP地址,或者直接连接网络IP地址;下一站路由器是指一个在直接相连完了上的路由器,通过它可以转发数据;③标志;其中一个标志指明目的IP地址是网络地址还是主机地址,另一个标志指明下一站路由器是否为真正的下一站路由器,还是一个直接相连的接口;④为数据报的传输指定一个网络接口。
  • 当数据报来自某个网络接口时,IP首先检查目的IP地址是否为本机IP地址之一或者IP广播地址。如果确实是这样,数据报就被送到由IP首部协议字段所指定的协议模块进行处理。
  • 如果数据报的目的IP是其他的地址,并且IP层被设置为路由器的功能,那么就对数据报进行转发。
  • IP路由选择主要完成:①搜索路由表,寻找能与目的IP地址网络号和主机号完全匹配的表目,如果找到,则把表目发给指定的下一站路由器或者直接相连的网络接口;②搜索路由表,找到能与目的网络号匹配的表,如果找到,将表目发给该表目指定的下一站路由器或者直接相连的网络接口;③搜索路由表,寻找标为"默认"的表目;④如果以上步骤都没成功,那么该数据报就不能被传送。

IPv4地址 #

  • 因特网的地址分配策略被称为无类别域间路由选择(Classless Interdomain Routing CIDR)。
  • 通过IP可以区分网络号和主机号,通过子网掩码可以区分子网号和主机号。子网掩码中的1表示IP地址中的网络前缀,子网掩码中的0表示IP地址中的主机号。
  • 通过IP地址和子网掩码的与运算,可以计算出IP属于哪一个子网。
  • 广播地址255.255.255.255,当一个主机向目的地址为255.255.255.255发送数据时,该报文会发送给同一个网络中的所有主机。

DHCP #

  • 动态主机配置协议(dynamic host configuration ),此协议允许主机能自动被分配到一个IP地址;此外,通过DHCP,主机还能得到如第一跳路由器信息、DNS服务器地址等。
  • 对于一台新到达的主机,通过如下4个步骤获取IP地址。
    • DHCP服务器发现:客户端通过向UDP67端口发送DHCP发现报文(DHCP discover message),其中源IP地址为0.0.0.0,目标IP地址为255.255.255.255,链路层随后将该帧光波导该网络中的所有主机。
    • DHCP服务器响应:DHCP服务器向网络中广播DHCP提供报文(DHCP offer message),因为此时客户端没有IP地址,所以使用广播。因为子网中可能存在多个DHCP服务器,客户端可以进行选择。DHCP报文中包含推荐给客户端的IP地址,发现报文的事务ID,网络掩码及IP地址的租用期。
    • DHCP请求:客户端从一个或多个服务器中选一个,向选中的服务器发送DHCP请求报文(DHCP request message)。
    • DHCP ACK:服务器用DHCP ACK报文(DHCP ACK message)进行响应,证实请求的参数。

NAT #

  • 网络地址转换(Network Address Translation)能解决IPv4地址匮乏的问题,从广域网到NAT路由器的所有数据报都有相同的目的IP地址,NAT路由器维护一个NAT转换表(NAT translation table)表中包含了端口号及IP地址。
  • 如果一个用户的内网地址是172.20.20.2,请求的web服务地址为xiaoxiang.space,当发送该数据报到NAT主机前,源IP为172.20.20.2,源端口为30306(源端口不重要),当此数据报到NAT路由器时,路由器将修改源端口号为3456,源IP为外网IP,并在NAT转换表生成一条记录。当收到web服务的响应时,再根据NAT表中的记录还原IP和端口。
  • IDS是入侵检测设备,通常位于网络的边界,它不仅检查数据报的首部,还检查载荷。IDS具有一个特征数据库。

IPv6 #

  • IPv6地址为128位。数据报格式如下:
    • 版本:为6
    • 流量类型,和IPv4的TOS类似。
    • 流标签:
    • 有效载荷长度:载荷部分的字节数量。
    • 下一个首部:如UDP或TCP。
    • 源地址和目标地址:
  • IPv6中引入了任播地址,允许将数据报发给一组主机中的任意一个。
  • IPv6中的中间路由器不能对数据报进行分片。这种操作只能在源和目的端进行。如果路由器收到的数据报太大时,路由器会丢掉该数据报,并发送一个分组太大的ICMP差错报文。
  • IPV6去掉了首部检验和,在IPV4中,每经过一个路由器,IP头部的TTL就会减一,所以在每个路由器上都需要计算检验和。IPV6不需要了。
  • 将IPV4迁移到IPv6可以通过建隧道,将整个IPv6数据报放在IPV4数据包的有效载荷中,如图所示。

ICMP #

  • 因特网控制报文协议(Internet Control Messages Protocol)。被主机和路由器用来交流网络层之间的信息。最典型的用途是差错报告。
  • ICMP是承载在IP载荷中,当一个主机收到一个指明上层协议为ICMP的IP数据报时,它分解该数据报的内容给ICMP。
  • ICMP报文有一个类型字段和一个编码字段,介绍如下图:
  • ping程序会发送一个类型8编码0的报文到指定主机,目的主机会发回一个类型0编码0的ICMP回答。
  • windows上的traceroute程序也是ICMP实现,源主机向目的主机发送一系列的Ping数据报,第一个数据报的TTL为1,第二个数据报的TTL为2,以此类推。当第n个数据到到达第n个路由器时,这个数据报的TTL正好过期,此时路由器会丢弃该报文并向源主机发生用一个类型11编码0的ICMP报文。当路由器收到一个类型0编码0的报文时,就知道已经到达了目的主机,就可以停止发送数据报。

虚拟机

2022-08-03
其他

#virtualbox后台启动
C:\programs\VirtualBox\VBoxManage.exe startvm "centos7" --type headless
#vmware后台启动
C:\programs\vmware-workstation\vmrun.exe -T ws start "D:\programs-data\vmware-vm\centos7\centos7.vmx" nogui

Httpcomponent

2022-06-07
java

//httpClient建议复用
CloseableHttpClient httpClient = HttpClients.createDefault();
HttpPost httpPost = new HttpPost(path);
List<NameValuePair> nameValuePairs = new ArrayList<>();
nameValuePairs.add(new BasicNameValuePair(USERNAME, admin.getUsername());
nameValuePairs.add(new BasicNameValuePair(PASSWORD, admin.getPassword());
httpPost.setEntity(new UrlEncodedFormEntity(nameValuePairs));
try(CloseableHttpResponse response = httpClient.execute(httpPost)) {
    Header[] cookies = response.getHeaders(COOKIE_HTTP_HEADER);
    if (cookies.length > 0) {
        return cookies[0].getValue();
    }
}

传输层

2022-06-05
计算机网络

  • 传输层为运行在不同的主机上的进程提供了一种逻辑通信机制。

  • 发送方将应用递交的消息分成一个或多个segment,并向下传给网络层;接收方将接收到的segment组成消息,向上交给应用层。

  • 传输层协议分类:

    • 可靠、按序的交付服务(TCP),提供拥塞控制、流量控制和连接建立。
    • 不可靠的交付服务(UDP),基于尽力而为的网络层没有做可靠性方面的扩展。
  • 接收端进行多路复用,传输层依据头部信息将接收到的segment交给正确的socket;发送端进行多路复用,多个socket为每个数据块封装头部信息,生成segment,交给网络层。

  • 每个数据报携带源IP地址、目的IP地址,每个数据报携带一个传输层的端(Segment),每个段携带源端口和目的端口。主机收到segment后,传输层协议提取IP地址和端口信息,将segemnt导向相应的socket。

  • UDP的SOCKET用二元组标识(目的IP地址,目的端口号),来自不同源IP地址和端口号的IP数据报被导向同一个Socket,TCP的SOCKET用四元组标识(源地址,源端口,目的地址,目的端口)。

UDP #

  • UDP
  • UDP(USER DATAGRAM PROTOCOL)基于IP协议,简单的包装了下IP协议,提供了传输层的复用、分用,同时提供了简单的错误校验。
  • UDP段可能会丢失、错序。常用于流媒体应用。
  • UDP校验和提供了差错校验功能。

可靠数据传输 #

  • 可靠指的是不错、不丢失、不乱序。
  • 通过使用校验和来检查位错误来保证不错,同时使用ACK(acknowledgement)来显式的告诉发送方已经正确的接收分组。
  • 重传可用保证不丢失,对于未收到ACK的分组,进行重传,重传需要使用定时器,当超过一定时间未收到ACK则重传。
  • 简单的重传可能会导致重复分组或乱序,需要使用序列号,发送方给每个分组增加序列号,接收方通过序列号来确定分组顺序。

流水线机制 #

  • 简单的停-等协议效率很低,需要使用流水线机制来提高资源的利用率。
  • 例:1Gbps(R)的链路,15ms(RTT)的端到端的传播延迟,8Kb(L)分组。
  • 停等协议
  • 使用流水线机制
  • 流水线机制

滑动窗口协议 #

  • 包括GBN(go back N)和SR(selective repeat)。

GBN #

  • 分组的头部中包含K-bit的序列号。窗口尺寸为N,最多允许N个分组未确认。ACK(n)表示序列号n(包括n)之前的分组均已被正确接收。
  • 只为序列号最小的那个未收到ACK的分组设置计时器。
  • 当发生了超时事件,即序列号n的分组未收到对应的ack时,会重传序列号大于等于n的所有分组。
  • GBN发送方的FSM。base表示当前滑动窗口的起始位置,nextseqnum表示发送的分组的位置,下面的介绍是并行进行的。
    • 当序列号小于滑动窗口的右边界时,会持续发送分组,直到达到滑动窗口的右边界。此时会启动定时器并拒绝上层协议发来的数据。
    • 当定时器超时时,会重新发送滑动窗口左边界开始的窗口中的所有数据。
    • 当正确接收到ack时,滑动窗口会向右移动,同时重新启动定时器;当数据已经发完了时,会关闭定时器。
  • GBN-sender
  • GBN接收方的FSM
    • GBN只发送拥有最高序列号的、已被正确接收的分组的ACK,这就意味着序号为n的分组被正确接收时,序号小于n的所有分组都被成功接收。
    • 对于乱序到达的分组,接收方会直接丢弃,并且为最近按序接收的、序列号最大的分组重新发送一个ACK。
  • GBN-sender
  • 案例
    • 分组0和分组1均被正确接收,分组2由于丢失了。发送方发送过去的分组3、分组4、分组5,接收方均重发ACK(1),当一段事件后发送方一直未收到ACK(2),所以会重新发送分组2、分组3、分组4、分组5。
  • GBN-example

SR #

  • GBN单个分组的差错就能引起大量分组的重传。选择重传能仅让发送方重传个别它怀疑在接收方出错的分组,避免了不必要的重传。

  • SR接收方确认一个正确接收的分组而不管其是否按序,失序的分组将被缓存直到所有的丢失分组(序号更小的分组)都被收到为止。

  • SR-example

  • 序列号的空间大小必须大于等于窗口长度的两倍。

  • 例:当窗口大小为4,序号大小也为4,发送方连续发送4个分组,接收方收到4个分组后,返回4个ACK,窗口已经向右滑动了4个。此时假如4个ACK都丢了,发送方超时后重新发送4个分组,此时接收方把分组0、1、2、3当作新的分组,就会导致错误。

  • SR-4-4

  • 例:当窗口大小为4,序号大小为5,发送方连续发送4个分组,接收方收到4个分组后,返回4个ACK,窗口已经向右滑动了4个。此时假如4个ACK都丢了,发送方超时后重新发送4个分组,此时接收方把分组0、1、2当作新的分组,就会导致错误。

  • SR-4-5

  • 例:当窗口大小为4,序号大小为7,发送方连续发送4个分组,接收方收到4个分组后,返回4个ACK,窗口已经向右滑动了4个。此时假如4个ACK都丢了,发送方超时后重新发送4个分组,此时接收方把分组0当作新的分组,就会导致错误。

  • SR-4-7

TCP #

  • 一个应用进程向另一个应用进程发送数据之前,会现在两个进程之间建立一条逻辑链路。当一端通过套接字传递数据,TCP将这些数据引导到该连接的发送缓存中,发送缓存时三次握手期间设置的缓存之一。接下来TCP会不时从发送缓存中取出一块数据,并将数据传送到网络层。
  • TCP从缓存中取出并放入段中的数据大小受限于MSS(maximum segment size,即最大报文段长度)。MSS通常根据MTU(maximum Transmission Unit,最大传输单元)来设置。通常MTU为1500字节,TCP首部一般20字节,IP首部一般20字节,所以MSS是一般情况为1440字节。

TCP报文段结构 #

  • 32位的序号和确认号用来实现可靠数据传输。
  • 16位的接受窗口字段用来进行流量控制。
  • 4位的首部长度用来指示以32bit的字为单位的TCP首部的长度。
  • 可选和变长的选项字段,在协商MSS或调节窗口因子时使用。
  • 6位的标志字段。ACK用于指示确认号的值是有效的,即该报文段包含一个对已被接收报文段的确认。RST、SYN、FIN用于连接的建立和拆除。

序号和确认号 #

  • 一个报文段的序号是报文段首字节的编号,TCP连接双方都会随机地选择初始序号。例:假如MSS为1000,一个数据流的大小为5000字节,初始序号为234。则第一个报文段的序号为234,第二个报文段的序号为1234,第三个报文段的序号为2234。
  • 确认号是接收方期望从发送方接收到的下一个字节的序号。TCP是累计确认的,如果收到了确认号为2234的报文段,则说明2234(不包含2234)之前的报文段都被成功接收。

往返时间的估计和超时 #

  • TCP采用超时重传机制来处理报文段的丢失问题。超时时间间隔必须大于连接的往返时间(RTT),否则会造成丢包。
  • SampleRTT是某报文段从发出到对该报文段的确认被收到之间的时间量。大多数TCP的实现是在某个时刻为一个已发送但未被确认的报文段估计SampleRTT,TCP不会对已被重传的报文段计算sampleRTT。
  • 由于sampleRTT可能会有大的波动,TCP会维持一个EstimatedRTT,一旦获取一个新的sampleRTT,TCP会按照如下公式更新EstimatedRTT。α的推荐值为0.125。
EstimatedRTT = ( 1 - α ) * EstimateRTT + α * SampleRTT
  • DevRTT用来计算sampleRTT偏离EstimatedRTT的程度, β的推荐值为0.25。
DevRTT = ( 1 - β ) * DevRTT + β * | SampleRTT - EstimatedRTT |
  • 超时时间TimeoutInterval的计算如下,推荐初始的TimeoutInterval为1秒。当收到报文段并更新EstimatedRTT时,就会更新TimeoutInterval。
TimeoutInterval = EstimatedRTT + 4 * DevRTT
  • 当出现超时后,会直接把TimeoutInterval加倍。例:假设当前的过期时间为0.75,当定时器超时后,TCP会重传报文段,并把过期时间设置为1.5s,当再次过期时,TCP会重传报文段,并将过期时间设置为3s。

可靠数据传输 #

  • 快速重传是指如果TCP发送方接收到对相同数据的3个冗余ACK,即收到了一个正常的ACK(n)和三个冗余的ACK(n)时,TCP会重传序号为n的段,即使当前未超时。
  • TCP采用累积确认,当受到ACK(n)则说明n之前的字节(不包括n)都已成功收到,存在如下的三种情况。

流量控制 #

  • 一台TCP连接的每一侧主机都为该连接设置了接受缓存,为了防止缓存溢出,TCP提供了流量控制服务(flow-control service)。

  • TCP的发送方也可能因为IP网络的拥塞而遏制,这种控制方式为拥塞控制(congestion service)。

  • TCP通过让发送方维护一个叫接收窗口(Receive Window)的变量来提供流量控制,该字段是接收方的剩余缓存空间大小。因为TCP是全双工的,连接两端都会维护接收窗口。

  • 假设主机A向主机B发送一个文件,主机B的接收缓存大小为RcvBuffer,LastByteRead用来表示主机B的应用程序从缓存中读到的最后一个字节编号,LastByteRcvd用来表示主机A发送到主机B且放入到接收缓存的最后一个字节的编号。

  • 接收窗口rwnd的大小的计算如下,该字段是动态变化的,最开始rwnd等于RcvBuffer。

#接收窗口大小 = 接收缓存总大小 - 已接收但是未读的数据
# 1. 如果发的数据快,但是读数据慢,接收方来不及处理时,导致接收窗口变小
rwnd = RcvBuffer - ( LastByteRecvd - LastByteRead )
  • 主机B通过把rwnd放到它发送给主机A报文段的接收窗口字段中,通知A该连接中还存在多少的可用缓存。主机A会跟踪两个变量,LastByteSent用来表示最后发送的一个字节编号,LastByteAcked用来表示最后一个确认的字节编号,通过如下关系来保证发送的数据不会造成缓存溢出。
#接收窗口大小 >= 未确认的数据
# 1. 当接收窗口变小后,发送方已发送但未确认的这部分数据减少
# 2. 当接收窗口大小为0时,发送方停止向接收方发送数据,但是还是会发送特殊的段,以便获取rwnd。
LastByteSent - LastByteAcked ≤ rwnd
  • 为了避免主机B的接收缓存已满,然后发送给主机A rwnd=0,此时主机A不会在给主机B发送数据的情况,TCP要求当主机B的缓存已满时,主机A继续发送只有一个字节数据的报文段。这些报文段会被接收方确认,等主机B的缓存空间不为0时,会发送给主机A非0的rwnd值。

TCP连接管理 #

  • 三次握手

    1. 客户端会像服务端发送一个特殊的报文段,该报文段不携带任何数据,SYN标志位被置为1,并且会随机选择一个序号client_isn,发送给服务器。该报文段被称为SYN报文段。
    2. 当该服务端收到SYN报文段后,为TCP连接分配缓存和变量,并向客户端发送报文段,该报文段SYN标志位置为1,并随即生成一个序号server_isn,同时ACK标志位置为1,确认号填client_isn+1,改报文段不包含任何数据。该报文段被称为SYNACK报文段。
    3. 客户端收到SYNACK后,为TCP连接分配缓存和变量,向服务端发送报文段,该报文段可以携带数据,SYN标志位被置为0(因为连接已建立)。同时ACK标志位置为1,确认号填server_isn+1。
  • TCP连接关闭

  1. 当客户端发起关闭连接时(服务端也可以发起),会向服务端发送一个特殊报文段,该报文段的FIN报文段被置为1,同时生成一个seq序号y,发给服务端。其实此时ACK标志位也会被置为1,用来确认上一次发来的数据。
  2. 服务端收到后,会将ACK标志位置为1,ack填y+1。
  3. 服务端会重复1~2步。
  • 一次HTTP请求的连接过程,第三次握手时就已经开始带上数据了。
  • 洪范攻击(SYN flood attack)指攻击者发送大量的TCP SYN段,却不完成第三次握手,由于服务端在第二次握手就开始分配资源,导致服务端资源被消耗殆尽。一种有效的防御机制SYN cookies能解决这个问题,】工作方式如下:
    • 当服务端收到一个SYN段时,它不会开启一个半开的连接。它会根据源和目标的IP和端口以及秘密数通过散列函数来生成一个初始的TCP序号,这个序号被称为"cookie",服务端将这个特殊的SYNACK段发给客户端。
    • 当服务端收到一个ACK时,通过散列函数来计算一个值,如果该值加1等于ACK,则说明改ACK是对之前的某个SYNACK的确认,服务端会生成一个具有套接字的全开链接。
    • 如果客户端没有返回一个ACK,对服务器也没有影响。
  • 当一台服务器接收到了一个TCP报文段,该报文段的目的端口或源IP与服务器上的套接字都不匹配时,服务器会向源发送一个特殊的重置段,该段的RST标志位被置为1。当一台主机接收到了一个UDP分组,它的目的端口与主机上的套接字都不符合,主机会发送一个ICMP数据报。

TCP拥塞控制 #

  • 运行在发送方的TCP拥塞控制机制跟踪一个额外的变量拥塞窗口cwnd(congestion window),它对TCP发送方能向网络中发送的流量进行了限制,即:
LastByteSent - LastByteAcked ≤ min { rwnd, cwnd }
  • TCP拥塞控制算法:1. 慢启动;2. 拥塞避免;3. 快速恢复。

慢启动 #

  1. 当TCP连接开始时,cwnd通常设置为MSS(存疑),这使得初始的发送速率约为MSS/RTT;
  2. TCP向网络中发送第一个报文段并等待一个确认,当确认到达时,将cwnd增加一个MSS;并发送出两个段,当着两个段被确认时,每个确认都将使cwnd增加一个MSS,这使得现在cwnd变成了4个MSS。总结:每经过一个RTT,cwnd = cwnd * 2
  • 拥塞窗口不会无限增大:

    • 如果发生了丢包事件,TCP发送方将cwnd设置为1并重新开始慢启动过程,并设置ssthresh(慢启动阈值)的值为cwnd/2,当达到ssthresh后,cwnd线性增长;
    • 如果检测到3个冗余ACK(连续收到4个相同的ACK,重复的ACK表示网络有能力来传输段)时,cwnd减半,并开始线性增长。(TCP RENO
    • 如果检测到3个冗余ACK,将cwnd设置为1(TCP Tahoe

抓包

2022-05-25
linux

wireshark #

eq ==
ne !=
gt >
lt <
ge >=
le <=
# 指定来源ip、目的端口和协议
ip.src eq 10.2.4.50 and http and tcp.dstport eq 40010
tcp.port in {80, 443, 8080}
http.request.method in {"HEAD", "GET"}
#支持使用range
ip.addr in {10.0.0.5 .. 10.0.0.9, 192.168.1.1 .. 192.168.1.9}
#支持子网的形式
ip.addr == 129.111.0.0/16

目录映射

2022-05-19
nginx

server {
    listen 20000;
    location / {
        root /opt/share;
        #开启自动映射目录
        autoindex on;
        charset utf-8;
        #时间设置为本地时间
        autoindex_localtime on;
        #通过字节精确表示大小
        autoindex_exact_size on;
    }
}

应用层

2022-05-05
计算机网络, c语言

HTTP #

  • 网页包含多个对象,如HTML文件、JPEG图片、视频文件、动态脚本等,基本HTML文件包含对其他对象引用的链接。通过URL可以进行对象的寻址。
  • HTTP协议流程:
    1. 服务器在80端口等待客户的请求
    2. 浏览器发起到服务器的TCP连接(创建套接字Socket)
    3. 浏览器与Web服务器交换HTTP消息
    4. 关闭TCP连接
  • HTTP是无状态的协议,即服务器不维护任何有关客户端过去所发请求的信息。

HTTP连接 #

  • HTTP包含非持久性连接和持久性连接
    • 非持久性连接指的是每个TCP连接最多允许传输一个对象,HTTP1.0使用非持久性连接。
    • 持久性连接指每个TCP连接可以传输多个对象,HTTP1.1默认使用持久性连接。

HTTP消息格式 #

  • HTTP有两类消息,请求消息(request)和响应消息(response)。
  • HTTP请求消息的格式如下:
  • HTTP请求格式
  • HTTP响应消息的格式如下:
  • HTTP请求格式

Web缓存 #

  • 如果浏览器缓存过数据,当下次发送相同请求时,浏览器向服务器发送HTTP请求,并带上If-modified-since: <date>
  • 如果对象未改变,则返回304 Not Modified,不反会对象,表示对象未被修改。
  • 如果对象发生改变,服务器会返回对象。

DNS #

  • DNS的是分布式数据库。提供了域名向IP地址的翻译、主机别名等功能。
  • 一般来说是本地域名解析服务器代替进行域名解析的,当主机进行DNS查询时,查询会被发送到本地域名服务器,当本地域名服务器无法解析域名时,就会访问根域名服务器。全球共13个根域名服务器。
  • 顶级域名服务器(TLD,top-level domain),负责com、org、net等顶级域名和国家顶级域名,如cn、uk等。
  • 权威域名服务器是组织的域名解析服务器,提供组织内部服务器的解析服务。
  • cis.poly.edu想获取gaia.cs.umass.edu的IP地址时,迭代查询流程如下
  • 迭代查询流程
  • 递归查询的流程如下(将域名解析的任务交给所联系的服务器)
  • 递归查询流程
  • 只要域名解析服务器获得域名时,就会缓存这一映射,一段时间后缓存条目才会失效。

DNS记录 #

  • 资源记录格式为(name, value, type, ttl),类型如下
  • type=A,Name为主机域名,Value为IP地址
  • type=NS,Name为域(如edu.cn),value为该域权威域名解析服务器的主机域名。
  • type=CNAME,name为某一真实域名的别名,value为真实域名
  • type=MX,value是与name对应的邮件服务器。

DNS协议消息格式 #

  • DNS查询(query)和回复(reply消息)的格式相同。
  • 消息头部
    • Identification:16为查询编号,回复使用相同的编号。
    • flags表示查询或回复、期望递归、递归可用、权威回答。
  • DNS查询流程

socket #

  • 对外通过IP地址+端口号表示通信端点。
  • 操作系统通过套接字描述符(socket descriptor)来管理套接字。
  • socket类似于文件,当应用进程创建套接字时,操作系统分配一个数据结构存储该套接字相关信息。
  • socket描述符表

地址结构 #

  • 使用TCP/IP协议簇的网络应用程序声明端点地址变量时,使用结构socketaddr_in
struct sockaddr_in
{
  u_char sin_len; /*地址长度 */
  u_char sin_family; /*地址族(TCP/IP:AF_INET) */
  u_short sin_port; /*端口号 */
  struct in_addr sin_addr; /*IP地址 */
  char sin_zero[8]; /*未用(置0) */
}

socket api函数 #

socket函数 #

  • sd = socket(protofamily,type,proto); 创建套接字并返回套接字描述符。
  • 第一个参数指定协议族:protofamily=PF_INET(TCP/IP)
  • 第二个参数指定套接字类型:SOCK_STREAM(TCP), SOCK_DGRAM(UDP), SOCK_RAW(面向网络层)
  • 第三个参数指定协议号:0为默认
struct protoent *p;
p=getprotobyname("tcp");
SOCKET sd=socket(PF_INET,SOCKET_STREAM,p->p_proto);

close #

  • int close(SOCKET sd) 关闭一个描述符为sd的套接字
  • 如果多个进程共享一个套接字,调用close将套接字引用计数减1,减至0才关闭。
  • 一个进程中的多线程对一个套接字的使用无计数。
  • 返回值 0:成功,SOCKET_ERROR:失败。

bind #

  • int bind(sd,localaddr,addrlen); 绑定套接字的本地端点地址
  • 客户端一般不必调用bind函数,一般由服务端调用。
  • 一台机器可能由多个网卡,可用使用地址通配符INADDR_ANY来绑定。

listen #

  • int listen(sd,queuesize);置服务器端的流套接字处理处于监听状态。
  • 仅服务端调用,仅用于面向连接的流套接字。
  • queuesize表示连接请求的队列大小。
  • 返回值 0:成功,SOCKET_ERROR:失败。

connect #

  • connect(sd,saddr,saddrlen) 客户端调用connect函数来使客户端套接字(sd)与特定计算机的特定端口(saddr)的套接字服务进行连接。
  • 仅用于客户端,可用于TCP客户端也可以用于UDP客户端。

accept #

  • newsock = accept(sd,caddr,caddrlen);服务程序调用accept函数从处于监听状态的流套接字sd的客户端连接请求队列中取出排在最前的一个客户请求,并且创建一个新的套接字来与客户套接字创建连接通道。
  • 仅用于TCP套接字,仅用于服务器。
  • 服务器会利用新创建的套接字(newsock)与客户端通信。

send #

  • send(sd,*buf,len,flags);
  • sendto(sd,*buf,len,flags,destaddr,addrlen);
  • send:发送数据(用于TCP套接字或连接模式(调用了connect函数)的客户端UDP套接字)
  • sendto函数用于UDP服务器端套接字与未调用connect函数的UDP客户端套接字发送数据

recv #

  • recv(sd,buffer,len,flags);
  • recvfrom(sd,buf,len,flags,senderaddr,saddrlen);
  • recv函数从TCP连接的另一端接收数据,或者从调用了connect函数的UDP客户端套接接收服务器发来的数据
  • recvfrom函数用于从UDP服务器端套接字与未调用connect函数的UDP客户端套接字接收对端数据

setsockopt,getsockopt #

  • int setsockopt(int sd, int level, int optname, *optval, int optlen);
  • int setsockopt(int sd, int level, int optname, *optval, int optlen);
  • setsockopt()函数用来设置套接字sd的选项参数
  • getsockopt()函数用于获取任意类型、任意状态套接口的选项当前值,并把结果存入optval

网络字节序 #

  • 网络字节序采用大端排序方式(低位低地址,高位高地址)
  • 某些Socket API函数的参数需要存储为网络字节顺序(如IP地址、端口号等)
  • 转换函数
    • htons: 本地字节顺序→网络字节顺序(16bits)
    • ntohs: 网络字节顺序→本地字节顺序(16bits)
    • htonl: 本地字节顺序→网络字节顺序(32bits)
    • ntohl: 网络字节顺序→本地字节顺序(32bits)

解析服务器IP地址 #

  • 客户端可能使用域名或IP地址标识服务器,IP协议需要使用32为二进制IP地址,需要将函数名或IP地址转换为32为IP地址。
  • inet_addr可用实现点分十进制IP地址到32位IP地址转换。
  • gethostbyname实现域名到32位IP地址转换。会返回一个指向结构hostent的指针。
struct hostent {
 char FAR* h_name; /*official host name */
 char FAR* FAR* h_aliases; /*other aliases */
 short h_addrtype; /*address type */
 short h_lengty; /*address length */
 char FAR* FAR* h_addr_list; /*list of address */
};
#define h_addr h_addr_list[0] 

解析服务器端口号 #

  • 客户端可能使用服务名(如HTTP)标识服务器端口,需要将服务名转换为熟知端口号
  • getservbyname会返回一个指向结构servent的指针。
struct servent {
 char FAR* s_name; /*official service name */
 char FAR* FAR* s_aliases; /*other aliases */
 short s_port; /*port for this service */
 char FAR* s_proto; /*protocol to use */
}; 

解析协议号 #

  • 客户端可能使用协议名来指定协议,需要将协议名转换为协议号
  • 函数getprotobyname实现协议名到协议号的转换。会返回一个protoent的指针。
struct protoent {
 char FAR* p_name; /*official protocol name */
 char FAR* FAR* p_aliases; /*list of aliases allowed */
 short p_proto; /*official protocol number*/
 }; 

TCP客户端软件流程 #

  1. 确定服务器IP地址和端口号
  2. 创建套接字
  3. 分配本地端点地址(可选)
  4. 连接服务器(套接字)
  5. 遵循应用层协议进行通信
  6. 关闭/释放连接

UDP客户端软件流程 #

  1. 确定服务器IP地址与端口号
  2. 创建套接字
  3. 分配本地端点地址(IP地址+端口号)
  4. 指定服务器端点地址,构造UDP数据报
  5. 遵循应用层协议进行通信
  6. 关闭/释放套接字