networkctl: introduce 'dhcp-lease' command to dump acquired DHCP lease (#42137)

This commit is contained in:
Yu Watanabe
2026-05-18 01:28:11 +09:00
committed by GitHub
13 changed files with 1465 additions and 2 deletions
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,11 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once
#include "dhcp-message.h"
typedef enum {
DUMP_DHCP_MESSAGE_LEGEND = 1 << 0,
DUMP_DHCP_MESSAGE_FULL = 1 << 1,
} DumpDHCPMessageFlag;
int dump_dhcp_message(sd_dhcp_message *message, char * const *args, DumpDHCPMessageFlag flags);
+1
View File
@@ -4,6 +4,7 @@ libsystemd_network_sources = files(
'arp-util.c',
'dhcp-client-send.c',
'dhcp-message.c',
'dhcp-message-dump.c',
'dhcp-network.c',
'dhcp-option.c',
'dhcp-packet.c',
@@ -7,6 +7,7 @@
#include "alloc-util.h"
#include "dhcp-client-id-internal.h"
#include "dhcp-message.h"
#include "dhcp-message-dump.h"
#include "dhcp-protocol.h"
#include "dhcp-route.h"
#include "dns-packet.h"
@@ -545,6 +546,9 @@ TEST(dhcp_message) {
/* send */
verify_send_udp(m, xid, &hw_addr);
verify_send_raw(m, xid, &hw_addr);
/* dump */
ASSERT_OK(dump_dhcp_message(m, /* args= */ NULL, DUMP_DHCP_MESSAGE_LEGEND | DUMP_DHCP_MESSAGE_FULL));
}
static void test_domains_one(size_t len, const uint8_t *data, char * const *expected) {
@@ -581,6 +585,8 @@ static void test_domains_one(size_t len, const uint8_t *data, char * const *expe
ASSERT_OK(dhcp_message_append_option(m, SD_DHCP_OPTION_SIP_SERVER, len + 1 - (len + 1) / 2, sip + (len + 1) / 2));
ASSERT_OK(dhcp_message_get_option_domains(m, SD_DHCP_OPTION_SIP_SERVER, &strv));
ASSERT_TRUE(strv_equal(strv, expected));
ASSERT_OK(dump_dhcp_message(m, STRV_MAKE("119", "120"), DUMP_DHCP_MESSAGE_LEGEND | DUMP_DHCP_MESSAGE_FULL));
}
static void test_domains_fail(size_t len, const uint8_t *data) {
@@ -804,6 +810,8 @@ TEST(dnr) {
ASSERT_EQ(resolvers[1].port, 33u);
ASSERT_NULL(resolvers[1].dohpath);
ASSERT_OK(dump_dhcp_message(m, STRV_MAKE("162"), DUMP_DHCP_MESSAGE_LEGEND | DUMP_DHCP_MESSAGE_FULL));
/* missing DoH path */
static uint8_t invalid[] = {
/* length */
@@ -875,4 +883,60 @@ TEST(dnr) {
ASSERT_ERROR(dhcp_message_get_option_dnr(m, NULL, NULL), EMSGSIZE);
}
TEST(dump_vendor) {
_cleanup_(sd_dhcp_message_unrefp) sd_dhcp_message *m = NULL;
ASSERT_OK(dhcp_message_new(&m));
/* Vendor Specific Information (43) -- TLV */
static uint8_t option_43[] = {
1, 6, 'm', 'o', 'd', 'e', 'm', '1',
2, 6, 's', 't', 'a', 't', 'u', 's',
3, 6, 1, 2, 3, 4, 5, 6,
};
/* Vendor Class Identifier (60) -- typically string */
static uint8_t option_60[] = {
'n', 'e', 't', 'w', 'o', 'r', 'k', 'd',
};
/* User Class (77) -- length-prefixed data, typically strings */
static uint8_t option_77[] = {
6, 'l', 'a', 'p', 't', 'o', 'p',
4, 'c', 'o', 'r', 'p',
};
/* Vendor-Identifying Vendor Class -- length-prefixed data tagged with enterprise number */
static uint8_t option_124[] = {
0x00, 0x00, 0x00, 0x09, /* enterprise number: 9 */
13,
5, 'c', 'i', 's', 'c', 'o',
6, 'f', 'o', 'o', 'b', 'a', 'r',
0x00, 0x00, 0x11, 0x8b, /* enterprise number: 4491 */
21,
9, 'd', 'o', 'c', 's', 'i', 's', '3', '.', '0',
10, 'e', 'R', 'o', 'u', 't', 'e', 'r', '1', '.', '0',
};
/* Vendor-Identifying Vendor-Specific Information (125) -- sub TLVs with enterprise number */
static uint8_t option_125[] = {
0x00, 0x00, 0x00, 0x09, /* enterprise number: 9 */
12,
1, 4, 'C', 'i', 's', 'c',
2, 4, 'I', 'O', 'S', 'X',
0x00, 0x00, 0x11, 0x8b, /* enterprise number: 4491 */
16,
1, 6, 'm', 'o', 'd', 'e', 'm', '1',
2, 6, 's', 't', 'a', 't', 'u', 's',
};
ASSERT_OK(dhcp_message_append_option(m, 43, ELEMENTSOF(option_43), option_43));
ASSERT_OK(dhcp_message_append_option(m, 60, ELEMENTSOF(option_60), option_60));
ASSERT_OK(dhcp_message_append_option(m, 77, ELEMENTSOF(option_77), option_77));
ASSERT_OK(dhcp_message_append_option(m, 124, ELEMENTSOF(option_124), option_124));
ASSERT_OK(dhcp_message_append_option(m, 125, ELEMENTSOF(option_125), option_125));
ASSERT_OK(dump_dhcp_message(m, STRV_MAKE("43", "60", "77", "124", "125"),
DUMP_DHCP_MESSAGE_LEGEND | DUMP_DHCP_MESSAGE_FULL));
}
DEFINE_TEST_MAIN(LOG_DEBUG);
+1
View File
@@ -128,6 +128,7 @@ networkctl_sources = files(
'networkctl-address-label.c',
'networkctl-config-file.c',
'networkctl-description.c',
'networkctl-dhcp-lease.c',
'networkctl-dump-util.c',
'networkctl-journal.c',
'networkctl-link-info.c',
+67
View File
@@ -0,0 +1,67 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include "sd-json.h"
#include "sd-netlink.h"
#include "sd-varlink.h"
#include "dhcp-message-dump.h"
#include "log.h"
#include "networkctl.h"
#include "networkctl-dhcp-lease.h"
#include "networkctl-link-info.h"
#include "networkctl-util.h"
#include "strv.h"
int verb_dhcp_lease(int argc, char *argv[], uintptr_t _data, void *userdata) {
int r;
/* networkctl dhcp-lease INTERFACE [CODE[:FORMAT] ...] */
assert(argc >= 2);
pager_open(arg_pager_flags);
_cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL;
r = sd_netlink_open(&rtnl);
if (r < 0)
return log_error_errno(r, "Failed to connect to netlink: %m");
_cleanup_(sd_varlink_flush_close_unrefp) sd_varlink *vl = NULL;
r = varlink_connect_networkd(&vl);
if (r < 0)
return r;
const char *ifname = argv[1];
_cleanup_(link_info_array_freep) LinkInfo *link = NULL;
r = acquire_link_info(vl, rtnl, STRV_MAKE(ifname), &link);
if (r < 0)
return r;
if (r == 0)
return -EINVAL; /* already logged in acquire_link_info(). */
if (r > 1)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"Interface name '%s' matches multiple interfaces.", ifname);
if (!link->dhcp_message)
return log_error_errno(SYNTHETIC_ERRNO(ENODATA),
"Interface '%s' does not have DHCPv4 lease.", link->name);
if (sd_json_format_enabled(arg_json_format_flags)) {
_cleanup_(sd_json_variant_unrefp) sd_json_variant *v = NULL;
r = dhcp_message_build_json(link->dhcp_message, &v);
if (r < 0)
return log_error_errno(r, "Failed to build JSON variant from DHCP message: %m");
r = sd_json_variant_dump(v, arg_json_format_flags, /* f= */ NULL, /* prefix= */ NULL);
if (r < 0)
return log_error_errno(r, "Failed to dump JSON variant: %m");
return 0;
}
DumpDHCPMessageFlag flags = 0;
SET_FLAG(flags, DUMP_DHCP_MESSAGE_LEGEND, arg_legend);
SET_FLAG(flags, DUMP_DHCP_MESSAGE_FULL, arg_full);
return dump_dhcp_message(link->dhcp_message, strv_skip(argv, 2), flags);
}
+6
View File
@@ -0,0 +1,6 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once
#include "shared-forward.h"
int verb_dhcp_lease(int argc, char *argv[], uintptr_t _data, void *userdata);
+3
View File
@@ -12,6 +12,7 @@
#include "networkctl.h"
#include "networkctl-address-label.h"
#include "networkctl-config-file.h"
#include "networkctl-dhcp-lease.h"
#include "networkctl-list.h"
#include "networkctl-lldp.h"
#include "networkctl-misc.h"
@@ -42,6 +43,8 @@ VERB_SCOPE(, verb_list_links, "list", "[PATTERN...
"List links");
VERB_SCOPE(, verb_link_status, "status", "[PATTERN...]", VERB_ANY, VERB_ANY, VERB_ONLINE_ONLY,
"Show link status");
VERB_SCOPE(, verb_dhcp_lease, "dhcp-lease", "INTERFACE [CODE[:FORMAT]...]", 2, VERB_ANY, VERB_ONLINE_ONLY,
"Show DHCP lease");
VERB_SCOPE(, verb_link_lldp_status, "lldp", "[PATTERN...]", VERB_ANY, VERB_ANY, 0,
"Show LLDP neighbors");
VERB_SCOPE(, verb_list_address_labels, "label", NULL, 1, 1, 0,