TCP/IP详解 卷2:实现 — 附录A 部分习题解答精华
来源:云盘
/田浩然上传的资料/电子书/TCPIP/TCP-IP详解卷2:实现/033.PDF(附录A 单独分册,约90页,覆盖第1-32章的部分习题答案)。本书为 W. Richard Stevens 经典,逐行剖析 BSD 4.4 Lite Net/2 网络源代码。本笔记按主题归纳附录中最有复用价值的解答,而非逐题抄录。全书结构见 TCP-IP详解卷2-实现-全书章节索引。
提取说明
- pdf-inspector 报 “document has no readable pages”(分册 PDF 页结构异常),pdftotext 兜底成功,文本完整
- 电子版页眉带”下载”水印字样,正文中 inet 等标识符被空格拆开(如
s l i n p u t),整理时已还原
mbuf 与缓冲机制(第2/15/16章)
- M_EXT 标志是 mbuf 自身的属性,不是它所存数据报的属性;多个 mbuf 可指向同一个簇,所以簇里没有后向指针的空间;簇引用计数是
mclrefcnt数组(MCLALLOC/MCLFREE宏) - 环回接口收包用堆栈分配而非动态内存:栈分配快于 malloc,而 BPF 对每个入向数据报都要执行这段代码,性能优先
sbappendaddr/sbappendcontrol(UDP 调用)会先检查sbspace,返回 0 就拒绝入队;TCP 调sbappend则假定调用者已查过空间——即使队列满也会入队,但SS_CANTRECVMORE标志会阻止 read 返回数据- 若内核不限制每个缓存可持有的 mbuf 数量,应用进程用大量小 mbuf 就能轻易造成内存枯竭(sb_cc 远低于 sb_hiwat)
sofree中先复制 in pcb 再在 splimp 下 bzero:为了最小化 CPU 停留在 splimp(阻塞网络中断)的时间- select 存在固有竞争:事件发生在 selscan 检查之后、tsleep 之前会丢失,进程继续沉睡——这是应用层”虚假超时常量”存在的根源
链路层与接口(第4/5/12/21章)
- BPF 开关使接口进入混杂模式后,
leread必须判断数据报是否该丢弃(目的地可能是别的主机) - 环回接口不需要输入函数:它收到的所有分组都直接来自
looutput,后者实际完成了输入功能;也不必响应 IGMP 查询(本地主机是环回网唯一成员) - 缓存溢出处理:溢出首字节丢弃、置 SC_ERROR,
slinput收到 END 字符后丢弃整帧并从缓存起始重新收集 ifp能直接强转为le_softc*,因为 ifp 指向 ifnet 结构,而 ifnet 是 softc 结构第一个成员(arpcom 同理)——Net/3 的通用”结构首成员”惯用法- ARP 记录不完整时 0~5 分钟超时:
arpresolve发 ARP 请求时把rt_expire设为当前时间,下次仍未解析即删除 ether_output故意返回 EHOSTUNREACH 而非 EHOSTDOWN,使 ip_forward 能发 ICMP 主机不可达差错- IP 广播地址 255.255.255.255 转成以太网广播 ff:ff:ff:ff:ff:ff(全网卡收);多播 224.0.0.1 转 01:00:5e:00:00:01,由网卡硬件直接过滤,没跑 IP 的系统根本收不到
- 多播路由中只有虚接口(隧道)能成为多播树父接口;分组若在隧道上接收,对应物理接口不能当父接口,ip_mforward 丢弃
IP 层(第8/9/10/12/13章)
- TTL 减 1 必须放在 ≤1 测试之后:否则收到 TTL=0 的包减 1 变 255(无符号回绕)继续转发
- 路由器互相视对方为下一跳即形成路由环路(路由更新暂态不一致所致):两路由器互发 ICMP 重定向,数据报来回传直到 TTL 减为 0 被丢弃——“这就是 TTL 存在的主要原因”
- ICMP 差错只对第一个分片(偏移=0)生成:偏移 0 在大小端字节序下表示相同,无需转换
- 源路由选项处理会改
ip_dst,因此记录路由/时间戳选项要保存原始目的地址;多个源路由选项时 Net/3 只能正确处理第一个(ip_dst 已被更新);NOP 填充让每个 IP 地址按 4 字节边界对齐以优化读取 - 最大标准时间戳值 86399999(24×60×60×1000−1)只需 28 bit,32 bit 字段避免与非标准值高位混淆
- 分片重装后只有第一个分片的选项上交运输层
- 多播组成员报告加随机延迟的原因:让网络中的报告数趋近 1(减少 IGMP 报文量),并防止大量报告淹没接口输出队列(SLIP 输出队列满会丢弃所有等待数据报);点对点链路两端就 2 个接口,无需延迟
IP_MAX_MEMBERSHIPS上限 25:完整 ip_moptions 结构必须放进单个 mbuf(108 字节 = 4+1+1+2+4×25,扣 20 字节 mbuf 首部)- Net/3 的
ip_getmoptions存在内存泄漏(mbuf 永不释放)——原书中的经典 bug 答案 - 环回数据报免检验和的改进思路:新 mbuf 标志 M_LOCAL,ipintr 见置位即跳过校验和(SunOS 5.x 有 ip_local_cksum 选项)
ICMP(第11章)
- 不允许对链路层广播数据报发 ICMP 差错:伪造源地址的坏广播包会让全网每台主机都向”源”回 ICMP,形成放大攻击(天然版反射洪水)
- 主机只接受”自己选定的默认路由器”发来的重定向(RFC 1009 规定路由器只能向同子网路由器发重定向),防重定向欺骗
- 收到 ICMP 请求的接口若未配 IP 地址(ia 为空)则应答消失
- ICMP 处理过程中产生的差错一律丢弃(icmp_send 不返回错误)——避免差错生差错的死循环
- 老系统靠守护进程接管 RIP 报文:rip_input 把报文交给 rip_input 处理以兼容依赖此行为的旧系统
路由表(第18/19/20章)
- 路由匹配的本质:
(查找键 XOR 路由键) AND 掩码 == 0。异或为 1 表示该位不同;与掩码相与忽略”掩码位=0”的位(构建路由表时保证掩码 0 位对应键 0 位) rn_b是 short,16 bit → 每个路由键最长 32767 bit(4095 字节)- 一条路由 rte 约 120 字节 + 2 个 sockaddr_in = 152 字节;因特网全表约 3MB
- ICMP 重定向建的新路由置 RTF_DYNAMIC,改网关置 RTF_MODIFIED;有了逐主机动态路由后 TCP 可实现每主机 RTT 测量(对每个经默认路由可达主机建主机路由)
- 路由消息大小:rt_msghdr 76B + 2 个 sockaddr_in → 主机路由 108B、网络路由 116B(多 8B 掩码);rtm_errno 与 write 返回值双通道回传错误(后者更可靠,mbuf 短缺可能丢响应报文)
插口层与 UDP(第15/16/22/23章)
- 绑临时端口的 DoS:应用进程打开足够多描述符可占满所有临时端口(无限循环 bind 端口 0)
- bind 255.255.255.255 会失败(ifa_ifwithaddr 不认),但 bind 某接口广播地址可成功并被用做源地址——RFC 1122 不允许,Net/3 未拦
- sosend 的 mbuf 策略:≤100B 单 mbuf;≤207B 两 mbuf;更长则每段挂簇;再 M_PREPEND 给 IP/TCP 首部单独 mbuf
- 未连接 UDP 套接字首次 sendto 也会触发 in_pcbconnect:临时端口 + 按路由选本地地址;断开”连接”的方式是 connect 到 0.0.0.0:0
- 多宿主服务器回包源地址问题:需 IP_RECVDSTADDR + recvmsg 取目的地址,而一个套接字只能 bind 一次 → 每次应答都要新建套接字
- UDP 想让数据报带 DF 位:IP 不改调用者传的 DF,需新套接字选项让 udp_output 在递交前设置
- recvmsg 与 recvfrom 都走 recvit;只有 recvmsg 处理控制信息(msg_hdr 整体复制)
- uiomove 而非 copyin/copyout:因为要跨多个 mbuf 复制
TCP 与原始套接字/BPF(第24/31/32章)
- tcp_output 保存 IP+TCP 首部的 mbuf 里要预留 max_linkhdr 空间:若另配链路层首部 mbuf,40 字节首部可能被迫拆到两个 mbuf(bcopy 直拷不可行的原因)
- 原始 IP 套接字收不到内核已处理的协议数据报(收不到 TCP/UDP 段);协议号 255/0 是 RFC 保留值:设为 255 的原始套接字永远收不到任何数据报(rip_input 第一项测试即过滤),协议 0(通配)则接收所有内核不处理的数据报
- 原始 IP 套接字 vs BPF 输出对比:raw IP 走 sendto→ip_output 正常选路(自构 IP 首部);BPF 走 write、自构链路层首部、跳过 IP 选路,只能发直连网(或手动把帧丢给路由器)
- BPF 能收所有到达接口帧(含非 IP),BIOCROMISC 混杂模式可收”不发给本机”的包;BIOCSETIF 找不到接口返回 ENXIO;fork 后多进程可共享同一 BPF 设备句柄
关键工程启示
- 无符号回绕(TTL-1)、差错风暴(广播→ICMP 放大)、差错死循环(ICMP 生 ICMP)是网络协议实现的三大经典陷阱,Net/3 全部用简单规则封堵
- Net/3 大量依赖”结构首成员”指针强转惯用法(ifnet↔arpcom↔softc、le_softc),改动结构布局即崩
- 性能取向的取舍贯穿全书:栈分配代替 malloc、NOP 对齐、splimp 窗口最小化、硬件多播过滤
- 原书自己承认的实现缺陷(ip_getmoptions 泄漏、23.4 splnet 未还原)提醒:读源码要带批判视角
关联
- TCP-IP详解卷2-实现-全书章节索引 — 同书 32 章结构索引(本笔记是附录A 答案精华)
- TCP-IP详解卷3-第12章-TTCP实现-TCP用户请求 — 卷3 同作者续篇
- WAPI安全标准技术白皮书-证书双向认证体系 — 同期网络协议类文档