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/>.
25 #include "sd-network.h"
32 #include "rtnl-util.h"
33 #include "udev-util.h"
34 #include "arphrd-list.h"
35 #include "local-addresses.h"
36 #include "socket-util.h"
38 static bool arg_no_pager = false;
39 static bool arg_legend = true;
40 static bool arg_all = false;
42 static void pager_open_if_enabled(void) {
50 static int link_get_type_string(int iftype, struct udev_device *d, char **ret) {
54 if (iftype == ARPHRD_ETHER && d) {
55 const char *devtype, *id = NULL;
56 /* WLANs have iftype ARPHRD_ETHER, but we want
57 * to show a more useful type string for
60 devtype = udev_device_get_devtype(d);
61 if (streq_ptr(devtype, "wlan"))
63 else if (streq_ptr(devtype, "wwan"))
76 t = arphrd_to_name(iftype);
92 typedef struct LinkInfo {
98 static int link_info_compare(const void *a, const void *b) {
99 const LinkInfo *x = a, *y = b;
101 return x->ifindex - y->ifindex;
104 static int decode_and_sort_links(sd_rtnl_message *m, LinkInfo **ret) {
105 _cleanup_free_ LinkInfo *links = NULL;
106 size_t size = 0, c = 0;
110 for (i = m; i; i = sd_rtnl_message_next(i)) {
116 r = sd_rtnl_message_get_type(i, &type);
120 if (type != RTM_NEWLINK)
123 r = sd_rtnl_message_link_get_ifindex(i, &ifindex);
127 r = sd_rtnl_message_read_string(i, IFLA_IFNAME, &name);
131 r = sd_rtnl_message_link_get_type(i, &iftype);
135 if (!GREEDY_REALLOC(links, size, c+1))
138 links[c].name = name;
139 links[c].ifindex = ifindex;
140 links[c].iftype = iftype;
144 qsort_safe(links, c, sizeof(LinkInfo), link_info_compare);
152 static void operational_state_to_color(const char *state, const char **on, const char **off) {
156 if (streq_ptr(state, "routable")) {
157 *on = ansi_highlight_green();
158 *off = ansi_highlight_off();
159 } else if (streq_ptr(state, "degraded")) {
160 *on = ansi_highlight_yellow();
161 *off = ansi_highlight_off();
166 static void setup_state_to_color(const char *state, const char **on, const char **off) {
170 if (streq_ptr(state, "configured")) {
171 *on = ansi_highlight_green();
172 *off = ansi_highlight_off();
173 } else if (streq_ptr(state, "configuring")) {
174 *on = ansi_highlight_yellow();
175 *off = ansi_highlight_off();
176 } else if (streq_ptr(state, "failed") || streq_ptr(state, "linger")) {
177 *on = ansi_highlight_red();
178 *off = ansi_highlight_off();
183 static int list_links(char **args, unsigned n) {
184 _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL, *reply = NULL;
185 _cleanup_udev_unref_ struct udev *udev = NULL;
186 _cleanup_rtnl_unref_ sd_rtnl *rtnl = NULL;
187 _cleanup_free_ LinkInfo *links = NULL;
190 pager_open_if_enabled();
192 r = sd_rtnl_open(&rtnl, 0);
194 return log_error_errno(r, "Failed to connect to netlink: %m");
198 return log_error_errno(errno, "Failed to connect to udev: %m");
200 r = sd_rtnl_message_new_link(rtnl, &req, RTM_GETLINK, 0);
202 return rtnl_log_create_error(r);
204 r = sd_rtnl_message_request_dump(req, true);
206 return rtnl_log_create_error(r);
208 r = sd_rtnl_call(rtnl, req, 0, &reply);
210 return log_error_errno(r, "Failed to enumerate links: %m");
213 printf("%3s %-16s %-18s %-11s %-10s\n", "IDX", "LINK", "TYPE", "OPERATIONAL", "SETUP");
215 c = decode_and_sort_links(reply, &links);
217 return rtnl_log_parse_error(c);
219 for (i = 0; i < c; i++) {
220 _cleanup_free_ char *setup_state = NULL, *operational_state = NULL;
221 _cleanup_udev_device_unref_ struct udev_device *d = NULL;
222 const char *on_color_operational, *off_color_operational,
223 *on_color_setup, *off_color_setup;
224 char devid[2 + DECIMAL_STR_MAX(int)];
225 _cleanup_free_ char *t = NULL;
227 sd_network_link_get_operational_state(links[i].ifindex, &operational_state);
228 operational_state_to_color(operational_state, &on_color_operational, &off_color_operational);
230 sd_network_link_get_setup_state(links[i].ifindex, &setup_state);
231 setup_state_to_color(setup_state, &on_color_setup, &off_color_setup);
233 sprintf(devid, "n%i", links[i].ifindex);
234 d = udev_device_new_from_device_id(udev, devid);
236 link_get_type_string(links[i].iftype, d, &t);
238 printf("%3i %-16s %-18s %s%-11s%s %s%-10s%s\n",
239 links[i].ifindex, links[i].name, strna(t),
240 on_color_operational, strna(operational_state), off_color_operational,
241 on_color_setup, strna(setup_state), off_color_setup);
245 printf("\n%i links listed.\n", c);
250 /* IEEE Organizationally Unique Identifier vendor string */
251 static int ieee_oui(struct udev_hwdb *hwdb, struct ether_addr *mac, char **ret) {
252 struct udev_list_entry *entry;
256 /* skip commonly misused 00:00:00 (Xerox) prefix */
257 if (memcmp(mac, "\0\0\0", 3) == 0)
260 snprintf(str, sizeof(str), "OUI:%02X%02X%02X%02X%02X%02X", mac->ether_addr_octet[0], mac->ether_addr_octet[1], mac->ether_addr_octet[2],
261 mac->ether_addr_octet[3], mac->ether_addr_octet[4], mac->ether_addr_octet[5]);
263 udev_list_entry_foreach(entry, udev_hwdb_get_properties_list_entry(hwdb, str, 0))
264 if (strcmp(udev_list_entry_get_name(entry), "ID_OUI_FROM_DATABASE") == 0) {
265 description = strdup(udev_list_entry_get_value(entry));
276 static int get_gateway_description(sd_rtnl *rtnl, struct udev_hwdb *hwdb, int ifindex, int family,
277 union in_addr_union *gateway, char **gateway_description) {
278 _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL, *reply = NULL;
283 assert(ifindex >= 0);
284 assert(family == AF_INET || family == AF_INET6);
286 assert(gateway_description);
288 r = sd_rtnl_message_new_neigh(rtnl, &req, RTM_GETNEIGH, ifindex, family);
292 r = sd_rtnl_message_request_dump(req, true);
296 r = sd_rtnl_call(rtnl, req, 0, &reply);
300 for (m = reply; m; m = sd_rtnl_message_next(m)) {
301 union in_addr_union gw = {};
302 struct ether_addr mac = {};
306 r = sd_rtnl_message_get_errno(m);
308 log_error_errno(r, "got error: %m");
312 r = sd_rtnl_message_get_type(m, &type);
314 log_error_errno(r, "could not get type: %m");
318 if (type != RTM_NEWNEIGH) {
319 log_error("type is not RTM_NEWNEIGH");
323 r = sd_rtnl_message_neigh_get_family(m, &fam);
325 log_error_errno(r, "could not get family: %m");
330 log_error("family is not correct");
334 r = sd_rtnl_message_neigh_get_ifindex(m, &ifi);
336 log_error_errno(r, "colud not get ifindex: %m");
340 if (ifindex > 0 && ifi != ifindex)
345 r = sd_rtnl_message_read_in_addr(m, NDA_DST, &gw.in);
351 r = sd_rtnl_message_read_in6_addr(m, NDA_DST, &gw.in6);
360 if (!in_addr_equal(fam, &gw, gateway))
363 r = sd_rtnl_message_read_ether_addr(m, NDA_LLADDR, &mac);
367 r = ieee_oui(hwdb, &mac, gateway_description);
377 static int dump_gateways(sd_rtnl *rtnl, struct udev_hwdb *hwdb, const char *prefix, int ifindex) {
378 _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL, *reply = NULL;
384 assert(ifindex >= 0);
386 r = sd_rtnl_message_new_route(rtnl, &req, RTM_GETROUTE, AF_UNSPEC, RTPROT_UNSPEC);
390 r = sd_rtnl_message_request_dump(req, true);
394 r = sd_rtnl_call(rtnl, req, 0, &reply);
398 for (m = reply; m; m = sd_rtnl_message_next(m)) {
399 _cleanup_free_ char *gateway = NULL, *gateway_description = NULL;
400 union in_addr_union gw = {};
405 r = sd_rtnl_message_get_errno(m);
407 log_error_errno(r, "got error: %m");
411 r = sd_rtnl_message_get_type(m, &type);
413 log_error_errno(r, "could not get type: %m");
417 if (type != RTM_NEWROUTE) {
418 log_error("type is not RTM_NEWROUTE");
422 r = sd_rtnl_message_route_get_family(m, &family);
424 log_error_errno(r, "could not get family: %m");
428 r = sd_rtnl_message_read_u32(m, RTA_OIF, &ifi);
430 log_error_errno(r, "colud not get RTA_OIF: %m");
434 if (ifindex > 0 && ifi != (unsigned) ifindex)
439 r = sd_rtnl_message_read_in_addr(m, RTA_GATEWAY, &gw.in);
443 r = sd_rtnl_message_read_in_addr(m, RTA_DST, NULL);
447 r = sd_rtnl_message_read_in_addr(m, RTA_SRC, NULL);
453 r = sd_rtnl_message_read_in6_addr(m, RTA_GATEWAY, &gw.in6);
457 r = sd_rtnl_message_read_in6_addr(m, RTA_DST, NULL);
461 r = sd_rtnl_message_read_in6_addr(m, RTA_SRC, NULL);
470 r = in_addr_to_string(family, &gw, &gateway);
474 r = get_gateway_description(rtnl, hwdb, ifi, family, &gw, &gateway_description);
476 log_debug("could not get description of gateway: %s", strerror(-r));
478 if (gateway_description)
479 printf("%*s%s (%s)\n",
480 (int) strlen(prefix),
482 gateway, gateway_description);
485 (int) strlen(prefix),
495 static int dump_addresses(sd_rtnl *rtnl, const char *prefix, int ifindex) {
496 _cleanup_free_ struct local_address *local = NULL;
499 n = local_addresses(rtnl, ifindex, &local);
503 for (i = 0; i < n; i++) {
504 _cleanup_free_ char *pretty = NULL;
506 r = in_addr_to_string(local[i].family, &local[i].address, &pretty);
511 (int) strlen(prefix),
512 i == 0 ? prefix : "",
519 static void dump_list(const char *prefix, char **l) {
524 (int) strlen(prefix),
525 i == l ? prefix : "",
530 static int link_status_one(sd_rtnl *rtnl, struct udev *udev, const char *name) {
531 _cleanup_strv_free_ char **dns = NULL, **ntp = NULL, **domains = NULL;
532 _cleanup_free_ char *setup_state = NULL, *operational_state = NULL, *gateway = NULL, *gateway_description = NULL,
533 *gateway6 = NULL, *gateway6_description = NULL;
534 _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL, *reply = NULL;
535 _cleanup_udev_device_unref_ struct udev_device *d = NULL;
536 _cleanup_udev_hwdb_unref_ struct udev_hwdb *hwdb = NULL;
537 char devid[2 + DECIMAL_STR_MAX(int)];
538 _cleanup_free_ char *t = NULL, *network = NULL;
539 const char *driver = NULL, *path = NULL, *vendor = NULL, *model = NULL, *link = NULL;
540 const char *on_color_operational, *off_color_operational,
541 *on_color_setup, *off_color_setup;
552 if (safe_atoi(name, &ifindex) >= 0 && ifindex > 0)
553 r = sd_rtnl_message_new_link(rtnl, &req, RTM_GETLINK, ifindex);
555 r = sd_rtnl_message_new_link(rtnl, &req, RTM_GETLINK, 0);
557 return rtnl_log_create_error(r);
559 r = sd_rtnl_message_append_string(req, IFLA_IFNAME, name);
563 return rtnl_log_create_error(r);
565 r = sd_rtnl_call(rtnl, req, 0, &reply);
567 return log_error_errno(r, "Failed to query link: %m");
569 r = sd_rtnl_message_link_get_ifindex(reply, &ifindex);
571 return rtnl_log_parse_error(r);
573 r = sd_rtnl_message_read_string(reply, IFLA_IFNAME, &name);
575 return rtnl_log_parse_error(r);
577 r = sd_rtnl_message_link_get_type(reply, &iftype);
579 return rtnl_log_parse_error(r);
581 have_mac = sd_rtnl_message_read_ether_addr(reply, IFLA_ADDRESS, &e) >= 0;
585 bool all_zeroes = true;
587 for (p = (uint8_t*) &e; p < (uint8_t*) &e + sizeof(e); p++)
597 sd_rtnl_message_read_u32(reply, IFLA_MTU, &mtu);
599 sd_network_link_get_operational_state(ifindex, &operational_state);
600 operational_state_to_color(operational_state, &on_color_operational, &off_color_operational);
602 sd_network_link_get_setup_state(ifindex, &setup_state);
603 setup_state_to_color(setup_state, &on_color_setup, &off_color_setup);
605 sd_network_link_get_dns(ifindex, &dns);
606 sd_network_link_get_ntp(ifindex, &ntp);
607 sd_network_link_get_domains(ifindex, &domains);
608 r = sd_network_link_get_wildcard_domain(ifindex);
612 wildcard = strdup("*");
616 if (strv_consume(&domains, wildcard) < 0)
620 sprintf(devid, "n%i", ifindex);
621 d = udev_device_new_from_device_id(udev, devid);
623 link_get_type_string(iftype, d, &t);
626 link = udev_device_get_property_value(d, "ID_NET_LINK_FILE");
627 driver = udev_device_get_property_value(d, "ID_NET_DRIVER");
628 path = udev_device_get_property_value(d, "ID_PATH");
630 vendor = udev_device_get_property_value(d, "ID_VENDOR_FROM_DATABASE");
632 vendor = udev_device_get_property_value(d, "ID_VENDOR");
634 model = udev_device_get_property_value(d, "ID_MODEL_FROM_DATABASE");
636 model = udev_device_get_property_value(d, "ID_MODEL");
639 sd_network_link_get_network_file(ifindex, &network);
641 printf("%s%s%s %i: %s\n", on_color_operational, draw_special_char(DRAW_BLACK_CIRCLE), off_color_operational, ifindex, name);
643 printf(" Link File: %s\n"
646 " State: %s%s%s (%s%s%s)\n",
650 on_color_operational, strna(operational_state), off_color_operational,
651 on_color_setup, strna(setup_state), off_color_setup);
654 printf(" Path: %s\n", path);
656 printf(" Driver: %s\n", driver);
658 printf(" Vendor: %s\n", vendor);
660 printf(" Model: %s\n", model);
663 char ea[ETHER_ADDR_TO_STRING_MAX];
664 printf(" HW Address: %s\n", ether_addr_to_string(&e, ea));
668 printf(" MTU: %u\n", mtu);
670 hwdb = udev_hwdb_new(udev);
672 dump_gateways(rtnl, hwdb, " Gateway: ", ifindex);
674 dump_addresses(rtnl, " Address: ", ifindex);
676 if (!strv_isempty(dns))
677 dump_list(" DNS: ", dns);
678 if (!strv_isempty(domains))
679 dump_list(" Domain: ", domains);
680 if (!strv_isempty(ntp))
681 dump_list(" NTP: ", ntp);
686 static int link_status(char **args, unsigned n) {
687 _cleanup_udev_unref_ struct udev *udev = NULL;
688 _cleanup_rtnl_unref_ sd_rtnl *rtnl = NULL;
692 r = sd_rtnl_open(&rtnl, 0);
694 return log_error_errno(r, "Failed to connect to netlink: %m");
698 return log_error_errno(errno, "Failed to connect to udev: %m");
700 if (n <= 1 && !arg_all) {
701 _cleanup_free_ char *operational_state = NULL;
702 _cleanup_strv_free_ char **dns = NULL, **ntp = NULL, **domains = NULL;
703 _cleanup_free_ struct local_address *addresses = NULL;
704 const char *on_color_operational, *off_color_operational;
707 sd_network_get_operational_state(&operational_state);
708 operational_state_to_color(operational_state, &on_color_operational, &off_color_operational);
710 printf(" State: %s%s%s\n", on_color_operational, strna(operational_state), off_color_operational);
712 c = local_addresses(rtnl, 0, &addresses);
713 for (i = 0; i < c; i++) {
714 _cleanup_free_ char *pretty = NULL;
716 r = in_addr_to_string(addresses[i].family, &addresses[i].address, &pretty);
721 i > 0 ? "" : "Address:", pretty);
724 sd_network_get_dns(&dns);
725 if (!strv_isempty(dns))
726 dump_list(" DNS: ", dns);
728 sd_network_get_domains(&domains);
729 if (!strv_isempty(domains))
730 dump_list(" Domain: ", domains);
732 sd_network_get_ntp(&ntp);
733 if (!strv_isempty(ntp))
734 dump_list(" NTP: ", ntp);
739 pager_open_if_enabled();
742 _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL, *reply = NULL;
743 _cleanup_free_ LinkInfo *links = NULL;
746 r = sd_rtnl_message_new_link(rtnl, &req, RTM_GETLINK, 0);
748 return rtnl_log_create_error(r);
750 r = sd_rtnl_message_request_dump(req, true);
752 return rtnl_log_create_error(r);
754 r = sd_rtnl_call(rtnl, req, 0, &reply);
756 return log_error_errno(r, "Failed to enumerate links: %m");
758 c = decode_and_sort_links(reply, &links);
760 return rtnl_log_parse_error(c);
762 for (i = 0; i < c; i++) {
766 link_status_one(rtnl, udev, links[i].name);
770 STRV_FOREACH(name, args + 1) {
774 link_status_one(rtnl, udev, *name);
780 static void help(void) {
781 printf("%s [OPTIONS...]\n\n"
782 "Query and control the networking subsystem.\n\n"
783 " -h --help Show this help\n"
784 " --version Show package version\n"
785 " --no-pager Do not pipe output into a pager\n"
786 " --no-legend Do not show the headers and footers\n"
787 " -a --all Show status for all links\n\n"
790 " status LINK Show link status\n"
791 , program_invocation_short_name);
794 static int parse_argv(int argc, char *argv[]) {
802 static const struct option options[] = {
803 { "help", no_argument, NULL, 'h' },
804 { "version", no_argument, NULL, ARG_VERSION },
805 { "no-pager", no_argument, NULL, ARG_NO_PAGER },
806 { "no-legend", no_argument, NULL, ARG_NO_LEGEND },
807 { "all", no_argument, NULL, 'a' },
816 while ((c = getopt_long(argc, argv, "ha", options, NULL)) >= 0) {
825 puts(PACKAGE_STRING);
826 puts(SYSTEMD_FEATURES);
845 assert_not_reached("Unhandled option");
852 static int networkctl_main(int argc, char *argv[]) {
854 static const struct {
862 int (* const dispatch)(char **args, unsigned n);
864 { "list", LESS, 1, list_links },
865 { "status", MORE, 1, link_status },
874 left = argc - optind;
877 /* Special rule: no arguments means "list" */
880 if (streq(argv[optind], "help")) {
885 for (i = 0; i < ELEMENTSOF(verbs); i++)
886 if (streq(argv[optind], verbs[i].verb))
889 if (i >= ELEMENTSOF(verbs)) {
890 log_error("Unknown operation %s", argv[optind]);
895 switch (verbs[i].argc_cmp) {
898 if (left != verbs[i].argc) {
899 log_error("Invalid number of arguments.");
906 if (left < verbs[i].argc) {
907 log_error("Too few arguments.");
914 if (left > verbs[i].argc) {
915 log_error("Too many arguments.");
922 assert_not_reached("Unknown comparison operator.");
925 return verbs[i].dispatch(argv + optind, left);
928 int main(int argc, char* argv[]) {
931 log_parse_environment();
934 r = parse_argv(argc, argv);
938 r = networkctl_main(argc, argv);
943 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;