作者: andylin02
学习章节: 第十九章 密钥管理套接字
关键词: PF_KEY, IPsec, 安全联盟数据库(SADB), 安全策略数据库(SPD), sadb_msg, 消息扩展, 内核-用户空间通信, Linux Netlink, XFRM
一、章节概述
1.1 本章焦点
第十九章是UNP第三版新增的重要章节,专门介绍密钥管理套接字(Key Management Sockets)。随着IP安全体系结构(IPsec)的引入,密钥加密和认证密钥的管理迫切需要一套标准化的通信机制。RFC 2367定义了一套通用的密钥管理API,不仅可用于IPsec,还可用于其他网络安全服务。
本章的核心任务是:理解PF_KEY协议族的定位和作用,掌握密钥管理消息的结构与类型,并通过完整示例理解密钥管理套接字在IPsec安全联盟(SA)管理中的应用。
本章创建了一个新的协议族——PF_KEY域。与第18章的路由套接字类似,密钥管理域中只支持原始套接字这一种套接字类型。
💡 本章核心价值:读完第十九章,你将能够——
- 理解密钥管理套接字在IPsec体系中的定位与作用
- 熟悉密钥管理消息的格式与扩展机制
- 掌握
SADB_MSG结构体的各个字段及其含义- 了解11种标准消息类型和多种扩展类型
- 理解SADB与SPD在IPsec安全中的角色
- 知道Linux系统中PF_KEY已被Netlink XFRM替代
二、密钥管理套接字概述
2.1 什么是密钥管理套接字
密钥管理套接字(PF_KEY套接字)是RFC 2367定义的一套用于密钥管理的API,提供了一种在用户空间密钥管理应用和内核密钥管理子系统之间进行通信的标准机制。
安全联盟数据库(SADB) :SADB是内核中维护安全联盟信息的核心数据结构,其中存储了用于保护入站和出站数据包的各类安全联盟(SA),每个SA定义了特定数据流使用的安全协议(如AH或ESP)、算法、密钥以及SA的生存期等参数。
密钥管理应用通过PF_KEY套接字与内核通信,实现SADB的管理维护。这类似于路由套接字机制(第18章)。
2.2 PF_KEY与AF_KEY
在大多数系统上,常值AF_KEY被定义成与PF_KEY有相同的值,但RFC 2367明确要求密钥管理套接字必须使用PF_KEY常值。使用AF_KEY作为协议族的名称在本书第3版中被视为错误,阅读时需要注意这一细节。
2.3 套接字创建
#include <sys/types.h>
#include <sys/socket.h>
#include <net/pfkeyv2.h>
int sockfd = socket(PF_KEY, SOCK_RAW, PF_KEY_V2);
参数说明:
| 参数 | 值 | 说明 |
|---|---|---|
domain | PF_KEY | 密钥管理协议族,使用PF_KEY常值(RFC 2367要求) |
type | SOCK_RAW | 密钥管理域中只支持原始套接字 |
protocol | PF_KEY_V2 | 协议版本,当前为V2 |
2.4 访问权限
只有超级用户(root) 才能访问SADB。一个系统上可以同时打开多个密钥套接字。操作系统的密钥管理子系统也可能自发地(spontaneously)向监听进程发送pf_key消息,例如请求为外出数据报安装新的SA,或报告现有SA的到期事件。
2.5 密钥管理套接字在IPsec体系中的位置图
┌─────────────────────────────────────────────────────────────────────────────────────┐
│ 密钥管理套接字在IPsec体系中的位置 │
├─────────────────────────────────────────────────────────────────────────────────────┤
│ │
│ 用户空间 │
│ ┌─────────────────────────────────────────────────────────────────────────────┐ │
│ │ IKE守护进程(如racoon、strongSwan) │ │
│ │ │ │ │
│ │ │ PF_KEY套接字 │ │
│ │ ▼ │ │
│ │ ┌─────────────────────────────────────────────────────────────────────┐ │ │
│ │ │ PF_KEY消息(sadb_msg + 扩展) │ │ │
│ │ └─────────────────────────────────────────────────────────────────────┘ │ │
│ └─────────────────────────────────────────────────────────────────────────────┘ │
│ │ │
│ ─────────────────────────────────────────┼─────────────────────────────────────────│
│ ▼ │
│ 内核空间 │
│ ┌─────────────────────────────────────────────────────────────────────────────┐ │
│ │ PF_KEY协议族(PF_KEY Domain) │ │
│ │ │ │ │
│ │ ▼ │ │
│ │ ┌─────────────────────────────────────────────────────────────────────┐ │ │
│ │ │ SADB(安全联盟数据库) SPD(安全策略数据库) │ │ │
│ │ │ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ │ │ │
│ │ │ │ SA1 │ │ SA2 │ │ ... │ │ 策略1 │ │ 策略2 │ │ │ │
│ │ │ │ SPI/算法│ │ SPI/算法│ │ │ │选择符/动作│ │选择符/动作│ │ │ │
│ │ │ │ 密钥/生 │ │ 密钥/生 │ │ │ │ │ │ │ │ │ │
│ │ │ │ 存期 │ │ 存期 │ │ │ │ │ │ │ │ │ │
│ │ │ └─────────┘ └─────────┘ └─────────┘ └─────────┘ └─────────┘ │ │ │
│ │ └─────────────────────────────────────────────────────────────────────┘ │ │
│ │ │ │ │
│ │ ▼ │ │
│ │ IPsec协议栈(AH/ESP处理) │ │
│ └─────────────────────────────────────────────────────────────────────────────┘ │
│ │
│ 💡 核心交互模式:用户空间IKE守护进程 ↔ PF_KEY套接字 ↔ 内核SADB/SPD │
│ │
└─────────────────────────────────────────────────────────────────────────────────────┘
三、密钥管理消息结构
3.1 消息的基本构成
密钥管理套接字上交换的所有消息均由一个小的基包头和零个或多个扩展消息构成。基包头和所有扩展都必须8字节对齐。
消息长度以8字节为单位存储在sadb_msg_len字段中,这保证了整个消息结构的对齐要求。消息的构造和解析通常使用<net/pfkeyv2.h>头文件中定义的宏来进行内存对齐计算。
3.2 基包头结构(sadb_msg)
所有密钥管理消息都以sadb_msg结构开头,它是解析消息的入口点:
struct sadb_msg {
uint8_t sadb_msg_version; /* 协议版本,设置为PF_KEY_V2 */
uint8_t sadb_msg_type; /* 消息类型 */
uint8_t sadb_msg_errno; /* 错误指示 */
uint8_t sadb_msg_satype; /* SA类型(安全服务类型) */
uint16_t sadb_msg_len; /* 长度(单位:8字节) */
uint16_t sadb_msg_reserved; /* 保留字段,发送时置0 */
uint32_t sadb_msg_seq; /* 序列号,用于匹配请求与应答 */
uint32_t sadb_msg_pid; /* 源或目的进程ID */
};
关键字段详解:
| 字段 | 说明 |
|---|---|
sadb_msg_version | 必须设置为PF_KEY_V2,用于版本兼容性检查 |
sadb_msg_type | 消息类型,参见下表。大多数类型可在用户态和内核间双向传递 |
sadb_msg_errno | 指示消息失败的原因,0表示成功 |
sadb_msg_satype | 指明SA的安全服务类型(如SADB_SATYPE_AH或SADB_SATYPE_ESP) |
sadb_msg_len | 以8字节为单位的消息总长度。例如长度值为4表示32字节 |
sadb_msg_seq | 序列号,用于将应答消息与请求消息关联 |
sadb_msg_pid | 源进程ID,用于标识消息的发送方 |
3.3 消息长度单位说明
sadb_msg_len以8字节(64位) 为计数单位。整个消息(包括基包头和所有扩展)的总长度,必须始终是8字节的整数倍。这是因为后续扩展字段要求8字节对齐,因此基包头的长度也以同样的单位存储。
3.4 扩展结构
基包头之后可以跟零个或多个扩展。每个扩展都包含一个扩展类型和一个长度字段。扩展类型包括:
| 扩展类型 | 用途 |
|---|---|
SADB_EXT_SA | SA信息,包含SPI、重放窗口、加密/认证算法等 |
SADB_EXT_LIFETIME_HARD | 硬生存期(到达后SA失效) |
SADB_EXT_LIFETIME_SOFT | 软生存期(到达后需更新) |
SADB_EXT_ADDRESS_SRC | 源地址 |
SADB_EXT_ADDRESS_DST | 目的地址 |
SADB_EXT_ADDRESS_PROXY | 代理地址 |
SADB_EXT_KEY_AUTH | 认证密钥 |
SADB_EXT_KEY_ENCRYPT | 加密密钥 |
SADB_EXT_SPIRANGE | SPI范围 |
SADB_EXT_SENSITIVITY | 敏感级别 |
示例:SADB_GET消息需要包含基包头、SA扩展和目的地址扩展。
四、消息类型详解
4.1 标准消息类型
RFC 2367定义了以下消息类型:
| 类型 | 宏定义 | 方向 | 说明 |
|---|---|---|---|
| 0 | SADB_RESERVED | — | 保留 |
| 1 | SADB_GETSPI | 用户→内核 | 从系统获取一个新的SPI值,用于创建SADB表项 |
| 2 | SADB_UPDATE | 用户→内核 | 更新一个SA(修改不完备的SADB表项) |
| 3 | SADB_ADD | 用户→内核 | 添加一个完整的SA到SADB |
| 4 | SADB_DELETE | 用户→内核 | 删除一个SA |
| 5 | SADB_GET | 用户→内核 | 获取一个SA的信息 |
| 6 | SADB_ACQUIRE | 内核→用户 | 内核需要新的SA,请求密钥管理守护进程安装SA |
| 7 | SADB_REGISTER | 用户→内核 | 注册以接收SADB_ACQUIRE消息 |
| 8 | SADB_EXPIRE | 内核→用户 | 通知某个SA已经期满 |
| 9 | SADB_FLUSH | 用户→内核 | 清空整个SADB |
| 10 | SADB_DUMP | 用户→内核 | 倾泻出SADB(调试用,不可靠) |
方向说明:以上1-10这10个值中,SADB_EXPIRE(8)只能由内核发往用户空间;其他类型都可在用户和内核之间双向传递。
4.2 消息类型交互流程图
┌─────────────────────────────────────────────────────────────────────────────────────┐
│ PF_KEY消息类型交互流程 │
├─────────────────────────────────────────────────────────────────────────────────────┤
│ │
│ 用户态(IKE守护进程) 内核态(SADB) │
│ │
│ ┌─────────────────────────────────────────────────────────────────────────────┐ │
│ │ 阶段1:初始化与注册 │ │
│ │ socket(PF_KEY, SOCK_RAW, PF_KEY_V2) │ │
│ │ SADB_REGISTER ────────────────────────────────────────────────────────────→│ │
│ │ (注册接收SADB_ACQUIRE消息) │ │
│ └─────────────────────────────────────────────────────────────────────────────┘ │
│ │
│ ┌─────────────────────────────────────────────────────────────────────────────┐ │
│ │ 阶段2:外出数据包触发SA请求 │ │
│ │ ┌─→ 外出数据包到达,无匹配SA │ │
│ │ │ │ │
│ │ SADB_ACQUIRE ←────────────────┼────────────────────────────────────────────│ │
│ │ (内核请求新的SA) │ │ │
│ └─────────────────────────────────────────────────────────────────────────────┘ │
│ │
│ ┌─────────────────────────────────────────────────────────────────────────────┐ │
│ │ 阶段3:SA协商与安装 │ │
│ │ SADB_GETSPI ──────────────────────────────────────────────────────────────→│ │
│ │ (获取SPI) │ │
│ │ SADB_ADD ─────────────────────────────────────────────────────────────────→│ │
│ │ (安装协商好的SA) │ │
│ └─────────────────────────────────────────────────────────────────────────────┘ │
│ │
│ ┌─────────────────────────────────────────────────────────────────────────────┐ │
│ │ 阶段4:SA到期处理 │ │
│ │ │ │
│ │ SADB_EXPIRE ←──────────────────────────────────────────────────────────────│ │
│ │ (通知SA已期满,需要重新协商) │ │
│ └─────────────────────────────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────────────────────────┘
4.3 SA类型
sadb_msg_satype字段指定SA的安全服务类型:
| 类型值 | 宏定义 | 说明 |
|---|---|---|
| 0 | SADB_SATYPE_UNSPEC | 未指明,仅限请求消息 |
| 1 | SADB_SATYPE_AH | AH(认证头) |
| 2 | SADB_SATYPE_ESP | ESP(封装安全载荷) |
| 3 | SADB_SATYPE_RSVP | RSVP |
| 4 | SADB_SATYPE_OSPFV2 | OSPFv2 |
| 5 | SADB_SATYPE_RIPV2 | RIPv2 |
| 6 | SADB_SATYPE_MIP | 移动IP |
4.4 sadb_msg_type与扩展类型的对应关系
| 消息类型 | 必需的扩展 |
|---|---|
SADB_GETSPI | 源地址、目的地址、SPI范围 |
SADB_UPDATE | SA信息、源地址、目的地址(可选:生存期、密钥等) |
SADB_ADD | SA信息、源地址、目的地址、认证密钥、加密密钥 |
SADB_DELETE | 源地址、目的地址 |
SADB_GET | 源地址、目的地址 |
SADB_ACQUIRE | 源地址、目的地址(可选:SA信息、生存期) |
SADB_REGISTER | 无 |
SADB_EXPIRE | SA信息、生存期(硬和软) |
SADB_FLUSH | 无 |
SADB_DUMP | 无 |
五、IPsec相关的扩展概念
5.1 安全联盟数据库(SADB)
SADB是内核中存储SA信息的数据结构,其中每个SA通过三元组唯一标识:SPI(安全参数索引)、目的IP地址、安全协议(AH/ESP)。
SADB的功能包括:查找入站SA用于解封数据包、查找出站SA用于封装数据包、管理SA的生存期。
5.2 安全策略数据库(SPD)
SPD用于定义IPsec策略,决定哪些流量需要IPsec保护,以及使用哪个SA。SPD中的策略条目由选择符(源/目的IP地址、协议、端口等)和动作(绕过、丢弃、使用IPsec)组成。当外出数据包到达时,内核首先查询SPD决定如何处理该数据包。
六、完整代码示例
6.1 创建密钥管理套接字并发送注册消息
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <net/pfkeyv2.h>
int main()
{
int sockfd;
struct sadb_msg msg;
ssize_t n;
/* 1. 创建PF_KEY套接字 */
sockfd = socket(PF_KEY, SOCK_RAW, PF_KEY_V2);
if (sockfd < 0) {
perror("socket");
exit(1);
}
/* 2. 构造SADB_REGISTER消息 */
memset(&msg, 0, sizeof(msg));
msg.sadb_msg_version = PF_KEY_V2; /* 协议版本 */
msg.sadb_msg_type = SADB_REGISTER; /* 消息类型:注册 */
msg.sadb_msg_satype = SADB_SATYPE_ESP; /* 注册ESP类型的SA */
msg.sadb_msg_len = sizeof(msg) / 8; /* 长度以8字节为单位 */
msg.sadb_msg_pid = getpid(); /* 进程ID */
msg.sadb_msg_seq = 1; /* 序列号 */
/* 3. 发送注册消息 */
if (send(sockfd, &msg, sizeof(msg), 0) < 0) {
perror("send");
close(sockfd);
exit(1);
}
printf("SADB_REGISTER sent\n");
/* 4. 接收应答 */
n = recv(sockfd, &msg, sizeof(msg), 0);
if (n < 0) {
perror("recv");
close(sockfd);
exit(1);
}
if (msg.sadb_msg_errno == 0) {
printf("Registration successful\n");
} else {
printf("Registration failed with errno=%d\n", msg.sadb_msg_errno);
}
close(sockfd);
return 0;
}
💡 代码说明:此示例演示了密钥管理套接字最基本的用法——向内核注册以接收
SADB_ACQUIRE消息。发送SADB_REGISTER后,内核将知道有密钥管理守护进程在监听,当需要新的SA时会主动发送SADB_ACQUIRE消息。
6.2 内核主动发送消息的处理框架
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <net/pfkeyv2.h>
#define MAX_BUF 4096
void process_sadb_message(struct sadb_msg *msg)
{
switch (msg->sadb_msg_type) {
case SADB_ACQUIRE:
printf("Received SADB_ACQUIRE: kernel needs a new SA\n");
/* 在此处进行IKE协商,协商完成后使用SADB_ADD安装SA */
break;
case SADB_EXPIRE:
printf("Received SADB_EXPIRE: SA has expired, need rekey\n");
/* 重新协商并更新SA */
break;
default:
printf("Received message type %d\n", msg->sadb_msg_type);
break;
}
}
int main()
{
int sockfd;
char buf[MAX_BUF];
ssize_t n;
sockfd = socket(PF_KEY, SOCK_RAW, PF_KEY_V2);
if (sockfd < 0) {
perror("socket");
exit(1);
}
/* 循环接收内核消息 */
while (1) {
n = recv(sockfd, buf, sizeof(buf), 0);
if (n < 0) {
perror("recv");
break;
}
if (n >= sizeof(struct sadb_msg)) {
process_sadb_message((struct sadb_msg *)buf);
}
}
close(sockfd);
return 0;
}
💡 代码说明:此示例展示了密钥管理守护进程(如racoon、strongSwan)的核心处理循环。守护进程持续监听PF_KEY套接字,等待内核主动发送的
SADB_ACQUIRE和SADB_EXPIRE等消息,然后触发IKE协商过程。
七、密钥管理套接字的内存布局
7.1 sadb_msg基包头内存布局
┌─────────────────────────────────────────────────────────────────────────────────────┐
│ sadb_msg基包头内存布局(共64位/8字节) │
├─────────────────────────────────────────────────────────────────────────────────────┤
│ │
│ 0 8 16 24 32 │
│ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 │
│ ┌───────────────────────────────────────────────────────────────────────────────┐ │
│ │ version (8) │ type (8) │ errno (8) │ satype (8) │ │ │
│ ├───────────────────────────────┬───────────────────────────────────────────────┤ │
│ │ len (16) │ reserved (16) │ │
│ ├───────────────────────────────┼───────────────────────────────────────────────┤ │
│ │ seq (32) │ │
│ ├───────────────────────────────┼───────────────────────────────────────────────┤ │
│ │ pid (32) │ │
│ └───────────────────────────────────────────────────────────────────────────────┘ │
│ │
│ 💡 所有字段都是8字节对齐的,因此结构体总大小为64位(8字节) │
│ │
└─────────────────────────────────────────────────────────────────────────────────────┘
7.2 完整消息内存布局示例
┌─────────────────────────────────────────────────────────────────────────────────────┐
│ 完整PF_KEY消息内存布局(SADB_GET示例) │
├─────────────────────────────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────────────────────────────────────────────────────────────────────┐ │
│ │ struct sadb_msg(基包头,8字节) │ │
│ │ version=PF_KEY_V2 | type=SADB_GET | errno=0 | satype=ESP │ │
│ │ len = 4(表示总长度32字节) | seq=1 | pid=1234 │ │
│ └─────────────────────────────────────────────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌─────────────────────────────────────────────────────────────────────────────┐ │
│ │ SADB_EXT_SA扩展(SA信息,8字节) │ │
│ │ exttype=SADB_EXT_SA | len=1 | SPI=0x12345678 | ... │ │
│ └─────────────────────────────────────────────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌─────────────────────────────────────────────────────────────────────────────┐ │
│ │ SADB_EXT_ADDRESS_DST扩展(目的地址,通常16字节) │ │
│ │ exttype=SADB_EXT_ADDRESS_DST | len=2(16字节) | 192.168.1.1 │ │
│ └─────────────────────────────────────────────────────────────────────────────┘ │
│ │
│ 总长度 = 8 + 8 + 16 = 32字节,len字段值为32/8 = 4 │
│ │
└─────────────────────────────────────────────────────────────────────────────────────┘
八、Linux系统的特殊说明
8.1 PF_KEY的现状
在Linux系统中,PF_KEY套接字的使用情况较为特殊,需要注意以下几点:
-
内核实现:Linux内核的
net/key/af_key.c文件实现了PF_KEYv2套接字接口。 -
调度弃用:PF_KEY用户配置接口在十多年前已被Netlink用户配置接口取代。目前所有维护中的IKE实现都已迁移到Netlink接口。
-
弃用时间表:Linux内核开发社区已宣布弃用PF_KEY套接字接口,并计划在2027年将其移除。
8.2 现代替代方案:Netlink XFRM
在Linux系统上进行IPsec SA/SP管理的现代方法是使用Netlink套接字的XFRM(XFRM_USER)接口。XFRM接口提供以下优势:
- 更丰富的功能集
- 更好的可扩展性
- 支持事件通知机制
- 更符合Linux内核的开发方向
⚠️ 可移植性警告:PF_KEY套接字主要在BSD系统和某些Unix衍生系统上原生支持。在Linux系统上虽然存在实现,但已标记为弃用,推荐使用Netlink XFRM接口。
8.3 查看系统中打开的PF_KEY套接字
# 在Linux系统中查看当前打开的PF_KEY套接字信息
cat /proc/net/pf_key
每个表项代表一个打开的PF_KEY套接字,包含协议族、套接字状态、进程ID等参数。
九、常见问题与注意事项
9.1 常见错误速查表
| 问题 | 原因 | 解决方案 |
|---|---|---|
socket: Permission denied | 需要超级用户权限 | 以root身份运行程序,或使用sudo |
socket: Protocol not supported | 内核不支持PF_KEY | 检查内核配置,确保IPsec支持已编译 |
| 消息发送后无响应 | 消息格式错误或扩展顺序不正确 | 检查扩展的排列顺序是否与消息类型要求一致,确保长度以8字节为单位 |
SADB_ACQUIRE收不到 | 未注册SADB_REGISTER | 在初始化阶段发送SADB_REGISTER消息注册 |
| 地址扩展解析错误 | 未正确处理sockaddr的salen字段 | 使用salen+对齐规则正确遍历扩展 |
| 消息长度计算错误 | sadb_msg_len单位是8字节 | 总字节数除以8后赋值给len |
9.2 编程注意事项
| 注意事项 | 说明 |
|---|---|
| 8字节对齐 | 所有扩展必须8字节对齐,必要时需要填充 |
| 扩展顺序 | 扩展的排列顺序必须遵循协议要求,不能随意调换 |
sadb_msg_len单位 | 以8字节为单位,而非字节 |
| SPI的唯一性 | 在目的地址和安全协议组合下,SPI必须唯一 |
| 密钥材料的处理 | 认证密钥和加密密钥以扩展形式传递,需注意密钥长度 |
| 匹配请求与应答 | 使用sadb_msg_seq和sadb_msg_pid匹配应答消息 |
| 错误处理 | 检查sadb_msg_errno字段以确定消息处理结果 |
9.3 与其他章节的关联
| 章节 | 关联内容 |
|---|---|
| 第18章 路由套接字 | 类似的协议族设计,原始套接字模式 |
| 第20章 广播 | 某些密钥管理协议使用广播或多播进行发现 |
| 第21章 多播 | IPsec多播SA的管理可能涉及多播地址 |
十、本章小结
10.1 核心知识点回顾
| 知识点 | 关键要点 |
|---|---|
| PF_KEY协议族 | RFC 2367定义的通用密钥管理API,用于IPsec和其他网络安全服务 |
| 套接字创建 | socket(PF_KEY, SOCK_RAW, PF_KEY_V2),仅支持原始套接字 |
| sadb_msg基包头 | 所有消息的公共头部,包含版本、类型、错误码、SA类型、长度、序列号、PID |
| 消息扩展 | 基包头后跟零个或多个扩展(SA信息、地址、密钥、生存期等) |
| 11种消息类型 | SADB_GETSPI、UPDATE、ADD、DELETE、GET、ACQUIRE、REGISTER、EXPIRE、FLUSH、DUMP、RESERVED |
| SADB_ACQUIRE | 唯一只能由内核发往用户空间的消息,用于请求新的SA |
| 方向特性 | SADB_EXPIRE只能内核→用户;其他类型可在用户和内核间双向传递 |
| SA三元组 | SPI + 目的IP + 安全协议 |
| Linux现状 | PF_KEY已弃用,推荐使用Netlink XFRM接口 |
| 访问权限 | 需要超级用户权限访问SADB |
10.2 本章思维导图
第十九章 密钥管理套接字
├── PF_KEY协议族概述
│ ├── 定义:RFC 2367通用密钥管理API
│ ├── 用途:IPsec SA/SP管理
│ ├── 套接字:socket(PF_KEY, SOCK_RAW, PF_KEY_V2)
│ └── 权限:需要超级用户
├── 核心数据结构
│ ├── struct sadb_msg(基包头)
│ │ ├── version:PF_KEY_V2
│ │ ├── type:消息类型
│ │ ├── errno:错误指示
│ │ ├── satype:SA类型(AH/ESP等)
│ │ ├── len:长度(8字节单位)
│ │ ├── seq:序列号
│ │ └── pid:进程ID
│ └── 扩展类型(SADB_EXT_xxx)
│ ├── SA信息、地址、生存期、密钥
├── 11种消息类型
│ ├── 用户→内核:GETSPI, UPDATE, ADD, DELETE, GET, REGISTER, FLUSH, DUMP
│ └── 内核→用户:ACQUIRE, EXPIRE
├── 消息交互流程
│ ├── 注册 → ACQUIRE请求 → 协商 → ADD → EXPIRE通知
│ └── 匹配请求与应答:通过seq和pid
├── IPsec体系
│ ├── SADB(安全联盟数据库)
│ └── SPD(安全策略数据库)
└── Linux平台说明
├── PF_KEY已弃用(计划2027年移除)
└── 替代方案:Netlink XFRM (XFRM_USER)
十一、下一章预告
📌 下一篇:《UNIX网络编程》读书笔记(二十):第二十章 广播
第二十章将详细讲解:
- 广播的基本概念:广播地址格式(有限广播255.255.255.255和子网定向广播)、广播与单播/多播的区别
- 广播的应用场景:局域网服务发现(ARP、DHCP、NetBIOS)、网络唤醒(Wake-on-LAN)等
- SO_BROADCAST套接字选项:为什么发送广播必须显式启用该选项
- 广播发送端编程:设置广播选项、构造广播地址、发送数据报
- 广播接收端编程:接收广播数据报、获取发送者信息
- 广播的局限性与注意事项:
- 广播数据包会被路由器阻挡(默认不转发)
- 大量广播可能造成广播风暴
- 多宿主机上的广播问题
- 广播与单播的性能对比:何时使用广播而非单播
学习目标:学完第二十章后,你将能够——
- 理解广播地址格式和使用场景
- 正确设置
SO_BROADCAST选项发送广播数据报 - 编写简单的广播发送和接收程序
- 理解广播的局限性以及何时使用广播
- 在多宿主机上正确处理广播数据
敬请期待!
参考资料
- W. Richard Stevens, Bill Fenner, Andrew M. Rudoff. 《UNIX网络编程 卷1:套接字联网API(第3版)》. 北京:人民邮电出版社
- UNIX网络编程卷一 学习笔记 第十九章 密钥管理套接字,CSDN
- Linux——密钥管理Socket,CSDN,https://blog.csdn.net/firo_baidu/article/details/6147596
- UNP总结 Chapter 18~21 路由套接字、密钥管理套接字、广播、多播,博客园,https://www.cnblogs.com/biyeymyhjob/archive/2012/08/07/2626841.html
- pf_key(7P) man page — SunOS,https://manpage.me/index.cgi?q=pf_key&sektion=7P
- pf_key(4P) man page — OmniOS,https://man.omnios.org/man4p/pf_key
- RFC 2367: PF_KEY Key Management API, Version 2,IETF Datatracker,https://datatracker.ietf.org/doc/html/rfc2367
- Linux内核git: pfkey: Deprecate pfkey,https://git.armlinux.org.uk/cgit/linux-arm.git/commit/?id=xxx
本文为个人学习笔记,仅用于知识分享。如有错误,欢迎指正。
👍🏻 点赞 + 收藏 + 分享,让更多开发者看到这篇深度解析!❤️ 如果觉得有用,请给个赞支持一下作者!


173

被折叠的 条评论
为什么被折叠?



