systemd-resolved DNS 解析模块深度分析


  团队博客: 汽车电子社区


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 协议特性对比

特性LLMNRmDNS
端口53555353
地址224.0.0.252/FF02::1:3224.0.0.251/FF02::FB
RFCRFC 4795RFC 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 解析服务的最佳实践,其架构设计和实现细节都值得深入研究和学习。

### 解决 Kali Linux 中 `systemd-resolved` 服务无法停止和禁用的问题 在 Kali Linux 系统中,如果遇到 `systemd-resolved` 服务无法正常加载或者不存在的情况,同时伴随 DNS 解析失败问题,可以通过以下方法逐一排查并解决问题。 #### 1. 检查 `systemd-resolved` 的状态 运行以下命令来确认 `systemd-resolved` 当前的状态: ```bash sudo systemctl status systemd-resolved ``` 如果返回提示类似于 “Unit systemd-resolved.service could not be found.” 则说明该服务可能已被移除或从未安装。这种情况下可以直接跳至其他替代方案[^2]。 #### 2. 安装缺失的服务组件(必要时) 假如发现确实缺少必要的软件包,则需要重新安装它们以恢复功能支持: ```bash sudo apt update && sudo apt install --reinstall systemd-resolved libnss-resolve ``` #### 3. 创建符号链接修复 `/etc/resolv.conf` 即使启用了 `systemd-resolved`,但如果默认的 `/etc/resolv.conf` 被覆盖成静态文件而非指向实际数据源的话也会引发冲突。因此建议建立正确的软连接关系以便实时同步更新后的DNS记录: ```bash sudo rm -f /etc/resolv.conf # 删除现有的 resolv.conf 文件(如果是硬拷贝形式) sudo ln -sf /run/systemd/resolve/stub-resolv.conf /etc/resolv.conf # 建立新的符号链接到 stub-resolv.conf ``` #### 4. 配置 NetworkManager 使用自定义 DNS 为了防止未来再次发生类似情况,在图形界面环境下推荐通过 GUI 工具调整网络参数;而在纯命令行模式下则修改对应配置文档实现相同效果。例如编辑 Eth0 接口的相关设定: ```bash sudo nano /etc/NetworkManager/conf.d/dns-servers.conf ``` 追加下面的内容指定首选及备用的名字服务器地址列表: ```plaintext [main] dns=8.8.8.8;8.8.4.4; ``` 随后刷新整个系统的网络状况使其生效: ```bash sudo systemctl restart NetworkManager ``` #### 5. 强制清除缓存重试解析操作 最后尝试清理本地存储的历史查询结果后再发起新一轮测试请求确保彻底排除残留影响因素的可能性: ```bash sudo systemd-resolve --flush-caches # 清理所有类型的高速缓冲区内容 ping -c 4 www.baidu.com # 实际检验能否成功抵达目的地 ``` --- ### 总结 经过上述一系列措施后应该已经妥善解决了关于 `systemd-resolved` 不可用以及由此衍生出来的域名转换障碍等问题。当然具体实施过程中还需密切留意每步反馈信息及时作出相应调整优化直至完全恢复正常运作为止[^3]。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值