赞
踩
目录
UDP(User Datagram Protocol):用户数据报协议。一种传输层协议。
IPv4中协议字段值:17。
特点:
有消息边界。
开销更小,因为没有TCP复杂机制。
当UDP应用程序每次调用send/write,就发出一个UDP数据报。
而TCP不一定,因为TCP可能分段,重组。
即TCP应用程序执行多次send/write调用会组合成一个数据包发送,或可能一个send/write调用被分成多个数据包发送。
头部格式如下:
字段:
源端口
目的端口
长度:UDP报文总长度,包括头部和数据。
校验和:校验整个UDP报文。
每个socket在创建时必须指定协议类型(TCP或UDP),并绑定到特定端口。
因此,一个套接字不能同时监听TCP/UDP相同端口。
一个主机可以创建两个socket,分别监听TCP和UDP的相同端口号,表示两种不同服务。
UDP校验和:校验范围覆盖UDP头部、UDP数据,伪头部。
伪头部(pseudo-header):
计算UDP校验和时,根据IP头信息生成的虚拟头部。
伪头部格式通常包括:
源IP、目标IP、协议类型(UDP),UDP数据报总长等。
作用:提供更多信息,确保校验更精确。
伪头部细节如下图:
NAT会改变报文IP和端口,所以经过NAT后需要重新校验和。
IPv4头中也有校验和,但只校验IPv4头内容,不包括IP载荷。
在每跳都要重新计算,因为TTL字段值减小。
小结:
IPv4头的校验和字段:只校验IPv4头内容。
传输层TCP/UDP头的校验和字段:校验范围不仅包含传输层头,还有载荷。
IPv6中TCP/UDP都需要伪头部来计算校验和。
Teredo隧道:
IPv6数据被封装成IPv4 UDP数据报后,发给Teredo中继,中继解封装后把IPv6报文转发给主机。
Teredo和GRE对比:
通用性:
GRE更通用,可封装任何类型数据包。
Teredo只用于IPv4 UDP封装IPv6数据。
实现方式:
GRE:不需要服务器或中继。
Teredo:需要服务器和中继。
UDP:校验是可选的,要么校验整个UDP报文,要么不校验。
UDP-Lite:对UDP数据一部分校验,而不是整个数据报校验。
所以未校验部分,容忍比特差错。
UDP-Lite:有单独的IPv4协议和IPv6协议号。算是一种新的传输层协议。
所以UDP- Lite有一个校验和覆盖范围字段,表示需要校验哪部分数据。
最小值为8,即只校验UDP-Lite头。
特殊值:0,表示校验整个负载。
socket简化程序举例,设置UDP-Lite校验和覆盖范围:
int main() {
int sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDPLITE);
int send_cscov = 8; // 只校验UDP-Lite头。
setsockopt(sockfd, IPPROTO_UDPLITE, UDPLITE_SEND_CSCOV, &send_cscov, sizeof(send_cscov)) ;
int recv_cscov = 0; // 校验整个负载
setsockopt(sockfd, IPPROTO_UDPLITE, UDPLITE_RECV_CSCOV, &recv_cscov, sizeof(recv_cscov));
}
IPv6只允许源主机分片,不允许中间转发设备分片,可减少中间设备负担。
IPv4既允许源主机分片,也允许中间路由器分片。
IP数据报大于MTU则分片。
被分片IP数据报,到了目的地才会重组,这样设计有两个原因:
1. 减轻中间路由器转发负担。
2. 同一数据报的不同分片可能经不同路径到达目的地,此时路径上路由器不能收到所有分片,搜到没有能力重组原始数据。
数据报分片后,每个分片IPv4头中的总长度字段被修改成该分片的总长度。
任一分片丢失,整个IP数据报无法完整接收。
当TCP报文的一个分片丢失了,TCP协议栈会重传整个TCP报文段,所以通常尽量避免TCP分片。
除最后一个分片外所有分片数据部分应是8字节倍数。
tcpdump为了能打印除了第一个分片外的其他分片的端口号,尝试重组其他分片的数据报,以恢复只出现在第一个分片的UDP头部中的端口号。
当任一分片最先到达时,IP层就启动计时器。
若超时前未收到所有分片,无法重组源报文,会丢弃所有分片,防止缓存耗尽。
超时时间:一般30s,60s。
只有接收到了第一个分片并且分片重组失败时,才产生ICMP错误。
PMTU:路径MTU 。
PMTUD:路径MTU发现。
作用:发现路径中MTU的最小值。发送报文不超过MTU,防止分片。
UDP PMTUD原理:
源端发送一个较大UDP数据报,并设置 DF(Don't Fragment)标志,确保不被分片。
某个中间路由器发现数据报超过其出接口MTU,则丢弃该数据报并回复"Packet Too Big" 的ICMP 错误消息给源端。
源端收到ICMP错误消息后,得到其中指示的MTU。于是重新发送较小的UDP数据报。
重复该过程就获得一个可在所有路由器通过的MTU,即路径最小MTU,PMTU。
IP层会基于每个目的地址缓存一个PMTUD值,有到该目的地报文则更新,否则超时需要重新尝试PMTUD。
PPPoE MTU:1492
1500字节去除了6字节PPPoE头部,2字节PPP头部。
理论一个IPv4数据报的最大长度是65535字节。
但实际存在限制,如:
1. 系统,setsocketopt设置收发缓存大小。
2. 应用程序。read/write指定读写大小数目小于一个UDP数据报,大多数时候发生API截断数据报,丢弃数据报里超过接收应用程序指定字节数的数据。
MSG_TRUNC标志位:
当socket收到超过recv函数指定接收缓冲区大小时,如果设置该标志位,系统将丢弃缓冲区以外数据,并且不报告任何错误,而是正常返回已接收数据长度。
MSG_TRUNC使用方法:
len = recvfrom(sockfd, buf, BUF_SIZE, MSG_TRUNC, (struct sockaddr *)&client_addr, &client_len);
如何获取截断数据大小:
socklen_t optlen = sizeof(recv_len);
getsockopt(sockfd, SOL_SOCKET, SO_RCVBUF, &recv_len, &optlen);
而TCP是连续的字节流,没有消息边界,不会被截断。
SO_REUSEADDR:
一个socket选项,当一个socket被关闭后,它的端口号会继续一段时间的被占用。
在这个时间内,其他程序无法绑定相同端口号,出现"Address already in use"错误。
设置SO_REUSEADDR选项后,当socket关闭后,立即可以被其他程序绑定,无需等待一段时间。
如何设置SO_REUSEADDR属性:
int reuse = 1;
setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse));
两种策略:
1. 只有报文目的IP地址是该接收接口的IP时,才接收数据。
2. 任何本地接口均可接收到目的IP是某本地接口之一的数据。
一台主机上,可以开启多个服务器进程,都使用同一个端口号,但每个服务器进程使用不同本机IP地址。
通过ip addr add给本机设备配置多个IP地址。
此时需要用SO_REUSEADDR选项告诉系统允许重用相同的端口。
可设置是否只接收来自指定源IPv4地址和端口号的UDP数据报。
UDP没有流量和拥塞控制机制。
UDP占据了的互联网流量的10% ~ 40%,随着P2P应用增加,UDP流量也在上升。
互联网总体流量只有极少是分片的(大约分组数的0.3%,字节数的0.8%),而其中分片流量的68.3%是UDP。
常见分片流量如:
多媒体视频流量(应用层大包)
VPN隧道中封装/隧道流量(多层封装)
常见UDP DoS攻击:
1. 短时间大流量。UDP没有流控。
2. 放大攻击。伪造IP源成受害者地址,并设置目的地址为广播。于是广播目的地都回复报文给该受害者。
3. 泪滴攻击。构造一个重叠偏移分片,可覆盖前一分片部分数据。
4. 发送不带任何数据的分片,攻击IPv4重组程序。
UDP是简单协议。
需要组播广播时使用UDP,可避免连接开销。
UDP使用场景:多媒体,P2P。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。