1. 路由
以太网交换机:
以太网交换机工作在数据链路层, 用于在同一网络中的设备转发以太网帧.
路由器:
负责不同网络之间的数据包传送. 路由器通过路由表来确定用于转发数据包的最佳路径. 当网络向不同IP网络中的设备发送数据包时, 数据包会先被转发到默认网关.
2. TCP/IP协议
协议 | PDU | 英文名 | 标识 |
---|---|---|---|
物理层 |
比特 |
bit |
|
链路层 |
帧 |
frame |
MAC地址 |
网络层 |
数据包 |
packet |
IP地址 |
传输层 |
数据段 |
segment |
端口号 |
应用层 |
报文 |
message |
应用协议 |
3. 数据链路层
3.1. CSMA/CD
-
一个站点首先检测网络上正在发送的信号, 并在网络空闲时发送自己的帧.
-
如果其他站点碰巧同时发送, 则为一次碰撞.
-
每个站点等待一个随即时间, 然后再次尝试发送.
-
随后如果再次碰撞, 等待的时间翻倍.
-
最终, 每个站点会得到机会发送, 或者在尝试一定次数(16)后超时.
3.2. Ethernet帧格式
-
前导字段
8
-
目标MAC地址
6
-
源MAC地址
6
-
长度或协议类型
2
-
P/Q标签
0/2
-
上层协议数据
46-1500字节
-
FCS
4
发送和接收由硬件处理
-
IPv4: 0x0800
-
IPv6: 0x86dd
-
ARP: 0x0806
-
RARP: 0x80
-
Q标签帧: 0x8100
MTU: 以太网帧大小范围为64~1518字节, 首部占14字节, CRC校验和占4字节, 所以数据部分大小范围为46~1500字节, 最大传输限制称为 MTU .
3.3. ARP帧格式
ARP提供网络层地址到硬件地址的映射
-
目标地址(1.1.1.1)
-
源地址
-
类型(0x0806)
-
硬件类型(Ethernet(1))
-
协议类型(IPv4)
-
硬件地址大小
-
协议地址大小
-
Opcode: ARP请求(1)/应答(2)
-
发送方MAC地址
-
发送方IP地址
-
接收方MAC地址
-
接收方IP地址
3.4. 物理设备
-
Repeater(中继器): 物理层设备, 用来放大信号.
-
Hub(集线器): 每次发送的信号都会被发送给连接Hub的其他所有机器.
-
Bridge(桥): 保存连接端口的所有设备的MAC地址.
-
Switch(交换机): 保存连接端口的所有设备的MAC地址, 全双工.
3.5. 交换机
交换机内部保存<Mac地址, 连接端口>表.
-
设备1向设备2发送数据包, 交换机收到请求, 根据以太网帧记录下发送方的Mac地址以及端口.
-
如果MAC表里有接收方的Mac地址, 则直接转发数据包到该条记录的端口.
-
如果没有找到记录, 则广播给其他所有端口, 此时连接Hub的所有设备都会收到该数据包, 但只有目标Mac地址与设备自身的Mac地址相同的设备才会受理该数据包.
-
此时总会有一个端口收到响应的数据, 交换机收到数据包后记录下发送方的Mac地址和端口.
4. IP
IP提供了一种尽力而为,无连接的数据包交付服务.
-
版本(0x0100/0x0110)
-
首部长度(一般为0101)
-
Differentiated Service
-
Explicit Congestion Notification
-
总长度
-
数据报标识
-
分片标记
-
分片偏移
-
生存时间
-
传输层协议类型
-
头部校验和
-
源IP地址
-
目的IP地址
-
选项
IP数据包最大为65535字节, 当一个IP数据包大于以太网的MTU时, IP协议会把数据包报文切分为多个小的片段.
4.1. IPv6格式
-
长度为128位, 表现为16进制, 每16位为一块. 如
5f05:2000:80ad:5800:58:800:2023:1d71
. -
a到f的16进制数必须小写.
-
每一块中前导0必须省略不写, 如
2001:0db8::0022
必须要写成2001:0db8::22
. -
最长的全0块必须简写成
::
, 如果有两个最长的全0块, 则第一个简写. 如5f05:0000:0000:5800:58:0000:0000:1d71
简写成5f05::5800:58:0000:0000:1d71
.
4.2. IPv4分类
类别 | 前导位 |
---|---|
A |
0 |
B |
10 |
C |
110 |
D |
1110 |
E |
1111 |
5. TCP
TCP是一种可靠地, 面向连接的, 基于字节流的, 全双工的传输层协议.
-
面向连接的: 通信双方建立连接时要经过三次握手, 断开连接时要经过四次挥手, 四元组
<源地址, 源端口, 目标地址, 目标端口>
标识了一条TCP连接. -
可靠地:
-
每个TCP首部都有两字节表示校验和, 如果收到一个校验和有差错的报文, TCP会直接丢弃该报文等待重传.
-
TCP的序列号保证了接收数据的顺序.
-
TCP在发送数据后会启动一个定时器, 等待对方确认收到这个数据包, 如果在指定时间内没有收到ACK确认包, 就会重传数据包.
-
TCP提供了拥塞控制机制.
-
面向字节的: 字节写入内核后, 最终TCP以多少条报文发送出去是不确定的.
-
全双工的: 通信的双方可以同时发送/接收数据.
-
5.1. TCP首部
-
源端口.
16
-
目的端口.
16
-
序列号: 标识了TCP发送端到TCP接收端的数据流的序号, 序列号用于保证包的顺序, 或者交换彼此的报文(SYN报文).
32
-
确认号: TCP使用确认号来告知对方下一个期望接受的序列号.
32
-
确认号表示小于此确认号的字节都已经收到.
-
不是所有包都需要确认.
-
收到了数据包可以延迟一会儿再确认.
-
ACK包不需要确认.
-
-
首部长度.
4
-
保留位.
4
-
标志位.
8
-
Nonce
-
CWR(Congest Window reduced): 发送方降低它的发送速率.
-
ECN-Echo: 发送方接收到了一个更早的拥塞通告.
-
URG: 标识紧急指针字段有效
-
ACK: 标识确认数据包.
-
PSH: 告知对方这些数据包收到后应立即交给上层应用, 不能缓存起来.
-
RST: 标识强制断开连接.
-
SYN: 标识这个数据包用于发起连接时同步双方的初始序列号.
-
FIN: 告知对方自己发送完了所有数据, 后续不会再有数据发送了.
-
-
窗口大小: 窗口大小值*缩放因子.
16
-
校验和.
16
-
紧急指针.
16
-
可选项.
320max
-
MSS: 发送方允许的最大数据段大小, 默认为536个字节.
-
SACK: 选择确认选项, 发送方带上SACK选项来标识自己支持选择确认的功能.
-
WSCALE: 窗口缩放选项, 标识TCP连接的实际窗口大小为 \$"window"xx2^x\$ .
-
TSOPT: 时间戳选项, 双方通信时记录时间戳, 用来计算往返时间.
-
UTO: 用户超时选项, 标识TCP发送方愿意等待ACK确认的最大超时时间.
-
5.2. MSS
TCP数据段最大值 = MTU - IP头大小 - TCP头大小 (\$1500-20-20=1460\$)
5.3. 端口号
端口号被划分成以下 3 种类型:
-
熟知端口号(0~1023)
-
已登记的端口(1024~49151)
-
临时端口号(49152~65535), 运行
cat /proc/sys/net/ipv4/ip_local_port_range
命令可以查看机器上可用的端口范围.
|
5.4. 三次握手
-
[C]客户端发送SYN包.
SYN-SENT
-
[S]服务端接收到后加一作为ACK包, 然后自己生成一个SYN包一起发送.
SYN-RECV
-
服务端此时会将这个连接信息放入 半连接队列
(SYN 队列)
.
-
-
[C]客户端接收到服务端的SYN包加一, 作为ACK包发送给服务端.
ESTABLISHED
-
服务端收到客户端的ACK包后会将这个连接信息移动到 全连接队列
(Accept队列)
. 此时socket处于ESTABLISHED
状态,每次调用accept
函数会移除队列头的连接. 如果队列为空, 则会阻塞accept
函数.
-
|
5.5. 四次挥手
-
[C]客户端发送FIN包, 以后客户端不能再发送数据给服务端了.
FIN-WAIT-1
-
[S]服务端接收到后回复ACK包.
CLOSE-WAIT
-
[C]客户端接收到ACK包.
FIN-WAIT-2
-
[S]服务端发送FIN包.
LAST-ACK
-
[C]客户端收到FIN包, 发送ACK包.
TIME-WAIT
-
[S]服务端收到ACK包断开连接.
CLOSED
-
[C]客户端经过两个MSL后断开连接.
CLOSED
net.ipv4.tcp_fin_timeout 设置了 TIME-WAIT 状态需要等待的超时时间.
|
-
TIME-WAIT 状态存在的意义?
-
保证上一个连接的包不会因为网络慢发送到一个连接里.
-
可以收到对方的第二个
FIN
包. -
如果主动断开方重用端口, 进行三次握手发送SYN包, 对方(
LAST_ACK
)立即会返回RST
包导致三次握手失败.
-
-
为什么是两个MSL?
-
1个MSL保证
ACK
包能发送到对方. -
1个MSL保证对方如果没有收到
ACK
包, 那么可以收到对方重传的FIN
包.
-
-
发送方对一个ACK应该等待多长时间?
TODO
-
如果ACK丢失该怎么办?
TODO
-
如果分组被接收到了, 但是里面有错该怎么办?
-
使用差错纠正码修复数据.
-
重传.
-
5.6. TCP时间戳选项
TCP时间戳选项首部由四部分组成:
-
Kind: 时间戳类别固定为8
-
Length: 固定为10
-
TS value
-
TS echo reply
-
三次握手SYN包将时间戳写在
TS value
字段上. -
服务端收到SYN包后, 将收到的
TS value
写到TS echo reply
字段上, 然后生成自己的时间戳写到TS value
字段上. -
以此往复.
-
5.8. SO_REUSEADDR
TCP四次挥手后, 主动断开连接的一方会进入 TIME_WAIT
状态, 等待两个MSL后才最终释放这个连接, 此时进程虽然结束, 但是不能在 TIME_WAIT
状态下继续使用该端口.
SO_REUSEADDR
设置为1后即使在 TIME_WAIT
状态下也可以复用该端口.
5.9. SO_LINGER
struct linger {
int l_onoff; /* linger active */
int l_linger; /* how many seconds to linger for */
};
-
l_onoff
为0时表示禁用该特性, close函数会立即返回,操作系统负责把缓冲队列中的数据全部发送至对方. -
l_onoff
为非0时表示启用该特性.-
l_linger
为0, close函数会立即返回,不执行正常的四次挥手, 操作系统把缓冲区数据全部丢弃并立即发送RST包重置连接. -
l_linger
为非0, 那么此时close函数在l_linger时间内发送数据, 之后操作系统把缓冲区数据全部丢弃并立即发送RST包重置连接.
-
6. HTTP
6.1. Cookie
Cookie记录了当前会话的一些数据, 保存在客户端的磁盘或内存中.
-
Set-Cookie头部只能传递一个key/value对, 但可以有多个Set-Cookie头.
-
Cookie属性:
-
Expires: 设置到指定日期后Cookie失效.
-
Max-Age: 设置经过多少秒后Cookie失效, 优先级大于Expires.
-
Domain: 设置该Cookie可以在哪些域名下访问.
-
Path: 设置该Cookie可以在哪些路径下访问.
-
Secure: 设置只有https协议下才能访问该Cookie.
-
HttpOnly: 设置不能用js访问到该Cookie.
-
跨站请求脚本攻击(CSRF): 第三方网站B带上用户本地存储的服务器A的Cookie, 来请求服务器A的接口.
-
校验Referer头是否为本站域名.
-
服务端返回表单中加上隐藏的CSRF Token字段, 表单提交的时候需要校验CSRF Token是否有效.
6.2. 重定向
6.2.2. 临时重定向
-
302: 使用GET请求新的地址.
-
303: 使用GET请求新的地址(语义与300不同).
-
307: 使用原请求的方法和请求体请求新的地址.
7. HTTP2
7.2. Stream结构
-
帧长度, 0~16MB.
24
-
消息内容类型
8
-
DATA
-
HEADERS
-
PRIORITY
-
RST_STREAM
-
SETTING
-
PUSH_PROMISE
-
PING
-
GOAWAY
-
WINDOW_UPDATE
-
CONTINUATION
-
-
标志
8
-
保留位
1
-
StreamId: 标识同一条Stream消息, 由客户端建立的流是奇数, 由服务端建立的流是偶数.
31
-
消息内容
8. 网络查看命令行工具
8.1. netstat
netstat 能够查看所有已连接的TCP/UDP网络连接, 网络协议分析, 端口分析, 查看路由表等.
8.1.1. 安装
sudo apt install net-tools
8.1.2. 命令选项
-
-l
显示所有正在listen
的socket -
-a
显示所有的socket -
-r
显示路由表 -
-i
显示所有接口 -
-g
显示所有广播组 -
-s
显示网络使用情况 -
-M
显示所有伪装的链接 -
-v
显示详细信息 -
-W
显示时不截断ip地址 -
-n
不解析主机名 -
-e
显示更多信息 -
-p
显示socket的进程id -
-o
显示所有的定时器 -
-F
显示转发信息 -
-C
显示路由缓存
8.1.3. 命令示例
# 查看端口占用的进程
sudo netstat -lnp | grep 22| awk '{print $NF}'
# 查看IPv4监听的端口列表
sudo netstat -vutlnp --listening -4
# 查看tcp使用情况分析
sudo netstat -st
# 查看所有监听的unix socket
sudo netstat -lx
8.2. ss
ss相比于netstat还能够查看更多socket信息.
8.2.1. 安装
sudo apt install iproute2 iproute2-doc
8.2.2. 命令选项
-
-n
不解析服务名称 -
-r
解析主机 -
-l
显示所有监听中的socket -
-o
显示所有的定时器 -
-e
显示socket详细信息 -
-m
显示socket内存使用 -
-p
显示socket所属的进程 -
-s
显示socket使用概况 -
-4
仅显示 IPv4 socket -
-6
仅显示 IPv6 socket -
–0
显示 PACKET sockets -
-t
显示 TCP sockets -
-S
显示 SCTP sockets -
-u
显示 UDP sockets -
-w
显示 RAW sockets -
-x
显示 Unix domain sockets -
-f
显示指定FAMILY_TYPE的sockets, 支持 unix, inet, inet6, link, netlink -
-tun
不解析主机名
8.2.3. 命令示例
# 查看指定目标地址/端口的连接
ss dst 192.168.0.2
# 查看指定状态的socket
ss state ESTABLISHED
# 查看port小于1024的socket
ss -n sport \< 1024
9. Appendix
-
路由器的主要功能和特性是什么?
-
在小型路由网络中,如何将设备连接起来?
-
如何使用CLI配置路由器上的基本设置,以实现两个直连网络之间的路由?
-
如何检验直连到路由器的两个网络之间的连接?
-
在接口之间交换数据包时,路由器使用的封装和解封装的过程是什么?
-
什么是路由器的路径决定功能?
-
直连网络的路由表条目是什么?
-
路由器如何创建直连网络的路由表?
-
路由器如何使用静态路由创建路由表?
-
路由器如何使用动态路由协议创建路由表?