1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2014 Lennart Poettering
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
26 #include "sd-network.h"
35 #include "rtnl-util.h"
36 #include "udev-util.h"
37 #include "hwdb-util.h"
38 #include "arphrd-list.h"
39 #include "local-addresses.h"
40 #include "socket-util.h"
41 #include "ether-addr-util.h"
43 static bool arg_no_pager = false;
44 static bool arg_legend = true;
45 static bool arg_all = false;
47 static void pager_open_if_enabled(void) {
55 static int link_get_type_string(int iftype, struct udev_device *d, char **ret) {
59 if (iftype == ARPHRD_ETHER && d) {
60 const char *devtype, *id = NULL;
61 /* WLANs have iftype ARPHRD_ETHER, but we want
62 * to show a more useful type string for
65 devtype = udev_device_get_devtype(d);
66 if (streq_ptr(devtype, "wlan"))
68 else if (streq_ptr(devtype, "wwan"))
81 t = arphrd_to_name(iftype);
97 typedef struct LinkInfo {
103 static int link_info_compare(const void *a, const void *b) {
104 const LinkInfo *x = a, *y = b;
106 return x->ifindex - y->ifindex;
109 static int decode_and_sort_links(sd_rtnl_message *m, LinkInfo **ret) {
110 _cleanup_free_ LinkInfo *links = NULL;
111 size_t size = 0, c = 0;
115 for (i = m; i; i = sd_rtnl_message_next(i)) {
121 r = sd_rtnl_message_get_type(i, &type);
125 if (type != RTM_NEWLINK)
128 r = sd_rtnl_message_link_get_ifindex(i, &ifindex);
132 r = sd_rtnl_message_read_string(i, IFLA_IFNAME, &name);
136 r = sd_rtnl_message_link_get_type(i, &iftype);
140 if (!GREEDY_REALLOC(links, size, c+1))
143 links[c].name = name;
144 links[c].ifindex = ifindex;
145 links[c].iftype = iftype;
149 qsort_safe(links, c, sizeof(LinkInfo), link_info_compare);
157 static void operational_state_to_color(const char *state, const char **on, const char **off) {
161 if (streq_ptr(state, "routable")) {
162 *on = ansi_highlight_green();
163 *off = ansi_highlight_off();
164 } else if (streq_ptr(state, "degraded")) {
165 *on = ansi_highlight_yellow();
166 *off = ansi_highlight_off();
171 static void setup_state_to_color(const char *state, const char **on, const char **off) {
175 if (streq_ptr(state, "configured")) {
176 *on = ansi_highlight_green();
177 *off = ansi_highlight_off();
178 } else if (streq_ptr(state, "configuring")) {
179 *on = ansi_highlight_yellow();
180 *off = ansi_highlight_off();
181 } else if (streq_ptr(state, "failed") || streq_ptr(state, "linger")) {
182 *on = ansi_highlight_red();
183 *off = ansi_highlight_off();
188 static int list_links(char **args, unsigned n) {
189 _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL, *reply = NULL;
190 _cleanup_udev_unref_ struct udev *udev = NULL;
191 _cleanup_rtnl_unref_ sd_rtnl *rtnl = NULL;
192 _cleanup_free_ LinkInfo *links = NULL;
195 pager_open_if_enabled();
197 r = sd_rtnl_open(&rtnl, 0);
199 return log_error_errno(r, "Failed to connect to netlink: %m");
203 return log_error_errno(errno, "Failed to connect to udev: %m");
205 r = sd_rtnl_message_new_link(rtnl, &req, RTM_GETLINK, 0);
207 return rtnl_log_create_error(r);
209 r = sd_rtnl_message_request_dump(req, true);
211 return rtnl_log_create_error(r);
213 r = sd_rtnl_call(rtnl, req, 0, &reply);
215 return log_error_errno(r, "Failed to enumerate links: %m");
218 printf("%3s %-16s %-18s %-11s %-10s\n", "IDX", "LINK", "TYPE", "OPERATIONAL", "SETUP");
220 c = decode_and_sort_links(reply, &links);
222 return rtnl_log_parse_error(c);
224 for (i = 0; i < c; i++) {
225 _cleanup_free_ char *setup_state = NULL, *operational_state = NULL;
226 _cleanup_udev_device_unref_ struct udev_device *d = NULL;
227 const char *on_color_operational, *off_color_operational,
228 *on_color_setup, *off_color_setup;
229 char devid[2 + DECIMAL_STR_MAX(int)];
230 _cleanup_free_ char *t = NULL;
232 sd_network_link_get_operational_state(links[i].ifindex, &operational_state);
233 operational_state_to_color(operational_state, &on_color_operational, &off_color_operational);
235 sd_network_link_get_setup_state(links[i].ifindex, &setup_state);
236 setup_state_to_color(setup_state, &on_color_setup, &off_color_setup);
238 sprintf(devid, "n%i", links[i].ifindex);
239 d = udev_device_new_from_device_id(udev, devid);
241 link_get_type_string(links[i].iftype, d, &t);
243 printf("%3i %-16s %-18s %s%-11s%s %s%-10s%s\n",
244 links[i].ifindex, links[i].name, strna(t),
245 on_color_operational, strna(operational_state), off_color_operational,
246 on_color_setup, strna(setup_state), off_color_setup);
250 printf("\n%i links listed.\n", c);
255 /* IEEE Organizationally Unique Identifier vendor string */
256 static int ieee_oui(sd_hwdb *hwdb, struct ether_addr *mac, char **ret) {
257 const char *description;
258 char modalias[strlen("OUI:XXYYXXYYXXYY") + 1], *desc;
269 /* skip commonly misused 00:00:00 (Xerox) prefix */
270 if (memcmp(mac, "\0\0\0", 3) == 0)
273 snprintf(modalias, sizeof(modalias), "OUI:" ETHER_ADDR_FORMAT_STR, ETHER_ADDR_FORMAT_VAL(*mac));
275 r = sd_hwdb_get(hwdb, modalias, "ID_OUI_FROM_DATABASE", &description);
279 desc = strdup(description);
288 static int get_gateway_description(
293 union in_addr_union *gateway,
294 char **gateway_description) {
295 _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL, *reply = NULL;
300 assert(ifindex >= 0);
301 assert(family == AF_INET || family == AF_INET6);
303 assert(gateway_description);
305 r = sd_rtnl_message_new_neigh(rtnl, &req, RTM_GETNEIGH, ifindex, family);
309 r = sd_rtnl_message_request_dump(req, true);
313 r = sd_rtnl_call(rtnl, req, 0, &reply);
317 for (m = reply; m; m = sd_rtnl_message_next(m)) {
318 union in_addr_union gw = {};
319 struct ether_addr mac = {};
323 r = sd_rtnl_message_get_errno(m);
325 log_error_errno(r, "got error: %m");
329 r = sd_rtnl_message_get_type(m, &type);
331 log_error_errno(r, "could not get type: %m");
335 if (type != RTM_NEWNEIGH) {
336 log_error("type is not RTM_NEWNEIGH");
340 r = sd_rtnl_message_neigh_get_family(m, &fam);
342 log_error_errno(r, "could not get family: %m");
347 log_error("family is not correct");
351 r = sd_rtnl_message_neigh_get_ifindex(m, &ifi);
353 log_error_errno(r, "could not get ifindex: %m");
357 if (ifindex > 0 && ifi != ifindex)
362 r = sd_rtnl_message_read_in_addr(m, NDA_DST, &gw.in);
368 r = sd_rtnl_message_read_in6_addr(m, NDA_DST, &gw.in6);
377 if (!in_addr_equal(fam, &gw, gateway))
380 r = sd_rtnl_message_read_ether_addr(m, NDA_LLADDR, &mac);
384 r = ieee_oui(hwdb, &mac, gateway_description);
394 static int dump_gateways(
399 _cleanup_free_ struct local_address *local = NULL;
402 n = local_gateways(rtnl, ifindex, AF_UNSPEC, &local);
406 for (i = 0; i < n; i++) {
407 _cleanup_free_ char *gateway = NULL, *description = NULL;
409 r = in_addr_to_string(local[i].family, &local[i].address, &gateway);
413 r = get_gateway_description(rtnl, hwdb, local[i].ifindex, local[i].family, &local[i].address, &description);
415 log_debug_errno(r, "Could not get description of gateway: %m");
418 (int) strlen(prefix),
419 i == 0 ? prefix : "",
423 printf(" (%s)", description);
425 /* Show interface name for the entry if we show
426 * entries for all interfaces */
428 char name[IF_NAMESIZE+1];
430 if (if_indextoname(local[i].ifindex, name)) {
431 fputs(" on ", stdout);
434 printf(" on %%%i", local[i].ifindex);
443 static int dump_addresses(
448 _cleanup_free_ struct local_address *local = NULL;
451 n = local_addresses(rtnl, ifindex, AF_UNSPEC, &local);
455 for (i = 0; i < n; i++) {
456 _cleanup_free_ char *pretty = NULL;
458 r = in_addr_to_string(local[i].family, &local[i].address, &pretty);
463 (int) strlen(prefix),
464 i == 0 ? prefix : "",
468 char name[IF_NAMESIZE+1];
470 if (if_indextoname(local[i].ifindex, name)) {
471 fputs(" on ", stdout);
474 printf(" on %%%i", local[i].ifindex);
483 static void dump_list(const char *prefix, char **l) {
488 (int) strlen(prefix),
489 i == l ? prefix : "",
494 static int link_status_one(
500 _cleanup_strv_free_ char **dns = NULL, **ntp = NULL, **domains = NULL;
501 _cleanup_free_ char *setup_state = NULL, *operational_state = NULL;
502 _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL, *reply = NULL;
503 _cleanup_udev_device_unref_ struct udev_device *d = NULL;
504 char devid[2 + DECIMAL_STR_MAX(int)];
505 _cleanup_free_ char *t = NULL, *network = NULL;
506 const char *driver = NULL, *path = NULL, *vendor = NULL, *model = NULL, *link = NULL;
507 const char *on_color_operational, *off_color_operational,
508 *on_color_setup, *off_color_setup;
519 if (safe_atoi(name, &ifindex) >= 0 && ifindex > 0)
520 r = sd_rtnl_message_new_link(rtnl, &req, RTM_GETLINK, ifindex);
522 r = sd_rtnl_message_new_link(rtnl, &req, RTM_GETLINK, 0);
524 return rtnl_log_create_error(r);
526 r = sd_rtnl_message_append_string(req, IFLA_IFNAME, name);
530 return rtnl_log_create_error(r);
532 r = sd_rtnl_call(rtnl, req, 0, &reply);
534 return log_error_errno(r, "Failed to query link: %m");
536 r = sd_rtnl_message_link_get_ifindex(reply, &ifindex);
538 return rtnl_log_parse_error(r);
540 r = sd_rtnl_message_read_string(reply, IFLA_IFNAME, &name);
542 return rtnl_log_parse_error(r);
544 r = sd_rtnl_message_link_get_type(reply, &iftype);
546 return rtnl_log_parse_error(r);
548 have_mac = sd_rtnl_message_read_ether_addr(reply, IFLA_ADDRESS, &e) >= 0;
552 bool all_zeroes = true;
554 for (p = (uint8_t*) &e; p < (uint8_t*) &e + sizeof(e); p++)
564 sd_rtnl_message_read_u32(reply, IFLA_MTU, &mtu);
566 sd_network_link_get_operational_state(ifindex, &operational_state);
567 operational_state_to_color(operational_state, &on_color_operational, &off_color_operational);
569 sd_network_link_get_setup_state(ifindex, &setup_state);
570 setup_state_to_color(setup_state, &on_color_setup, &off_color_setup);
572 sd_network_link_get_dns(ifindex, &dns);
573 sd_network_link_get_ntp(ifindex, &ntp);
574 sd_network_link_get_domains(ifindex, &domains);
575 r = sd_network_link_get_wildcard_domain(ifindex);
579 wildcard = strdup("*");
583 if (strv_consume(&domains, wildcard) < 0)
587 sprintf(devid, "n%i", ifindex);
588 d = udev_device_new_from_device_id(udev, devid);
590 link = udev_device_get_property_value(d, "ID_NET_LINK_FILE");
591 driver = udev_device_get_property_value(d, "ID_NET_DRIVER");
592 path = udev_device_get_property_value(d, "ID_PATH");
594 vendor = udev_device_get_property_value(d, "ID_VENDOR_FROM_DATABASE");
596 vendor = udev_device_get_property_value(d, "ID_VENDOR");
598 model = udev_device_get_property_value(d, "ID_MODEL_FROM_DATABASE");
600 model = udev_device_get_property_value(d, "ID_MODEL");
603 link_get_type_string(iftype, d, &t);
605 sd_network_link_get_network_file(ifindex, &network);
607 printf("%s%s%s %i: %s\n", on_color_operational, draw_special_char(DRAW_BLACK_CIRCLE), off_color_operational, ifindex, name);
609 printf(" Link File: %s\n"
612 " State: %s%s%s (%s%s%s)\n",
616 on_color_operational, strna(operational_state), off_color_operational,
617 on_color_setup, strna(setup_state), off_color_setup);
620 printf(" Path: %s\n", path);
622 printf(" Driver: %s\n", driver);
624 printf(" Vendor: %s\n", vendor);
626 printf(" Model: %s\n", model);
629 _cleanup_free_ char *description = NULL;
630 char ea[ETHER_ADDR_TO_STRING_MAX];
632 ieee_oui(hwdb, &e, &description);
635 printf(" HW Address: %s (%s)\n", ether_addr_to_string(&e, ea), description);
637 printf(" HW Address: %s\n", ether_addr_to_string(&e, ea));
641 printf(" MTU: %u\n", mtu);
643 dump_addresses(rtnl, " Address: ", ifindex);
644 dump_gateways(rtnl, hwdb, " Gateway: ", ifindex);
646 if (!strv_isempty(dns))
647 dump_list(" DNS: ", dns);
648 if (!strv_isempty(domains))
649 dump_list(" Domain: ", domains);
650 if (!strv_isempty(ntp))
651 dump_list(" NTP: ", ntp);
656 static int link_status(char **args, unsigned n) {
657 _cleanup_hwdb_unref_ sd_hwdb *hwdb = NULL;
658 _cleanup_udev_unref_ struct udev *udev = NULL;
659 _cleanup_rtnl_unref_ sd_rtnl *rtnl = NULL;
663 r = sd_rtnl_open(&rtnl, 0);
665 return log_error_errno(r, "Failed to connect to netlink: %m");
669 return log_error_errno(errno, "Failed to connect to udev: %m");
671 r = sd_hwdb_new(&hwdb);
673 log_debug_errno(r, "Failed to open hardware database: %m");
675 if (n <= 1 && !arg_all) {
676 _cleanup_free_ char *operational_state = NULL;
677 _cleanup_strv_free_ char **dns = NULL, **ntp = NULL, **domains = NULL;
678 const char *on_color_operational, *off_color_operational;
680 sd_network_get_operational_state(&operational_state);
681 operational_state_to_color(operational_state, &on_color_operational, &off_color_operational);
683 printf("%s%s%s State: %s%s%s\n",
684 on_color_operational, draw_special_char(DRAW_BLACK_CIRCLE), off_color_operational,
685 on_color_operational, strna(operational_state), off_color_operational);
687 dump_addresses(rtnl, " Address: ", 0);
688 dump_gateways(rtnl, hwdb, " Gateway: ", 0);
690 sd_network_get_dns(&dns);
691 if (!strv_isempty(dns))
692 dump_list(" DNS: ", dns);
694 sd_network_get_domains(&domains);
695 if (!strv_isempty(domains))
696 dump_list(" Domain: ", domains);
698 sd_network_get_ntp(&ntp);
699 if (!strv_isempty(ntp))
700 dump_list(" NTP: ", ntp);
705 pager_open_if_enabled();
708 _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL, *reply = NULL;
709 _cleanup_free_ LinkInfo *links = NULL;
712 r = sd_rtnl_message_new_link(rtnl, &req, RTM_GETLINK, 0);
714 return rtnl_log_create_error(r);
716 r = sd_rtnl_message_request_dump(req, true);
718 return rtnl_log_create_error(r);
720 r = sd_rtnl_call(rtnl, req, 0, &reply);
722 return log_error_errno(r, "Failed to enumerate links: %m");
724 c = decode_and_sort_links(reply, &links);
726 return rtnl_log_parse_error(c);
728 for (i = 0; i < c; i++) {
732 link_status_one(rtnl, udev, hwdb, links[i].name);
735 STRV_FOREACH(name, args + 1) {
739 link_status_one(rtnl, udev, hwdb, *name);
746 static void help(void) {
747 printf("%s [OPTIONS...]\n\n"
748 "Query and control the networking subsystem.\n\n"
749 " -h --help Show this help\n"
750 " --version Show package version\n"
751 " --no-pager Do not pipe output into a pager\n"
752 " --no-legend Do not show the headers and footers\n"
753 " -a --all Show status for all links\n\n"
756 " status LINK Show link status\n"
757 , program_invocation_short_name);
760 static int parse_argv(int argc, char *argv[]) {
768 static const struct option options[] = {
769 { "help", no_argument, NULL, 'h' },
770 { "version", no_argument, NULL, ARG_VERSION },
771 { "no-pager", no_argument, NULL, ARG_NO_PAGER },
772 { "no-legend", no_argument, NULL, ARG_NO_LEGEND },
773 { "all", no_argument, NULL, 'a' },
782 while ((c = getopt_long(argc, argv, "ha", options, NULL)) >= 0) {
791 puts(PACKAGE_STRING);
792 puts(SYSTEMD_FEATURES);
811 assert_not_reached("Unhandled option");
818 static int networkctl_main(int argc, char *argv[]) {
820 static const struct {
828 int (* const dispatch)(char **args, unsigned n);
830 { "list", LESS, 1, list_links },
831 { "status", MORE, 1, link_status },
840 left = argc - optind;
843 /* Special rule: no arguments means "list" */
846 if (streq(argv[optind], "help")) {
851 for (i = 0; i < ELEMENTSOF(verbs); i++)
852 if (streq(argv[optind], verbs[i].verb))
855 if (i >= ELEMENTSOF(verbs)) {
856 log_error("Unknown operation %s", argv[optind]);
861 switch (verbs[i].argc_cmp) {
864 if (left != verbs[i].argc) {
865 log_error("Invalid number of arguments.");
872 if (left < verbs[i].argc) {
873 log_error("Too few arguments.");
880 if (left > verbs[i].argc) {
881 log_error("Too many arguments.");
888 assert_not_reached("Unknown comparison operator.");
891 return verbs[i].dispatch(argv + optind, left);
894 int main(int argc, char* argv[]) {
897 log_parse_environment();
900 r = parse_argv(argc, argv);
904 r = networkctl_main(argc, argv);
909 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;