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"
37 #include "ether-addr-util.h"
39 static bool arg_no_pager
= false;
40 static bool arg_legend
= true;
41 static bool arg_all
= false;
43 static void pager_open_if_enabled(void) {
51 static int link_get_type_string(int iftype
, struct udev_device
*d
, char **ret
) {
55 if (iftype
== ARPHRD_ETHER
&& d
) {
56 const char *devtype
, *id
= NULL
;
57 /* WLANs have iftype ARPHRD_ETHER, but we want
58 * to show a more useful type string for
61 devtype
= udev_device_get_devtype(d
);
62 if (streq_ptr(devtype
, "wlan"))
64 else if (streq_ptr(devtype
, "wwan"))
77 t
= arphrd_to_name(iftype
);
93 typedef struct LinkInfo
{
99 static int link_info_compare(const void *a
, const void *b
) {
100 const LinkInfo
*x
= a
, *y
= b
;
102 return x
->ifindex
- y
->ifindex
;
105 static int decode_and_sort_links(sd_rtnl_message
*m
, LinkInfo
**ret
) {
106 _cleanup_free_ LinkInfo
*links
= NULL
;
107 size_t size
= 0, c
= 0;
111 for (i
= m
; i
; i
= sd_rtnl_message_next(i
)) {
117 r
= sd_rtnl_message_get_type(i
, &type
);
121 if (type
!= RTM_NEWLINK
)
124 r
= sd_rtnl_message_link_get_ifindex(i
, &ifindex
);
128 r
= sd_rtnl_message_read_string(i
, IFLA_IFNAME
, &name
);
132 r
= sd_rtnl_message_link_get_type(i
, &iftype
);
136 if (!GREEDY_REALLOC(links
, size
, c
+1))
139 links
[c
].name
= name
;
140 links
[c
].ifindex
= ifindex
;
141 links
[c
].iftype
= iftype
;
145 qsort_safe(links
, c
, sizeof(LinkInfo
), link_info_compare
);
153 static void operational_state_to_color(const char *state
, const char **on
, const char **off
) {
157 if (streq_ptr(state
, "routable")) {
158 *on
= ansi_highlight_green();
159 *off
= ansi_highlight_off();
160 } else if (streq_ptr(state
, "degraded")) {
161 *on
= ansi_highlight_yellow();
162 *off
= ansi_highlight_off();
167 static void setup_state_to_color(const char *state
, const char **on
, const char **off
) {
171 if (streq_ptr(state
, "configured")) {
172 *on
= ansi_highlight_green();
173 *off
= ansi_highlight_off();
174 } else if (streq_ptr(state
, "configuring")) {
175 *on
= ansi_highlight_yellow();
176 *off
= ansi_highlight_off();
177 } else if (streq_ptr(state
, "failed") || streq_ptr(state
, "linger")) {
178 *on
= ansi_highlight_red();
179 *off
= ansi_highlight_off();
184 static int list_links(char **args
, unsigned n
) {
185 _cleanup_rtnl_message_unref_ sd_rtnl_message
*req
= NULL
, *reply
= NULL
;
186 _cleanup_udev_unref_
struct udev
*udev
= NULL
;
187 _cleanup_rtnl_unref_ sd_rtnl
*rtnl
= NULL
;
188 _cleanup_free_ LinkInfo
*links
= NULL
;
191 pager_open_if_enabled();
193 r
= sd_rtnl_open(&rtnl
, 0);
195 return log_error_errno(r
, "Failed to connect to netlink: %m");
199 return log_error_errno(errno
, "Failed to connect to udev: %m");
201 r
= sd_rtnl_message_new_link(rtnl
, &req
, RTM_GETLINK
, 0);
203 return rtnl_log_create_error(r
);
205 r
= sd_rtnl_message_request_dump(req
, true);
207 return rtnl_log_create_error(r
);
209 r
= sd_rtnl_call(rtnl
, req
, 0, &reply
);
211 return log_error_errno(r
, "Failed to enumerate links: %m");
214 printf("%3s %-16s %-18s %-11s %-10s\n", "IDX", "LINK", "TYPE", "OPERATIONAL", "SETUP");
216 c
= decode_and_sort_links(reply
, &links
);
218 return rtnl_log_parse_error(c
);
220 for (i
= 0; i
< c
; i
++) {
221 _cleanup_free_
char *setup_state
= NULL
, *operational_state
= NULL
;
222 _cleanup_udev_device_unref_
struct udev_device
*d
= NULL
;
223 const char *on_color_operational
, *off_color_operational
,
224 *on_color_setup
, *off_color_setup
;
225 char devid
[2 + DECIMAL_STR_MAX(int)];
226 _cleanup_free_
char *t
= NULL
;
228 sd_network_link_get_operational_state(links
[i
].ifindex
, &operational_state
);
229 operational_state_to_color(operational_state
, &on_color_operational
, &off_color_operational
);
231 sd_network_link_get_setup_state(links
[i
].ifindex
, &setup_state
);
232 setup_state_to_color(setup_state
, &on_color_setup
, &off_color_setup
);
234 sprintf(devid
, "n%i", links
[i
].ifindex
);
235 d
= udev_device_new_from_device_id(udev
, devid
);
237 link_get_type_string(links
[i
].iftype
, d
, &t
);
239 printf("%3i %-16s %-18s %s%-11s%s %s%-10s%s\n",
240 links
[i
].ifindex
, links
[i
].name
, strna(t
),
241 on_color_operational
, strna(operational_state
), off_color_operational
,
242 on_color_setup
, strna(setup_state
), off_color_setup
);
246 printf("\n%i links listed.\n", c
);
251 /* IEEE Organizationally Unique Identifier vendor string */
252 static int ieee_oui(struct udev_hwdb
*hwdb
, struct ether_addr
*mac
, char **ret
) {
253 struct udev_list_entry
*entry
;
255 char str
[strlen("OUI:XXYYXXYYXXYY") + 1];
257 /* skip commonly misused 00:00:00 (Xerox) prefix */
258 if (memcmp(mac
, "\0\0\0", 3) == 0)
261 snprintf(str
, sizeof(str
), "OUI:" ETHER_ADDR_FORMAT_STR
, ETHER_ADDR_FORMAT_VAL(*mac
));
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
, "could 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
, "could 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
;
533 _cleanup_rtnl_message_unref_ sd_rtnl_message
*req
= NULL
, *reply
= NULL
;
534 _cleanup_udev_device_unref_
struct udev_device
*d
= NULL
;
535 _cleanup_udev_hwdb_unref_
struct udev_hwdb
*hwdb
= NULL
;
536 char devid
[2 + DECIMAL_STR_MAX(int)];
537 _cleanup_free_
char *t
= NULL
, *network
= NULL
;
538 const char *driver
= NULL
, *path
= NULL
, *vendor
= NULL
, *model
= NULL
, *link
= NULL
;
539 const char *on_color_operational
, *off_color_operational
,
540 *on_color_setup
, *off_color_setup
;
551 if (safe_atoi(name
, &ifindex
) >= 0 && ifindex
> 0)
552 r
= sd_rtnl_message_new_link(rtnl
, &req
, RTM_GETLINK
, ifindex
);
554 r
= sd_rtnl_message_new_link(rtnl
, &req
, RTM_GETLINK
, 0);
556 return rtnl_log_create_error(r
);
558 r
= sd_rtnl_message_append_string(req
, IFLA_IFNAME
, name
);
562 return rtnl_log_create_error(r
);
564 r
= sd_rtnl_call(rtnl
, req
, 0, &reply
);
566 return log_error_errno(r
, "Failed to query link: %m");
568 r
= sd_rtnl_message_link_get_ifindex(reply
, &ifindex
);
570 return rtnl_log_parse_error(r
);
572 r
= sd_rtnl_message_read_string(reply
, IFLA_IFNAME
, &name
);
574 return rtnl_log_parse_error(r
);
576 r
= sd_rtnl_message_link_get_type(reply
, &iftype
);
578 return rtnl_log_parse_error(r
);
580 have_mac
= sd_rtnl_message_read_ether_addr(reply
, IFLA_ADDRESS
, &e
) >= 0;
584 bool all_zeroes
= true;
586 for (p
= (uint8_t*) &e
; p
< (uint8_t*) &e
+ sizeof(e
); p
++)
596 sd_rtnl_message_read_u32(reply
, IFLA_MTU
, &mtu
);
598 sd_network_link_get_operational_state(ifindex
, &operational_state
);
599 operational_state_to_color(operational_state
, &on_color_operational
, &off_color_operational
);
601 sd_network_link_get_setup_state(ifindex
, &setup_state
);
602 setup_state_to_color(setup_state
, &on_color_setup
, &off_color_setup
);
604 sd_network_link_get_dns(ifindex
, &dns
);
605 sd_network_link_get_ntp(ifindex
, &ntp
);
606 sd_network_link_get_domains(ifindex
, &domains
);
607 r
= sd_network_link_get_wildcard_domain(ifindex
);
611 wildcard
= strdup("*");
615 if (strv_consume(&domains
, wildcard
) < 0)
619 sprintf(devid
, "n%i", ifindex
);
620 d
= udev_device_new_from_device_id(udev
, devid
);
622 link_get_type_string(iftype
, d
, &t
);
625 link
= udev_device_get_property_value(d
, "ID_NET_LINK_FILE");
626 driver
= udev_device_get_property_value(d
, "ID_NET_DRIVER");
627 path
= udev_device_get_property_value(d
, "ID_PATH");
629 vendor
= udev_device_get_property_value(d
, "ID_VENDOR_FROM_DATABASE");
631 vendor
= udev_device_get_property_value(d
, "ID_VENDOR");
633 model
= udev_device_get_property_value(d
, "ID_MODEL_FROM_DATABASE");
635 model
= udev_device_get_property_value(d
, "ID_MODEL");
638 sd_network_link_get_network_file(ifindex
, &network
);
640 printf("%s%s%s %i: %s\n", on_color_operational
, draw_special_char(DRAW_BLACK_CIRCLE
), off_color_operational
, ifindex
, name
);
642 printf(" Link File: %s\n"
645 " State: %s%s%s (%s%s%s)\n",
649 on_color_operational
, strna(operational_state
), off_color_operational
,
650 on_color_setup
, strna(setup_state
), off_color_setup
);
653 printf(" Path: %s\n", path
);
655 printf(" Driver: %s\n", driver
);
657 printf(" Vendor: %s\n", vendor
);
659 printf(" Model: %s\n", model
);
662 char ea
[ETHER_ADDR_TO_STRING_MAX
];
663 printf(" HW Address: %s\n", ether_addr_to_string(&e
, ea
));
667 printf(" MTU: %u\n", mtu
);
669 hwdb
= udev_hwdb_new(udev
);
671 dump_gateways(rtnl
, hwdb
, " Gateway: ", ifindex
);
673 dump_addresses(rtnl
, " Address: ", ifindex
);
675 if (!strv_isempty(dns
))
676 dump_list(" DNS: ", dns
);
677 if (!strv_isempty(domains
))
678 dump_list(" Domain: ", domains
);
679 if (!strv_isempty(ntp
))
680 dump_list(" NTP: ", ntp
);
685 static int link_status(char **args
, unsigned n
) {
686 _cleanup_udev_unref_
struct udev
*udev
= NULL
;
687 _cleanup_rtnl_unref_ sd_rtnl
*rtnl
= NULL
;
691 r
= sd_rtnl_open(&rtnl
, 0);
693 return log_error_errno(r
, "Failed to connect to netlink: %m");
697 return log_error_errno(errno
, "Failed to connect to udev: %m");
699 if (n
<= 1 && !arg_all
) {
700 _cleanup_free_
char *operational_state
= NULL
;
701 _cleanup_strv_free_
char **dns
= NULL
, **ntp
= NULL
, **domains
= NULL
;
702 _cleanup_free_
struct local_address
*addresses
= NULL
;
703 const char *on_color_operational
, *off_color_operational
;
706 sd_network_get_operational_state(&operational_state
);
707 operational_state_to_color(operational_state
, &on_color_operational
, &off_color_operational
);
709 printf(" State: %s%s%s\n", on_color_operational
, strna(operational_state
), off_color_operational
);
711 c
= local_addresses(rtnl
, 0, &addresses
);
712 for (i
= 0; i
< c
; i
++) {
713 _cleanup_free_
char *pretty
= NULL
;
715 r
= in_addr_to_string(addresses
[i
].family
, &addresses
[i
].address
, &pretty
);
720 i
> 0 ? "" : "Address:", pretty
);
723 sd_network_get_dns(&dns
);
724 if (!strv_isempty(dns
))
725 dump_list(" DNS: ", dns
);
727 sd_network_get_domains(&domains
);
728 if (!strv_isempty(domains
))
729 dump_list(" Domain: ", domains
);
731 sd_network_get_ntp(&ntp
);
732 if (!strv_isempty(ntp
))
733 dump_list(" NTP: ", ntp
);
738 pager_open_if_enabled();
741 _cleanup_rtnl_message_unref_ sd_rtnl_message
*req
= NULL
, *reply
= NULL
;
742 _cleanup_free_ LinkInfo
*links
= NULL
;
745 r
= sd_rtnl_message_new_link(rtnl
, &req
, RTM_GETLINK
, 0);
747 return rtnl_log_create_error(r
);
749 r
= sd_rtnl_message_request_dump(req
, true);
751 return rtnl_log_create_error(r
);
753 r
= sd_rtnl_call(rtnl
, req
, 0, &reply
);
755 return log_error_errno(r
, "Failed to enumerate links: %m");
757 c
= decode_and_sort_links(reply
, &links
);
759 return rtnl_log_parse_error(c
);
761 for (i
= 0; i
< c
; i
++) {
765 link_status_one(rtnl
, udev
, links
[i
].name
);
769 STRV_FOREACH(name
, args
+ 1) {
773 link_status_one(rtnl
, udev
, *name
);
779 static void help(void) {
780 printf("%s [OPTIONS...]\n\n"
781 "Query and control the networking subsystem.\n\n"
782 " -h --help Show this help\n"
783 " --version Show package version\n"
784 " --no-pager Do not pipe output into a pager\n"
785 " --no-legend Do not show the headers and footers\n"
786 " -a --all Show status for all links\n\n"
789 " status LINK Show link status\n"
790 , program_invocation_short_name
);
793 static int parse_argv(int argc
, char *argv
[]) {
801 static const struct option options
[] = {
802 { "help", no_argument
, NULL
, 'h' },
803 { "version", no_argument
, NULL
, ARG_VERSION
},
804 { "no-pager", no_argument
, NULL
, ARG_NO_PAGER
},
805 { "no-legend", no_argument
, NULL
, ARG_NO_LEGEND
},
806 { "all", no_argument
, NULL
, 'a' },
815 while ((c
= getopt_long(argc
, argv
, "ha", options
, NULL
)) >= 0) {
824 puts(PACKAGE_STRING
);
825 puts(SYSTEMD_FEATURES
);
844 assert_not_reached("Unhandled option");
851 static int networkctl_main(int argc
, char *argv
[]) {
853 static const struct {
861 int (* const dispatch
)(char **args
, unsigned n
);
863 { "list", LESS
, 1, list_links
},
864 { "status", MORE
, 1, link_status
},
873 left
= argc
- optind
;
876 /* Special rule: no arguments means "list" */
879 if (streq(argv
[optind
], "help")) {
884 for (i
= 0; i
< ELEMENTSOF(verbs
); i
++)
885 if (streq(argv
[optind
], verbs
[i
].verb
))
888 if (i
>= ELEMENTSOF(verbs
)) {
889 log_error("Unknown operation %s", argv
[optind
]);
894 switch (verbs
[i
].argc_cmp
) {
897 if (left
!= verbs
[i
].argc
) {
898 log_error("Invalid number of arguments.");
905 if (left
< verbs
[i
].argc
) {
906 log_error("Too few arguments.");
913 if (left
> verbs
[i
].argc
) {
914 log_error("Too many arguments.");
921 assert_not_reached("Unknown comparison operator.");
924 return verbs
[i
].dispatch(argv
+ optind
, left
);
927 int main(int argc
, char* argv
[]) {
930 log_parse_environment();
933 r
= parse_argv(argc
, argv
);
937 r
= networkctl_main(argc
, argv
);
942 return r
< 0 ? EXIT_FAILURE
: EXIT_SUCCESS
;