当充当 DHCPServer 时,systemd-networkd 将 DHCP 租约保存在哪里?

当充当 DHCPServer 时,systemd-networkd 将 DHCP 租约保存在哪里?

我有一个 ubuntu 22.04 系统作为我的家庭路由器/防火墙,我使用 systemd-networkd 作为 LAN 的 DHCP 服务器。我在提供 DNS 的容器中运行 pihole,上游 DNS 是在同一主机上运行的 dnscrypt-proxy 守护程序。我使用 shorewall 进行防火墙/NAT。

我希望 LAN 计算机的主机名映射到 DNS 中的 DHCP 租约,我认为最好的方法是解析 DHCP 租约数据库并附加 /etc/hosts。我不希望 pihole 成为 DHCP 服务器,也不希望 systemd-resolved 成为 DNS 服务器。

当充当 DHCP 服务器时,systemd-networkd 将 DHCP 租约数据库保存在哪里?或者有没有更好的方法来获取 IP 地址 <-> 主机名映射?

LAN接口的配置:

[Match]
MACAddress=aa:bb:cc:dd:ee:ff

[Network]
IPv6PrefixDelegation=dhcpv6
IPv6DuplicateAddressDetection=1
IPv6PrivacyExtensions=yes
LinkLocalAddressing=ipv6
Address=10.100.10.1/24
DNS=10.100.10.1
DHCPServer=yes
IPv6Token=::1
IPv6SendRA=yes
DHCPv6PrefixDelegation=yes

[DHCPv6PrefixDelegation]
SubnetId=2
Assign=yes

[IPv6PrefixDelegation]
RouterLifetimeSec=900
EmitDNS=yes
DNS=_link_local

[DHCPServer]
EmitDNS=yes
DNS=10.100.10.1
EmitNTP=yes
NTP=10.100.10.1

答案1

systemd-networkd 应将租约信息存储在 /run/systemd/netif/leases/ 下

答案2

总结:需要使用DBus来获取属性。

此处接受的答案是不正确的;给出的答案是针对 DHCP客户租约(从另一个 DHCP 服务器接收)。

networkctl配置报告Offered DHCP leases时的DHCPServer=yes源代码链接https://github.com/systemd/systemd/blob/fafded0ce0902e948cdeeaa6a12609a28d9c3ded/src/network/networkctl.c#L2339

要得到全部租约并仅隔离 IP 地址:

$ if=manage; \
  link_id="$(ip --oneline link show dev "$if" | cut -f 1 -d:)"; \
  busctl -j get-property org.freedesktop.network1 \
   "/org/freedesktop/network1/link/${link_id}" \
   org.freedesktop.network1.DHCPServer \
   Leases \
  | jq -r '"\(.data[][2][0]).\(.data[][2][1]).\(.data[][2][2]).\(.data[][2][3])"'
10.254.99.141

如果有多个租约,那么将返回多个结果;在这种情况下,需要进行一些更复杂的过滤,以报告客户端的 MAC 地址,从而识别正确的租约:

$ if=manage; \
  link_id="$(ip --oneline link show dev "$if" | cut -f 1 -d:)"; \
  eval "$( \
   busctl -j get-property org.freedesktop.network1 \
   "/org/freedesktop/network1/link/${link_id}" \
   org.freedesktop.network1.DHCPServer \
   Leases \
  | jq -r '[ "printf", "%d.%d.%d.%d %02X:%02X:%02X:%02X:%02X:%02X\\n", \ 
    .data[][2][0], .data[][2][1], .data[][2][2], .data[][2][3], \
    .data[][1][1], .data[][1][2], .data[][1][3], .data[][1][4], .data[][1][5], .data[][1][6] \
           ] | @sh' \
  )"
10.254.99.141 98:DA:C4:C2:EE:80

这可以通过几项更改扩展到远程工作:使用 ssh 来“获取”链接 ID,并添加busctl --host

$ if=manage; host="apu2.local"; \
  link_id="$(ssh "$host" ip --oneline link show dev "$if" | cut -f 1 -d:)"; \
 eval "$( \
  busctl --host "$host" -j get-property org.freedesktop.network1 \
  "/org/freedesktop/network1/link/${link_id}" \
  org.freedesktop.network1.DHCPServer \
  Leases \
 | jq -r '[ "printf", "%d.%d.%d.%d %02X:%02X:%02X:%02X:%02X:%02X\\n", \ 
   .data[][2][0], .data[][2][1], .data[][2][2], .data[][2][3], \
   .data[][1][1], .data[][1][2], .data[][1][3], .data[][1][4], .data[][1][5], .data[][1][6] \
          ] | @sh' \
 )"
10.254.99.141 98:DA:C4:C2:EE:80

答案3

此答案基于@ImproviseAdaptOvercome 的回答但使用较低的嵌套级别,因此希望更容易阅读和粘贴而没有引用问题。

link_id="$(ip --oneline link show dev "$iface" | cut -f 1 -d:)"
busctl -j get-property org.freedesktop.network1 "/org/freedesktop/network1/link/$link_id" org.freedesktop.network1.DHCPServer Leases \
    | jq -r 'def bytehex:
        [(./16|floor), .%16] | map(if . < 10 then 48 + . else . + 87 end) | implode;
    def formatentry:
        (.[2]|map(tostring)|join(".")) as $ip" | (.[1][1:]|map(bytehex)|join(":")) as $mac | \($ip) \($mac)";
    .data[] | formatentry'

它使用 purejq来格式化结果:bytehex将整数转换为十六进制,并将formatentry每条记录转换为字符串。可以轻松更改输出格式以供后续处理。

相关内容