以下所有内容来自于《Wireshark网络分析就这么简单》(林沛满 著)
因为B根据自己的子网掩码,计算出A属于不同子网,跨子网通信需要默认网关的转发。而要和默认网关通信,就需要获得其MAC地址。
因为在执行ARP回复时并不考虑子网,即使ARP请求来自其他子网IP也照样回复。
因为 MAC 地址的前 3 个字节表示厂商,这里表示Vmware公司。
假如自身有一个IP和对方在同一子网,就从这个IP直接发包给对方;假如没有一个IP和对方同子网,就走默认网关。
这说明A上存在一项符合与B同网段的路由,促使A通过eth1直接与B通信。由于不同子网所配的 VLAN 也不同,所以这些 ARP 请求根本到达不了 B。
两个网络之间存在 NAT(Network Address Translation),当客户端发出的请求经过NAT设备时,Source IP被改掉了,所以原有的放行策略可能就会失效。
(1)一般能抓到的每个包(称为“帧”更准确)的最大长度为1514字节,启用了 Jumbo Frame(巨型帧)之后可达 9000 字节以上,而大多数时候我们只需要 IP 头或者 TCP 头就足够分析了。
(2)一般设个偏大的数字:80字节,也就是说每个包只抓前80字节。这样TCP层、网络层和数据链路层的信息都可以包括在内
(3)用tcpdump命令抓包时可以用“-s”参数达到相同效果。
比如以下命令只抓eth0上每个包的前80字节,并把结果存到/tmp/tcpdump.cap文件中。[root@server_1 /]# tcpdump -i eth0 -s 80 -w /tmp/tcpdump.cap
抓的包除了要小,最好还能为每步操作打上标记。
(1)ping-n1-l1
(2)操作步骤1
(3)ping-n1-l2
(4)操作步骤2
查看包最底下的“Data(1byte)”,byte的数目表示是第几步
(1) Wireshark 的时间调成跟服务器一样的格式:单击 Wireshark 的 View–>Time Display Format–>Date and Time of Day,就可以实现此设置;
(2)如果在其他时区的服务器上抓包,然后下载到自己的电脑上分析,最好把自己电脑的时区设成跟抓包的服务器一样。这样,Wireshark显示的时间才能匹配服务器上日志的时间。
(1) 如果已知某个协议发生问题,可以用协议名称过滤一下。用协议过滤时务必考虑到协议间的依赖性。(比如 NFS 共享挂载失败,问题可能发生在挂载时所用的mount协议,也可能发生在mount之前的portmap协议。这种情况下就需要用“portmap||mount”来过滤了。)
(2) IP 地址加 port 号是最常用的过滤方式。除了手工输入 ip.addreq
(3)右键单击Wireshark上感兴趣的内容,然后选择Prepare a Filter–>Selected,就会在Filter框中自动生成过滤表达式。在有复杂需求的时候,还可以选择And、Or等选项来生成一个组合的过滤表达式。(假如右键单击之后选择的不是Prepare a Filter,而是Apply as Filter–>Selected,则该过滤表达式生成之后还会自动执行。)
(4)在Filter中输入“error”进行搜索。很多应用层的错误都可以靠这个方法锁定问题包。
(1)单击Wireshark的Analyze–>Expert Info Composite,就可以在不同标签下看到不同级别的提示信息。比如重传的统计、连接的建立和重置统计,等等。在分析网络性能和连接问题时,我们经常需要借助这个功能。(从Error和Warning里都没有看到报错,这说明网络没有问题。假如有重传、乱序之类的现象,应该能在这个窗口里看到。)
(2)单击Statistics–>Service Response Time,再选定协议名称,可以得到响应时间的统计表。我们在衡量服务器性能时经常需要此统计结果。
(3)单击Statistics–>TCP Stream Graph,可以生成几类统计图。
(4)单击Statistics–>Summary,可以看到一些统计信息,比如平均流量(Avg.MBit/sec)等,这有助于我们推测负载状况。比如网络包才 1.594Mbit/s,说明流量低得很。
Wireshark的命令行版,功能更强大。输出的分析文本大多可以直接写入分析报告中,而 Wireshark 生成不了这样的报告。
TCP是基于连接的,而UDP不需要连接。它们各自支持一些应用层协议,但也有些协议是两者都支持的,比如DNS。
网络对包的大小是有限制的,其最大值称为MTU,即“最大传输单元”。
大多数网络的MTU是1500字节,但也有些网络启用了巨帧(Jumbo Frame),能达到9000字节。
一个8192字节的包进入巨帧网络不会有问题,但到了1500字节的网络中就会被丢弃或者切分。
被丢弃意味着传输彻底失败,因为重传的包还会再一次被丢弃。
而被切分则意味着传输效率降低。
在TCP连接建立(三次握手)时,双方都会把自己的MSS(Maximum Segment Size)告诉对方。MSS加上TCP头和IP头的长度,就得到MTU了。
发包的大小是由MTU较小的一方决定的。
点开TCP层前的“+”号,我们可以看到Seq号和Ack号等一系列信息,它们用于网络包的排序、重传、流量控制等。
(1)Seq:表示该数据段的序。TCP提供有序的传输,所以每个数据段都要标上一个序号。当接收方收到乱序的包时,有了这个序号就可以重新排序了。一个Seq号的大小是根据上一个数据段的Seq号和长度相加而来的。
(2)Len:该数据段的长度,注意这个长度不包括TCP头。
(3)Ack:确认号,接收方向发送方确认已经收到了哪些字节。 比如甲发送了“Seq:x Len:y”的数据段给乙,那乙回复的确认号就是x+y,这意味着它收到了x+y之前的所有字节。(TCP的确认是可以累积的。)
(1)SYN:携带这个标志的包表示正在发起连接请求。因为连接是双向的,所以建立连接时,双方都要发一个SYN。
(2)FIN:携带这个标志的包表示正在请求终止连接。因为连接是双向的,所以彻底关闭一个连接时,双方都要发一个FIN。
(3)RST:用于重置一个混乱的连接,或者拒绝一个无效的请求。
事实上,握手时Seq号并不是从0开始的。我们之所以在 Wireshark 上看到 Seq=0,是因为 Wireshark 启用了 Relative Sequence Number。如果你想关闭这个功能,可以在Edit–>Preferences–>protocols–>TCP里设置。
工作中如果碰到断开连接的问题,可以使用 netstat 命令来排查。
这其实就是TCP处理交互式场景的策略之一。该策略的原理是这样的:如果收到一个包之后暂时没什么数据要发给对方,那就延迟一段时间(在Windows上默认为200毫秒)再确认。假如在这段时间里恰好有数据要发送,那确认信息和数据就可以在一个包里发出去了。
原理:在发出去的数据还没有被确认之前,假如又有小数据生成,那就把小数据收集起来,凑满一个MSS或者等收到确认后再发送。
现实中也存在一些限制:接收方的缓存(接收窗口)可能一下子接受不了这么多数据;网络的带宽也不一定足够大,一口气发太多会导致丢包事故。
所以,发送方要知道接收方的接收窗口和网络这两个限制因素中哪一个更严格,然后在其限制范围内尽可能多发包。这个一口气能发送的数据量就是传说中的TCP发送窗口。
(1)TCP 超时重传的间隔时间太长,设置一个较小的时间可以减少重传对性能的影响。
比如网络频繁拥塞,拥塞点大多在32KB以上。如果把发送窗口限制在32KB,就可以避免触碰拥塞点。
(2)真实环境中,发送窗口常常可以达到数十个MSS。
(1)每个包的TCP层都含有window size(也就是win=)的信息,这不是发送窗口,而是在向对方声明自己的接收窗口。
(2)假如接收方处理数据的速度跟不上接收数据的速度,缓存就会被占满,从而导致接收窗口为0。
(3)发送窗口决定了一口气能发多少字节,而MSS决定了这些字节要分多少个包发完。
(1)Window Scale的作用是向对方声明一个 Shift count,我们把它作为2的指数,再乘以TCP头中定义的接收窗口,就得到真正的TCP接收窗口了。
(2)要注意Wireshark是根据Shift count计算出这个结果的,如果抓包时没有抓到三次握手,Wireshark就不知道该如何计算,所以我们有时候会很莫名地看到一些极小的接收窗口值。还有些时候是防火墙识别不了Window Scale,因此对方无法获得Shift count,最终导致严重的性能问题。
(1)Westwood算法(Saverio先生提出)
根据接收方回应的Ack来推算出有多少包已经被送达接收方,从而更精确地估算发生拥塞时的带宽,最后再依据带宽来确定新的拥塞窗口。
(2)FlightSize
引进FlightSize只是为了得到一个安全的临界窗口值,而不是像Westwood+一样追求比较理想的窗口。
它的理论依据也并不复杂:当网络状况良好时,数据包的RTT(往返时间)比较稳定,这时候就可以增大拥塞窗口;当网络开始繁忙时,数据包开始排队,RTT就会变大,这时候就需要减小拥塞窗口了
这个策略就是在发送方维护一个虚拟的拥塞窗口,并利用各种算法使它尽可能接近真实的拥塞点。网络对发送窗口的限制,就是通过拥塞窗口实现的。
从发出原始包到重传该包的这段时间称为RTO。
(1)单击 Analyze–>Expert Info Composite菜单,就能在Notes标签看到它们了。点开+号还能看到具体是哪些包发生了重传。
(2)重传对性能的影响是极大的,即便是0.5%的比例也会使性能大幅度下降。
超时重传对传输性能有严重影响。
原因之一是在RTO阶段不能传数据,相当于浪费了一段时间;
原因之二是拥塞窗口的急剧减小,相当于接下来传得慢多了。
后续的包到达接收方时,接收方会发现其Seq号比期望的大,所以它每收到一个包就Ack一次期望的Seq号,以此提醒发送方重传。
当发送方收到3个或以上重复确认(Dup Ack)时,就意识到相应的包已经丢了,从而立即重传它。这个过程称为快速重传。之所以称为快速,是因为它不像超时重传一样需要等待一段时间。
由于一般乱序的距离不会相差太大,比如2号包也许会跑到4号包后面,但不太可能跑到6号包后面,所以限定成3个或以上可以在很大程度上避免因乱序而触发快速重传。
临界窗口值应该设为发生拥塞时还没被确认的数据量的1/2(但不能小于2个MSS)。然后将拥塞窗口设置为临界窗口值加3个MSS,继续保留在拥塞避免阶段。这个过程称为快速恢复。
(1)没有拥塞时,发送窗口越大,性能越好。所以在带宽没有限制的条件下,应该尽量增大接收窗口,比如启用Scale Option。
(2)如果经常发生拥塞,那限制发送窗口反而能提高性能,因为即便万分之一的重传对性能的影响都很大。
(3)超时重传对性能影响最大,因为它有一段时间(RTO)没有传输任何数据,而且拥塞窗口会被设成1个MSS,所以要尽量避免超时重传。
(4)快速重传对性能影响小一些,因为它没有等待时间,而且拥塞窗口减小的幅度没那么大。
(5)SACK和NewReno有利于提高重传效率,提高传输性能。(是否启用SACK是在TCP三次握手时协商决定的。只要双方中有一方没有发“SACK_PERM=1”,那该连接建立之后就不会用到 SACK。)
(6)丢包对极小文件的影响比大文件严重。因为读写一个小文件需要的包数很少,所以丢包时往往凑不满3个Dup Ack,只能等待超时重传了。而大文件有较大可能触发快速重传。
(1)UDP协议头中,只有端口号、包长度和校验码等少量信息,总共就8个字节。
(2)UDP不像TCP一样在乎双方MTU的大小。它拿到应用层的数据之后,直接打上UDP头就交给下一层了。
那么超过MTU的时候怎么办?
在这种情况下,发送方的网络层负责分片,接收方收到分片后再组装起来,这个过程会消耗资源,降低性能。
(3)UDP 没有重传机制,所以丢包由应用层来处理。
接收方之所以知道什么时候该把分片组装起来,是因为每个包里都有“More fragments”的flag。1表示后续还有分片,0 则表示这是最后一个分片,可以组装了。如果黑客持续快速地发送flag为1的UDP包,接收方一直无法把这些包组装起来,就有可能耗尽内存。
(1)NFS 服务器提供了/code 和/document两个共享目录,分别被挂载到多台客户端的本地目录上。当用户在这些本地目录读写文件时,实际是不知不觉地在NFS服务器上读写。
(2)看到portmap请求没有得到回复,就可以考虑防火墙对111端口的拦截;如果发现mount请求被服务器拒绝了,就应该检查该共享目录的访问控制。
(3)NFS对客户端的访问控制是通过IP地址实现的。创建共享目录时可以指定哪些IP允许读写,哪些IP只允许读,还有哪些IP连挂载都不允许
(4)NFS协议是只认UID不认用户名的,建议用户名和UID的关系在每台客户端上都保持一致。
(5)应用层:由于NFS是基于RPC的协议,所以Wireshark把它分成NFS和RPC两行来显示。
(1)假如mount时使用了sync参数,客户端会先发送一个WRITE Call,等收到Reply后再发下一个Call,也就是说WRITE Call和WRITE Reply是交替出现的。
除此之外,还有什么办法在包里看出一个写操作是async还是sync呢?
答案就是每个WRITE Call上的“UNSTABLE”和“FILE_SYNC”标志,前者表示async,后者表示sync。
(2)每个 WRITE Call写多少数据也是影响写性能的重要因素,我们可以在mount时用wsize参数来指定每次应该写多少。不过在有些客户端上启用sync参数之后,无论wsize定义成多少都会被强制为 4KB,从而导致写性能非常差。
那为什么还有人用 sync 方式呢?
答案是有些特殊的应用要求服务器收到sync的写请求之后,一定要等到存盘才能回复 WRITE Reply,sync 操作正符合了这个需求。由此我们也可以推出COMMIT对于sync写操作是没有必要的。
(3)从Write Call里的FILE_SYNC可以知道,虽然在mount时并没有指定sync参数,但是noac把写操作强制变成sync方式了,性能自然也会下降。
(1)Windows上一般使用什么共享协议呢?它就是微软维护的SMB协议,也叫Common Internet File System(CIFS)。
(2)CIFS协议有三个版本:SMB、SMB2和SMB3,目前SMB和SMB2比较普遍。
(3)CIFS 只能基于 TCP。
(4)CIFS服务器上的端口号为445。
(1)第一个CIFS操作是Negotiate(协商)。
(2)协商好版本之后,就可以建立CIFS Session了。
Session Setup的主要任务是身份验证,常用的方式有Kerberos和NTLM。
(3)点开这两个Tree Connect包,最有价值的信息当属服务器返回的Tree ID。从此之后客户端就能利用这个ID去访问/dest共享的子目录和子文件。
(4)Create是CIFS中非常重要的一个操作。无论是新建文件、打开目录,还是读写文件,都需要Create。
(5)CIFS采用了Oplock(机会锁)来解决这个问题。Oplock有Exclusive、Batch 和 Level2三种形式。Exclusive允许读写缓存,Batch 允许所有操作的缓存,而 Level 2 只允许读缓存。
(1)在 SMB3 的复制过程中,我们只是在网络上传输了一些指令,而文件内容并没有出现在网络上,因为复制数据完全由服务器自己完成了。
(2)SMB3的另一个破天荒改进是在CIFS层实现了负载均衡。与其他CIFS版本不同,一个SMB3Session可以基于多个TCP连接。
用 D N S 解析成 IP 地址,再通过 IP 地址找到服务器。
比如打开公司电脑,用域账号登录操作系统,就是依靠DNS找到Domain Controller来验证身份。
(1)递归:客户端只发一次请求,要求对方给出最终结果。
(2)迭代:客户端发出一次请求,对方如果没有授权回答,它就会返回一个能解答这个查询的其它名称服务器列表,客户端会再向返回的列表中发出请求,直到找到最终负责所查域名的名称服务器,从它得到最终结果。
用dig命令加上“+trace”参数可以强迫客户端采用迭代查询。
PTR记录:与A记录的功能相反,它能从IP地址解析到域名。
SRV记录:Windows的域管理员要特别关心SRV记录,因为它指向域里的资源。
CNAME 记录:又称为 Alias 记录,就是别名的意思。
这个特性可以广泛应用于负载均衡。比如某个网站有10台Web服务器,管理员就可以在DNS里创建10个同名记录指向这些服务器的IP。由于不同客户端查到的结果顺序不同,而且一般会选用结果中的第一个IP,所以大量客户端就会被均衡地分配到10台Web服务器上。
(1)DNS服务器被恶意修改指向钓鱼网站是很危险的事,即便是配了正规的DNS服务器,也是有可能中招的。比如正规的DNS服务器遭遇缓冲投毒之后,也会变得不可信;
(2)DNS 除了能用来欺骗,还能当做攻击性武器。著名的 DNS 放大攻击就很让人头疼。比如执行“dig ANY isc.org"时,DNS会回复一个很大的包,在这个包里伪造一个想要攻击的源地址,那该地址就会莫名收到 DNS服务器3111字节的回复。利用这个放大效应,黑客只要控制少量电脑就能把一个大网站拖垮了。
(1)FTP常被用来传播文件,尤其是免费软件;另一个广泛应用是采集日志,我们可以让服务器发生故障之后,自动通过FTP把日志传回厂商。
(2)FTP服务器的控制端口21。
(3)FTP 是用明文传输的
客户端连接FTP服务器的21端口仅仅是为了传输控制信息,我们称之为“控制连接”。
当需要传输数据时,就重新建立一个 TCP 连接,我们称之为“数据连接”。
不但在下载文件时如此,就连执行ls命令来列举文件时,也需要新建一个数据连接。
(1)如果你为FTP配置过防火墙,还会发现这种方式带来了一个更加严重的问题—由于数据连接的三次握手是由服务器端主动发起的(我们称之为主动模式),如果客户端的防火墙阻挡了连接请求,传输就失败了,此时可以试一下FTP的被动模式。
(2)Passive mode即表示被动模式。
(3)Windows自带的ftp命令似乎只支持主动模式。
由于海量文件不适合传统的目录结构,所以云存储一般使用对象存储的方式—客户端访问文件时并不使用其路径和文件名,而是使用它的对象ID。
(1)使用HTTPS搜索时抓的包,注意服务器端口是443,关键词也被加密到了“Encrypted Application Data”里。
(2)导出key并导入wireshark:单击Wireshark的Edit–>Preferences–>Protocols–>SSL–>RSA keys list。然后按照IP Address,Port,Protocol,Private Key 的格式填好,此时https中的内容就可以看见了。
(解码所用到的密钥只能在服务器端导出)
(1)身份认证协议也叫 Kerberos,它有着非常广泛的应用,比如Windows域环境的身份认证就会用到它。
(2)Kerberos 采用的方法是引入一个权威的第三方来负责身份认证。这个第三方称为KDC,它知道域里所有账号和资源的密码。
(3)把生成的字符串“{时间戳}Kclt”、账号A 的信息,以及一段随机字符串发给KDC。这样就组成了Kerberos的身份认证请求AS_REQ。
黑客可能在网络上截获字符串“{时间戳} Kclt”,然后伪装成账户A来骗认证。这种方式称为重放攻击。重放攻击的伪装过程需要一段时间,所以 KDC 把解密得到的时间戳和当前时间作对比,如果相差过大就可以判断是重放攻击了。假如采用与时间无关的字符来加密,则无法避开重放攻击,这就是我们必须在域中同步所有机器时间的原因。