文章目录
团队博客: 汽车电子社区
1. 源码结构和文件组织
1.1 核心目录结构
src/resolve/
├── resolved.c # 主守护进程入口点
├── resolved-manager.c/.h # 核心管理器 (78.87 KB)
├── resolved-dns-*.c/.h # DNS 核心组件
│ ├── resolved-dns-cache.c/.h # 缓存系统 (56.13 KB)
│ ├── resolved-dns-query.c/.h # 查询管理 (58.2 KB)
│ ├── resolved-dns-transaction.c/.h # 事务处理 (153.73 KB)
│ ├── resolved-dns-server.c/.h # DNS 服务器管理 (51.71 KB)
│ ├── resolved-dns-scope.c/.h # 作用域管理 (70.45 KB)
│ ├── resolved-dns-stream.c/.h # 流管理 (23.42 KB)
│ ├── resolved-dns-dnssec.c/.h # DNSSEC 验证 (76.74 KB)
│ └── resolved-dns-stub.c/.h # DNS 存根 (55.96 KB)
├── resolved-llmnr.c/.h # LLMNR 支持 (18.25 KB)
├── resolved-mdns.c/.h # mDNS 支持 (26.88 KB)
├── resolved-bus.c/.h # D-Bus 接口 (84.49 KB)
├── resolved-varlink.c/.h # Varlink 接口 (60.81 KB)
├── resolved-link.c/.h # 网络接口管理 (50.49 KB)
└── RFCs # 相关 RFC 文档
1.2 文件功能分类
- 核心管理: resolved.c, resolved-manager.c/h
- DNS 协议: resolved-dns-* 系列文件
- 本地解析: resolved-llmnr.c/h, resolved-mdns.c/h
- 接口层: resolved-bus.c/h, resolved-varlink.c/h
- 网络集成: resolved-link.c/h, resolved-dns-stream.c/h
- 配置管理: resolved-conf.c/h, resolved-resolv-conf.c/h
2. 核心功能和架构设计
2.1 整体架构图
┌─────────────────────────────────────────────────────────────┐
│ Client Applications │
├─────────────────────────────────────────────────────────────┤
│ D-Bus / Varlink Interface │
│ resolved-bus.c / resolved-varlink.c │
├─────────────────────────────────────────────────────────────┤
│ DNS Stub Layer │
│ resolved-dns-stub.c │
├─────────────────────────────────────────────────────────────┤
│ Core DNS Manager │
│ resolved-manager.c │
├─────────────────────────────────────────────────────────────┤
│ Query │Transaction│ Cache │ DNSSEC │ Stream │
│ Management│ Processing│ System │ Validator│ Management │
│ │ │ │ │ │
└───────────┴───────────┴───────────┴───────────┴────────────┘
2.2 Manager 核心结构
typedef struct Manager {
sd_event *event; // 事件循环
// 协议支持配置
ResolveSupport llmnr_support;
ResolveSupport mdns_support;
DnssecMode dnssec_mode;
DnsOverTlsMode dns_over_tls_mode;
DnsCacheMode enable_cache;
// 网络层
Hashmap *links; // 网络接口
sd_netlink *rtnl; // Netlink 连接
sd_network_monitor *network_monitor;
// DNS 查询管理
Hashmap *dns_transactions; // DNS 事务
LIST_HEAD(DnsQuery, dns_queries); // DNS 查询链表
// 缓存和服务器
LIST_HEAD(DnsServer, dns_servers); // DNS 服务器
DnsCache cache; // DNS 缓存
// LLMNR/mDNS 套接字
int llmnr_ipv4_udp_fd, llmnr_ipv6_udp_fd;
int mdns_ipv4_fd, mdns_ipv6_fd;
// D-Bus 和 Varlink
sd_bus *bus;
sd_varlink_server *varlink_server;
} Manager;
3. DNS协议实现
3.1 数据包处理
systemd-resolved 实现了完整的 DNS 协议栈:
// DNS 包结构
typedef struct DnsPacket {
int protocol; // DNS_PROTOCOL_DNS, DNS_PROTOCOL_LLMNR, DNS_PROTOCOL_MDNS
int family; // AF_INET, AF_INET6
int ifindex; // 接口索引
uint16_t id; // DNS ID
union in_addr_union sender; // 发送者地址
union in_addr_union destination; // 目标地址
uint8_t *data; // 原始数据
size_t size; // 数据大小
size_t rindex; // 读取索引
size_t windex; // 写入索引
} DnsPacket;
3.2 流类型和协议支持
typedef enum DnsStreamType {
DNS_STREAM_LOOKUP, // 标准 DNS 查询
DNS_STREAM_LLMNR_SEND, // LLMNR 发送
DNS_STREAM_LLMNR_RECV, // LLMNR 接收
DNS_STREAM_STUB, // DNS 存根
_DNS_STREAM_TYPE_MAX,
} DnsStreamType;
3.3 RFC 兼容性
支持的 RFC 标准:
- RFC 1034/1035: 基础 DNS 协议
- RFC 4795: LLMNR (Link-Local Multicast Name Resolution)
- RFC 6762: mDNS (Multicast DNS)
- RFC 4034/4035: DNSSEC
- RFC 6891: EDNS0
- RFC 7858: DNS over TLS
- RFC 8767: Stale DNS 数据
4. 缓存机制
4.1 缓存架构
typedef struct DnsCache {
Hashmap *by_key; // 按键索引的缓存项
Prioq *by_expiry; // 按过期时间排序的优先队列
unsigned n_hit; // 命中次数
unsigned n_miss; // 未命中次数
} DnsCache;
4.2 缓存项类型
typedef enum DnsCacheItemType {
DNS_CACHE_POSITIVE, // 正向缓存
DNS_CACHE_NODATA, // 无数据缓存
DNS_CACHE_NXDOMAIN, // 域名不存在
DNS_CACHE_RCODE, // 错误代码缓存
} DnsCacheItemType;
4.3 缓存限制和策略
#define CACHE_MAX 4096 // 最大缓存项数
#define CACHE_TTL_MAX_USEC (2 * USEC_PER_HOUR) // 最大 TTL 2小时
#define CACHE_STALE_TTL_MAX_USEC (30 * USEC_PER_SEC) // 过期数据保留 30秒
#define CACHE_TTL_STRANGE_RCODE_USEC (10 * USEC_PER_SEC) // 错误码缓存 10秒
4.4 缓存数据流程
Query → 检查缓存 → [命中] → 返回缓存结果
↓ [未命中]
执行查询 → 存储结果 → 返回结果
5. DNSSEC验证
5.1 DNSSEC 模式
typedef enum DnssecMode {
DNSSEC_NO, // 不验证
DNSSEC_ALLOW_DOWNGRADE, // 允许降级
DNSSEC_YES, // 强制验证
_DNSSEC_MODE_MAX,
} DnssecMode;
5.2 验证流程
// DNSSEC 验证函数
int dnssec_verify_rrset(
DnsResourceRecord *rrset,
DnsAnswer *rrsig,
DnsAnswer *dnskeys,
usec_t timestamp);
// 验证结果
typedef enum DnssecResult {
DNSSEC_VALID, // 验证通过
DNSSEC_INVALID, // 验证失败
DNSSEC_UNSIGNED, // 未签名
DNSSEC_INDETERMINATE, // 不确定
DNSSEC_BOGus, // 伪造
} DnssecResult;
5.3 支持的算法
- RSA/SHA-256 (RFC 5702)
- RSA/SHA-512 (RFC 5702)
- ECDSA P-256/SHA-256 (RFC 6605)
- ECDSA P-384/SHA-384 (RFC 6605)
- Ed25519 (RFC 8080)
5.4 信任锚管理
typedef struct DnsTrustAnchor {
DnsZone zone; // 信任锚区域
char *filename; // 配置文件路径
usec_t last_mtime; // 最后修改时间
} DnsTrustAnchor;
6. LLMNR和mDNS支持
6.1 LLMNR 实现
// LLMNR 特定逻辑
void manager_llmnr_start(Manager *m) {
// 启动 IPv4/IPv6 UDP 和 TCP 监听
manager_llmnr_ipv4_udp_fd(m);
manager_llmnr_ipv6_udp_fd(m);
manager_llmnr_ipv4_tcp_fd(m);
manager_llmnr_ipv6_tcp_fd(m);
}
// RFC 4795 Section 4.1 - 地址比较
if (memcmp(&p->sender, &p->destination, FAMILY_ADDRESS_SIZE(p->family)) >= 0) {
// 地址较大的节点放弃查询
}
6.2 mDNS 实现
// mDNS 缓存刷新处理 (RFC 6762 Section 10.2)
#define CLEAR_CACHE_FLUSH(x) (~MDNS_RR_CACHE_FLUSH_OR_QU & (x))
// mDNS 广播逻辑
int mdns_announce(DnsScope *scope, bool goodbye) {
// 发送启动公告或告别消息
}
6.3 协议特性对比
| 特性 | LLMNR | mDNS |
|---|---|---|
| 端口 | 5355 | 5353 |
| 地址 | 224.0.0.252/FF02::1:3 | 224.0.0.251/FF02::FB |
| RFC | RFC 4795 | RFC 6762 |
| 冲突检测 | 是 | 是 |
| 缓存刷新 | 否 | 是 |
7. D-Bus接口实现
7.1 接口架构
// D-Bus 对象定义
BUS_DEFINE_PROPERTY_GET_ENUM(bus_property_get_resolve_support, resolve_support, ResolveSupport);
// 主要接口方法
static int method_resolve_hostname(sd_bus_message *message, void *userdata, sd_bus_error *error);
static int method_resolve_address(sd_bus_message *message, void *userdata, sd_bus_error *error);
static int method_resolve_service(sd_bus_message *message, void *userdata, sd_bus_error *error);
7.2 查询接口
static int dns_query_new_for_bus(
Manager *m,
DnsQuery **ret,
DnsQuestion *question_utf8,
DnsQuestion *question_idna,
DnsPacket *question_bypass,
int ifindex,
uint64_t flags,
sd_bus_error *error);
7.3 客户端追踪
static int query_on_bus_track(sd_bus_track *t, void *userdata) {
DnsQuery *q = ASSERT_PTR(userdata);
if (!DNS_TRANSACTION_IS_LIVE(q->state))
return 0;
log_debug("Client of active query vanished, aborting query.");
dns_query_complete(q, DNS_TRANSACTION_ABORTED);
return 0;
}
8. 网络集成
8.1 网络接口管理
typedef struct Link {
Manager *manager;
int ifindex; // 接口索引
char *ifname; // 接口名称
// DNS 配置
ResolveSupport llmnr_support; // LLMNR 支持
ResolveSupport mdns_support; // mDNS 支持
DnssecMode dnssec_mode; // DNSSEC 模式
DnsOverTlsMode dns_over_tls_mode; // DNS over TLS 模式
// 服务器和域
LIST_HEAD(DnsServer, dns_servers); // DNS 服务器列表
LIST_HEAD(DnsSearchDomain, search_domains); // 搜索域
// 作用域
LIST_HEAD(DnsScope, dns_scopes); // DNS 作用域
} Link;
8.2 作用域管理
typedef enum DnsScopeOrigin {
DNS_SCOPE_GLOBAL, // 全局 DNS
DNS_SCOPE_LINK, // 链路本地 (LLMNR/mDNS)
DNS_SCOPE_DELEGATE, // 委派域
_DNS_SCOPE_ORIGIN_MAX,
} DnsScopeOrigin;
typedef struct DnsScope {
Manager *manager;
DnsScopeOrigin origin; // 作用域来源
DnsProtocol protocol; // 协议类型
int family; // 地址族
Link *link; // 关联接口
DnsCache cache; // 作用域缓存
DnsZone zone; // 本地区域
} DnsScope;
8.3 服务器特性检测
typedef enum DnsServerFeatureLevel {
DNS_SERVER_FEATURE_LEVEL_TCP, // 基础 TCP
DNS_SERVER_FEATURE_LEVEL_UDP, // UDP 支持
DNS_SERVER_FEATURE_LEVEL_EDNS0, // EDNS0 支持
DNS_SERVER_FEATURE_LEVEL_TLS_PLAIN, // 明文 TLS
DNS_SERVER_FEATURE_LEVEL_DO, // DNSSEC OK
DNS_SERVER_FEATURE_LEVEL_TLS_DO, // TLS + DNSSEC
_DNS_SERVER_FEATURE_LEVEL_MAX,
} DnsServerFeatureLevel;
9. 性能优化
9.1 连接管理
// DNS 流超时配置
#define DNS_STREAM_DEFAULT_TIMEOUT_USEC (10 * USEC_PER_SEC)
#define DNS_STREAM_ESTABLISHED_TIMEOUT_USEC (10 * USEC_PER_SEC)
#define DNS_STREAM_OPPORTUNISTIC_TLS_TIMEOUT_USEC (3 * USEC_PER_SEC)
// 套接字坟场机制
typedef struct SocketGraveyard {
LIST_FIELDS(SocketGraveyard, graveyard);
int fd; // 套接字描述符
usec_t timestamp; // 关闭时间
} SocketGraveyard;
9.2 缓存优化
- 预取: 对即将过期的记录进行预取
- 过期数据保留: RFC 8767 支持,保留过期数据 30 秒
- LRU 淘汰: 基于优先队列的过期时间管理
- 内存限制: 最多 4096 个缓存项
9.3 网络优化
// MTU 自适应
uint32_t manager_find_mtu(Manager *m);
// 拥塞控制
void dns_scope_packet_received(DnsScope *s, usec_t rtt);
void dns_scope_packet_lost(DnsScope *s, usec_t usec);
// 连接复用
DnsStream *dns_stream_ref(DnsStream *s); // TCP 连接复用
9.4 速率限制
typedef struct RateLimit {
unsigned interval; // 时间间隔 (μs)
unsigned burst; // 突发数量
usec_t begin; // 开始时间
unsigned num; // 当前计数
} RateLimit;
10. 安全特性
10.1 权限管理
// 守护进程权限降级
r = drop_privileges(uid, gid,
(UINT64_C(1) << CAP_NET_RAW) | // SO_BINDTODEVICE
(UINT64_C(1) << CAP_NET_BIND_SERVICE)); // 绑定端口 53
10.2 DNS over TLS
#if ENABLE_DNS_OVER_TLS
typedef struct DnsTlsServerData {
SSL_CTX *ssl_ctx; // OpenSSL 上下文
SSL *ssl; // SSL 连接
bool connected; // 连接状态
} DnsTlsServerData;
#endif
10.3 DNSSEC 验证
// 时间偏移限制
#define SKEW_MAX (1*USEC_PER_HOUR + 10*USEC_PER_MINUTE)
// NSEC3 迭代次数限制
#define NSEC3_ITERATIONS_MAX 100
10.4 沙箱和安全策略
- 用户运行: 以 systemd-resolve 用户运行
- 最小权限: 仅保留必要的 CAP_NET_RAW 和 CAP_NET_BIND_SERVICE
- 配置验证: 严格的配置文件解析和验证
- 内存保护: 防御性编程,避免缓冲区溢出
11. 数据流程图
11.1 DNS 查询流程
应用程序请求
↓
[D-Bus/Varlink 接口]
↓
[Manager 分发]
↓
[缓存检查] ────[命中]───→ 返回缓存结果
↓ [未命中]
[Scope 选择] ────→ DNS → DNS 服务器
↓ ↓
[LLMNR/mDNS] ────→ 多播查询
↓
[事务处理]
↓
[DNSSEC 验证]
↓
[缓存存储]
↓
返回结果
11.2 缓存数据流
查询请求 → 检查 by_key hashmap
↓
[未命中] → 执行 DNS 查询
↓
[命中] → 检查 by_expiry 优先队列
↓
[有效] → 返回缓存数据,更新 n_hit
↓
[过期] → 检查 stale_retention 策略
↓
[返回过期数据] ────→ 同时触发后台更新
12. 关键源码分析
12.1 主守护进程 (resolved.c)
static int run(int argc, char *argv[]) {
_cleanup_(manager_freep) Manager *m = NULL;
// 权限降级
if (getuid() == 0) {
r = drop_privileges(uid, gid,
(UINT64_C(1) << CAP_NET_RAW)|
(UINT64_C(1) << CAP_NET_BIND_SERVICE));
}
// 创建管理器
r = manager_new(&m);
r = manager_start(m);
// 运行事件循环
r = sd_event_loop(m->event);
return 0;
}
12.2 事务状态机 (resolved-dns-transaction.c)
typedef enum DnsTransactionState {
DNS_TRANSACTION_NULL, // 初始状态
DNS_TRANSACTION_PENDING, // 待处理
DNS_TRANSACTION_VALIDATING, // DNSSEC 验证中
DNS_TRANSACTION_SUCCESS, // 成功
DNS_TRANSACTION_TIMEOUT, // 超时
DNS_TRANSACTION_DNSSEC_FAILED, // DNSSEC 失败
// ... 其他状态
} DnsTransactionState;
12.3 缓存项管理 (resolved-dns-cache.c)
static DnsCacheItem* dns_cache_item_free(DnsCacheItem *i) {
if (!i)
return NULL;
dns_resource_key_unref(i->key);
dns_resource_record_unref(i->rr);
dns_answer_unref(i->answer);
dns_packet_unref(i->full_packet);
return mfree(i);
}
13. 总结
systemd-resolved 是一个功能完整、性能优化的 DNS 解析器,具有以下特点:
优势
1. 统一管理: 整合 DNS、LLMNR、mDNS 于单一服务
2. 安全可靠: 完整的 DNSSEC 支持,TLS 加密
3. 性能优化: 智能缓存、连接复用、预取机制
4. 现代接口: 同时支持 D-Bus 和 Varlink
5. 灵活配置: 支持多种运行模式和配置选项
技术特色
- RFC 标准完全兼容
- 事件驱动架构
- 模块化设计
- 防御性编程
- 完善的错误处理
适用场景
- 桌面和服务器系统的 DNS 解析
- 需要本地服务发现的网络环境
- 对安全性和性能要求较高的应用
- 需要统一管理多种 DNS 协议的场景
systemd-resolved 代表了现代 Linux 系统中 DNS 解析服务的最佳实践,其架构设计和实现细节都值得深入研究和学习。

859

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



