diff --git a/man/networkctl.xml b/man/networkctl.xml index 561eb93238..b436797999 100644 --- a/man/networkctl.xml +++ b/man/networkctl.xml @@ -287,6 +287,122 @@ + + + dhcp-lease + INTERFACE + CODE:FORMAT + … + + + + Show the DHCP message of the acquired lease (i.e. the received DHCPACK message). Takes an + interface name and optional DHCP option codes. If no option code is specified, both the DHCP + message header and all options are shown. If one or more option codes are specified, only the + specified options are shown. + + When called with the option, the entire DHCP message is shown in + JSON format. In that case, any specified option codes are ignored. + + By default, each option is displayed in a human-readable format, depending on the option. + For example, DNS server addresses are shown as a list of IP addresses (e.g. + 192.0.2.1), and the lease time is shown as a human-readable duration (e.g. + 8h). + + Each option code may optionally be followed by a formatter, separated by a colon (e.g. + 42:address). This can be useful if the default formatting is not appropriate. + + + The following formatters are supported: + + + + + Use the default formatting. + + + + + + Show the raw bytes in hexadecimal, separated by colons. + + + + + + Treat the option as having zero-length data and display yes. + + + + + + Treat the option as a 1-byte boolean and display yes or no. + + + + + + Treat the option as a 1-byte unsigned integer. + + + + + + Treat the option as a 2-byte unsigned integer. + + + + + + Treat the option as a 4-byte time value in seconds and display it as a human-readable duration. + + + + + + Treat the option as a string. + + + + + + Treat the option as one or more IPv4 addresses and display them in human-readable form. + + + + + Produces output similar to: + $ networkctl dhcp-lease eth0 +Header: + KEY VALUE + Hardware Type: ETHER +Hardware Address: 41:42:43:31:32:33 + Client Address: 192.0.2.123 + Server Address: 192.0.2.1 + +Options: +CODE NAME DATA + 1 subnet mask 255.255.255.0 + 3 router 192.0.2.1 + 6 domain name server 192.0.2.1 + 12 hostname test-node + 15 domain name lan + 28 broadcast address 192.0.2.255 + 42 NTP server 192.0.2.11 + 192.0.2.12 + 51 lease time 1d + 53 message type 5 + 54 server identifier 192.0.2.1 + 58 renewal time 11h 5min 38s + 59 rebinding time 20h 5min 38s + 119 domain search hoge.example.com + foo.example.com + + + + + + lldp diff --git a/shell-completion/bash/networkctl b/shell-completion/bash/networkctl index c16768079e..fe186a49a2 100644 --- a/shell-completion/bash/networkctl +++ b/shell-completion/bash/networkctl @@ -51,7 +51,7 @@ _networkctl() { local -A VERBS=( [STANDALONE]='label reload' - [LINKS]='status list lldp delete renew up down forcerenew reconfigure' + [LINKS]='status dhcp-lease list lldp delete renew up down forcerenew reconfigure' [FILES_OR_LINKS]='edit cat' [FILES]='mask unmask' [BOOL]='persistent-storage' diff --git a/shell-completion/zsh/_networkctl b/shell-completion/zsh/_networkctl index cf072c0fcb..c44b346949 100644 --- a/shell-completion/zsh/_networkctl +++ b/shell-completion/zsh/_networkctl @@ -7,6 +7,7 @@ _networkctl_cmds=( 'list:List existing links' 'status:Show information about the specified links' + 'dhcp-lease:Show DHCP lease' 'lldp:Show Link Layer Discovery Protocol status' 'label:Show address labels' 'delete:Delete virtual netdevs' @@ -26,7 +27,7 @@ local -a _links cmd="${${_networkctl_cmds[(r)$words[1]:*]%%:*}}" case $cmd in - (list|status|up|down|cat|edit|lldp|delete|renew|forcerenew|reconfigure) + (list|status|dhcp-lease|up|down|cat|edit|lldp|delete|renew|forcerenew|reconfigure) for link in ${(f)"$(_call_program links networkctl list --no-legend)"}; do _links+=($link[(w)2]:$link); done if [[ -n "$_links" ]]; then _describe -t links 'links' _links $( [[ $cmd == (edit|cat) ]] && print -- -P@ ) diff --git a/src/network/meson.build b/src/network/meson.build index 7370d011d0..0319102492 100644 --- a/src/network/meson.build +++ b/src/network/meson.build @@ -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', diff --git a/src/network/networkctl-dhcp-lease.c b/src/network/networkctl-dhcp-lease.c new file mode 100644 index 0000000000..465bff0979 --- /dev/null +++ b/src/network/networkctl-dhcp-lease.c @@ -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); +} diff --git a/src/network/networkctl-dhcp-lease.h b/src/network/networkctl-dhcp-lease.h new file mode 100644 index 0000000000..f068df3b5c --- /dev/null +++ b/src/network/networkctl-dhcp-lease.h @@ -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); diff --git a/src/network/networkctl.c b/src/network/networkctl.c index bdf487bf2e..bf74f10a4a 100644 --- a/src/network/networkctl.c +++ b/src/network/networkctl.c @@ -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, diff --git a/tools/command_ignorelist b/tools/command_ignorelist index 548acff8bd..cb256d6647 100644 --- a/tools/command_ignorelist +++ b/tools/command_ignorelist @@ -51,6 +51,15 @@ logind.conf.xml ./refsect1[title="Options"]/variablelist/varlistentry[term="Kill logind.conf.xml ./refsect1[title="Options"]/variablelist/varlistentry[term="InhibitDelayMaxSec="] machine-info.xml ./refsect1[title="Options"]/refsect2[title="Machine Information"]/variablelist/varlistentry[term="PRETTY_HOSTNAME="] machine-info.xml ./refsect1[title="Options"]/refsect2[title="Machine Information"]/variablelist/varlistentry[term="ICON_NAME="] +networkctl.xml ./refsect1[title="Commands"]/variablelist/varlistentry[term="\n dhcp-lease\n INTERFACE\n CODE:FORMAT\n …\n "]/listitem/variablelist/varlistentry[term="auto"] +networkctl.xml ./refsect1[title="Commands"]/variablelist/varlistentry[term="\n dhcp-lease\n INTERFACE\n CODE:FORMAT\n …\n "]/listitem/variablelist/varlistentry[term="hex"] +networkctl.xml ./refsect1[title="Commands"]/variablelist/varlistentry[term="\n dhcp-lease\n INTERFACE\n CODE:FORMAT\n …\n "]/listitem/variablelist/varlistentry[term="flag"] +networkctl.xml ./refsect1[title="Commands"]/variablelist/varlistentry[term="\n dhcp-lease\n INTERFACE\n CODE:FORMAT\n …\n "]/listitem/variablelist/varlistentry[term="bool"] +networkctl.xml ./refsect1[title="Commands"]/variablelist/varlistentry[term="\n dhcp-lease\n INTERFACE\n CODE:FORMAT\n …\n "]/listitem/variablelist/varlistentry[term="uint8"] +networkctl.xml ./refsect1[title="Commands"]/variablelist/varlistentry[term="\n dhcp-lease\n INTERFACE\n CODE:FORMAT\n …\n "]/listitem/variablelist/varlistentry[term="uint16"] +networkctl.xml ./refsect1[title="Commands"]/variablelist/varlistentry[term="\n dhcp-lease\n INTERFACE\n CODE:FORMAT\n …\n "]/listitem/variablelist/varlistentry[term="time"] +networkctl.xml ./refsect1[title="Commands"]/variablelist/varlistentry[term="\n dhcp-lease\n INTERFACE\n CODE:FORMAT\n …\n "]/listitem/variablelist/varlistentry[term="string"] +networkctl.xml ./refsect1[title="Commands"]/variablelist/varlistentry[term="\n dhcp-lease\n INTERFACE\n CODE:FORMAT\n …\n "]/listitem/variablelist/varlistentry[term="address"] os-release.xml ./refsect1[title="Options"]/refsect2[title="General information identifying the operating system"]/variablelist/varlistentry[term="NAME="] os-release.xml ./refsect1[title="Options"]/refsect2[title="Information about the version of the operating system"]/variablelist/varlistentry[term="VERSION="] os-release.xml ./refsect1[title="Options"]/refsect2[title="General information identifying the operating system"]/variablelist/varlistentry[term="ID="]