1、当发送的报文出问题的时候,会发送一个 ICMP 的差错报文来报告错误,但是如果 ICMP 的差错报文也出问题了呢?
答:不会导致产生 ICMP 差错报文的有:
- ICMP 差错报文(ICMP 查询报文可能会产生 ICMP 差错报文);
- 目的地址是广播地址或多播地址的 IP 数据报;
- 作为链路层广播的数据报;
- 不是 IP 分片的第一片;
- 源地址不是单个主机的数据报。这就是说,源地址不能为零地址、环回地址、广播地址或多播地址。
2、ping 使用的是什么网络编程接口?
答:网络编程接口是 Socket,对于 ping 来讲,使用的是 ICMP,创建 Socket 如下:
socket(AF_INET, SOCK_RAW, IPPROTO_ICMP)
SOCK_RAW 就是基于 IP 层协议建立通信机制。
如果是 TCP,则建立下面的 Socket:
socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)
如果是 UDP,则建立下面的 Socket:
socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)
3、ICMP 差错报文是谁发送的呢?
答:ICMP 包是由内核返回的,在内核中,有一个函数用于发送 ICMP 的包。
void icmp_send(struct sk_buff *skb_in, int type, int code, __be32 info);
例如,目标不可达,会调用下面的函数。
icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PROT_UNREACH, 0);
当 IP 大小超过 MTU 的时候,发送需要分片的 ICMP。
if (ip_exceeds_mtu(skb, mtu)) {icmp_send(skb, ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED, htonl(mtu));goto drop;}
4、NAT 能建立多少连接?
答:SNAT 多用于内网访问外网的场景,鉴于 conntrack 是由{源 IP,源端口,目标 IP,目标端口},hash 后确定的。
如果内网机器很多,但是访问的是不同的外网,也即目标 IP 和目标端口很多,这样内网可承载的数量就非常大,可不止 65535 个。
但是如果内网所有的机器,都一定要访问同一个目标 IP 和目标端口,这样源 IP 如果只有一个,这样的情况下,才受 65535 的端口数目限制,根据原理,一种方法就是多个源 IP,另外的方法就是多个 NAT 网关,来分摊不同的内网机器访问。
如果你使用的是公有云,65535 台机器,应该放在一个 VPC 里面,可以放在多个 VPC 里面,每个 VPC 都可以有自己的 NAT 网关。
5、公网 IP 和私网 IP 需要一一绑定吗?
答:公网 IP 是有限的,如果使用公有云,需要花钱去买。但是不是每一个虚拟机都要有一个公网 IP 的,只有需要对外提供服务的机器,也即接入层的那些 nginx 需要公网 IP,没有公网 IP,使用 SNAT,大家共享 SNAT 网关的公网 IP 地址,也是能够访问的外网的。
6、路由协议要在路由器之间交换信息,这些信息的交换还需要走路由吗?不是死锁了吗?
答:OSPF 是直接基于 IP 协议发送的,而且 OSPF 的包都是发给邻居的,也即只有一跳,不会中间经过路由设备。BGP 是基于 TCP 协议的,在 BGP peer 之间交换信息。
7、多线 BGP 机房是怎么回事儿?
答:BGP 主要用于互联网 AS 自治系统之间的互联,BGP 的最主要功能在于控制路由的传播和选择最好的路由。各大运营商都具有 AS 号,全国各大网络运营商多数都是通过 BGP 协议与自身的 AS 来实现多线互联的。
使用此方案来实现多线路互联,IDC 需要在 CNNIC(中国互联网信息中心)或 APNIC(亚太网络信息中心)申请自己的 IP 地址段和 AS 号,然后通过 BGP 协议将此段 IP 地址广播到其它的网络运营商的网络中。
使用 BGP 协议互联后,网络运营商的所有骨干路由设备将会判断到 IDC 机房 IP 段的最佳路由,以保证不同网络运营商用户的高速访问。
8、TCP 的连接有这么多的状态,你知道如何在系统中查看某个连接的状态吗?
答:可以使用netstat或者lsof命令grep一下establish listen close_wait等来查看。
9、TIME_WAIT 状态太多是怎么回事儿?
答:如果处于 TIMEWAIT 状态,说明双方建立成功过连接,而且已经发送了最后的 ACK 之后,才会处于这个状态,而且是主动发起关闭的一方处于这个状态。
如果存在大量的 TIMEWAIT,往往是因为短连接太多,不断的创建连接,然后释放连接,从而导致很多连接在这个状态,可能会导致无法发起新的连接。解决的方式往往是:
- 打开 tcp_tw_recycle 和 tcp_timestamps 选项;
- 打开 tcp_tw_reuse 和 tcp_timestamps 选项;
- 程序中使用 SO_LINGER,应用强制使用 rst 关闭。
当客户端收到 Connection Reset,往往是收到了 TCP 的 RST 消息,RST 消息一般在下面的情况下发送:
- 试图连接一个未被监听的服务端;
- 对方处于 TIMEWAIT 状态,或者连接已经关闭处于 CLOSED 状态,或者重新监听 seq num 不匹配;
- 发起连接时超时,重传超时,keepalive 超时;
- 在程序中使用 SO_LINGER,关闭连接时,放弃缓存中的数据,给对方发送 RST。
10、起始序列号是怎么计算的,会冲突吗?
答:起始 ISN 是基于时钟的,每 4 毫秒加一,转一圈要 4.55 个小时。
TCP 初始化序列号不能设置为一个固定值,因为这样容易被攻击者猜出后续序列号,从而遭到攻击。 RFC1948 中提出了一个较好的初始化序列号 ISN 随机生成算法。
ISN = M + F (localhost, localport, remotehost, remoteport)
M 是一个计时器,这个计时器每隔 4 毫秒加 1。F 是一个 Hash 算法,根据源 IP、目的 IP、源端口、目的端口生成一个随机数值。要保证 Hash 算法不能被外部轻易推算得出,用 MD5 算法是一个比较好的选择。
11、epoll 是 Linux 上的函数,那你知道 Windows 上对应的机制是什么吗?如果想实现一个跨平台的程序,你知道应该怎么办吗?
答:epoll 是异步通知,当事件发生的时候,通知应用去调用 IO 函数获取数据。IOCP 异步传输,当事件发生时,IOCP 机制会将数据直接拷贝到缓冲区里,应用可以直接使用。
如果跨平台,推荐使用 libevent 库,它是一个事件通知库,适用于 Windows、Linux、BSD 等多种平台,内部使用 select、epoll、kqueue、IOCP 等系统调用管理事件机制。
12、ping是如何nat的呢?
答:通过 nf_conntrack_tuple 里面的内容,可以唯一地标识一个连接:
src:包含源 IP 地址;如果是 TCP 或者 UDP,包含源端口;如果是 ICMP,包含的是 ID;
dst:包含目标 IP 地址;如果是 TCP 或者 UDP,包含目标端口;如果是 ICMP,包含的是 type, code。
此文章为10月Day12学习笔记,内容来源于极客时间《趣谈网络协议》,推荐该课程。