1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3 * 4 * Copyright (c) 2022 Alexander V. Chernikov <melifaro@FreeBSD.org> 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25 * SUCH DAMAGE. 26 */ 27 28 #define _WANT_IFCAP_BIT_NAMES 29 30 #include <stdio.h> 31 #include <stdlib.h> 32 #include <string.h> 33 #include <stdbool.h> 34 #include <err.h> 35 #include <errno.h> 36 #include <netdb.h> 37 38 #include <sys/bitcount.h> 39 #include <sys/param.h> 40 #include <sys/linker.h> 41 #include <sys/module.h> 42 #include <sys/socket.h> 43 #include <sys/sysctl.h> 44 #include <sys/time.h> 45 #include <sys/types.h> 46 47 #include <netinet/in.h> 48 #include <arpa/inet.h> 49 50 #include <net/ethernet.h> 51 #include <net/if.h> 52 #include <net/if_dl.h> 53 #include <net/if_strings.h> 54 #include <net/if_types.h> 55 #include "ifconfig.h" 56 #include "ifconfig_netlink.h" 57 58 static const char *IFFBITS[] = { 59 "UP", /* 00:0x1 IFF_UP*/ 60 "BROADCAST", /* 01:0x2 IFF_BROADCAST*/ 61 "DEBUG", /* 02:0x4 IFF_DEBUG*/ 62 "LOOPBACK", /* 03:0x8 IFF_LOOPBACK*/ 63 "POINTOPOINT", /* 04:0x10 IFF_POINTOPOINT*/ 64 "NEEDSEPOCH", /* 05:0x20 IFF_NEEDSEPOCH*/ 65 "RUNNING", /* 06:0x40 IFF_DRV_RUNNING*/ 66 "NOARP", /* 07:0x80 IFF_NOARP*/ 67 "PROMISC", /* 08:0x100 IFF_PROMISC*/ 68 "ALLMULTI", /* 09:0x200 IFF_ALLMULTI*/ 69 "DRV_OACTIVE", /* 10:0x400 IFF_DRV_OACTIVE*/ 70 "SIMPLEX", /* 11:0x800 IFF_SIMPLEX*/ 71 "LINK0", /* 12:0x1000 IFF_LINK0*/ 72 "LINK1", /* 13:0x2000 IFF_LINK1*/ 73 "LINK2", /* 14:0x4000 IFF_LINK2*/ 74 "MULTICAST", /* 15:0x8000 IFF_MULTICAST*/ 75 "CANTCONFIG", /* 16:0x10000 IFF_CANTCONFIG*/ 76 "PPROMISC", /* 17:0x20000 IFF_PPROMISC*/ 77 "MONITOR", /* 18:0x40000 IFF_MONITOR*/ 78 "STATICARP", /* 19:0x80000 IFF_STATICARP*/ 79 "STICKYARP", /* 20:0x100000 IFF_STICKYARP*/ 80 "DYING", /* 21:0x200000 IFF_DYING*/ 81 "RENAMING", /* 22:0x400000 IFF_RENAMING*/ 82 "PALLMULTI", /* 23:0x800000 IFF_PALLMULTI*/ 83 "LOWER_UP", /* 24:0x1000000 IFF_NETLINK_1*/ 84 }; 85 86 static void 87 nl_init_socket(struct snl_state *ss) 88 { 89 if (snl_init(ss, NETLINK_ROUTE)) 90 return; 91 92 if (modfind("netlink") == -1 && errno == ENOENT) { 93 /* Try to load */ 94 if (kldload("netlink") == -1) 95 err(1, "netlink is not loaded and load attempt failed"); 96 if (snl_init(ss, NETLINK_ROUTE)) 97 return; 98 } 99 100 err(1, "unable to open netlink socket"); 101 } 102 103 int 104 ifconfig_nl(if_ctx *ctx, int iscreate, 105 const struct afswtch *uafp) 106 { 107 struct snl_state ss = {}; 108 109 nl_init_socket(&ss); 110 ctx->io_ss = &ss; 111 112 int error = ifconfig_ioctl(ctx, iscreate, uafp); 113 114 snl_free(&ss); 115 ctx->io_ss = NULL; 116 117 return (error); 118 } 119 120 struct ifa { 121 struct ifa *next; 122 uint32_t idx; 123 struct snl_parsed_addr addr; 124 }; 125 126 struct iface { 127 struct snl_parsed_link link; 128 struct ifa *ifa; 129 uint32_t ifa_count; 130 uint32_t idx; 131 }; 132 133 struct ifmap { 134 uint32_t size; 135 uint32_t count; 136 struct iface **ifaces; 137 }; 138 139 /* 140 * Returns ifmap ifindex->snl_parsed_link. 141 * Memory is allocated using snl temporary buffers 142 */ 143 static struct ifmap * 144 prepare_ifmap(struct snl_state *ss, const char *ifname) 145 { 146 struct snl_writer nw = {}; 147 148 snl_init_writer(ss, &nw); 149 struct nlmsghdr *hdr = snl_create_msg_request(&nw, RTM_GETLINK); 150 hdr->nlmsg_flags |= NLM_F_DUMP; 151 snl_reserve_msg_object(&nw, struct ifinfomsg); 152 if (ifname != NULL) 153 snl_add_msg_attr_string(&nw, IFLA_IFNAME, ifname); 154 155 if (! (hdr = snl_finalize_msg(&nw)) || !snl_send_message(ss, hdr)) 156 return (NULL); 157 158 uint32_t nlmsg_seq = hdr->nlmsg_seq; 159 struct ifmap *ifmap = snl_allocz(ss, sizeof(*ifmap)); 160 struct snl_errmsg_data e = {}; 161 162 while ((hdr = snl_read_reply_multi(ss, nlmsg_seq, &e)) != NULL) { 163 struct iface *iface = snl_allocz(ss, sizeof(*iface)); 164 165 if (!snl_parse_nlmsg(ss, hdr, &snl_rtm_link_parser, &iface->link)) 166 continue; 167 if (iface->link.ifi_index >= ifmap->size) { 168 size_t new_size = MAX(ifmap->size, 32); 169 170 while (new_size <= iface->link.ifi_index + 1) 171 new_size *= 2; 172 173 struct iface **ifaces= snl_allocz(ss, new_size * sizeof(void *)); 174 memcpy(ifaces, ifmap->ifaces, ifmap->size * sizeof(void *)); 175 ifmap->ifaces = ifaces; 176 ifmap->size = new_size; 177 } 178 ifmap->ifaces[iface->link.ifi_index] = iface; 179 ifmap->count++; 180 iface->idx = ifmap->count; 181 } 182 return (ifmap); 183 } 184 185 uint32_t 186 if_nametoindex_nl(struct snl_state *ss, const char *ifname) 187 { 188 struct snl_writer nw = {}; 189 struct snl_parsed_link_simple link = {}; 190 191 snl_init_writer(ss, &nw); 192 struct nlmsghdr *hdr = snl_create_msg_request(&nw, RTM_GETLINK); 193 snl_reserve_msg_object(&nw, struct ifinfomsg); 194 snl_add_msg_attr_string(&nw, IFLA_IFNAME, ifname); 195 196 if (! (hdr = snl_finalize_msg(&nw)) || !snl_send_message(ss, hdr)) 197 return (0); 198 199 hdr = snl_read_reply(ss, hdr->nlmsg_seq); 200 if (hdr->nlmsg_type != NL_RTM_NEWLINK) 201 return (0); 202 if (!snl_parse_nlmsg(ss, hdr, &snl_rtm_link_parser_simple, &link)) 203 return (0); 204 205 return (link.ifi_index); 206 } 207 208 ifType 209 convert_iftype(ifType iftype) 210 { 211 switch (iftype) { 212 case IFT_IEEE8023ADLAG: 213 return (IFT_ETHER); 214 case IFT_INFINIBANDLAG: 215 return (IFT_INFINIBAND); 216 default: 217 return (iftype); 218 } 219 } 220 221 static void 222 prepare_ifaddrs(struct snl_state *ss, struct ifmap *ifmap) 223 { 224 struct snl_writer nw = {}; 225 226 snl_init_writer(ss, &nw); 227 struct nlmsghdr *hdr = snl_create_msg_request(&nw, RTM_GETADDR); 228 hdr->nlmsg_flags |= NLM_F_DUMP; 229 snl_reserve_msg_object(&nw, struct ifaddrmsg); 230 231 if (! (hdr = snl_finalize_msg(&nw)) || !snl_send_message(ss, hdr)) 232 return; 233 234 uint32_t nlmsg_seq = hdr->nlmsg_seq; 235 struct snl_errmsg_data e = {}; 236 uint32_t count = 0; 237 238 while ((hdr = snl_read_reply_multi(ss, nlmsg_seq, &e)) != NULL) { 239 struct ifa *ifa = snl_allocz(ss, sizeof(*ifa)); 240 241 if (!snl_parse_nlmsg(ss, hdr, &snl_rtm_addr_parser, &ifa->addr)) 242 continue; 243 244 const uint32_t ifindex = ifa->addr.ifa_index; 245 if (ifindex >= ifmap->size || ifmap->ifaces[ifindex] == NULL) 246 continue; 247 struct iface *iface = ifmap->ifaces[ifindex]; 248 ifa->next = iface->ifa; 249 ifa->idx = ++count; 250 iface->ifa = ifa; 251 iface->ifa_count++; 252 } 253 } 254 255 static bool 256 match_iface(struct ifconfig_args *args, struct iface *iface) 257 { 258 if_link_t *link = &iface->link; 259 260 if (args->ifname != NULL && strcmp(args->ifname, link->ifla_ifname)) 261 return (false); 262 263 if (!match_if_flags(args, link->ifi_flags)) 264 return (false); 265 266 if (!group_member(link->ifla_ifname, args->matchgroup, args->nogroup)) 267 return (false); 268 269 if (args->afp == NULL) 270 return (true); 271 272 if (!strcmp(args->afp->af_name, "ether")) { 273 if (link->ifla_address == NULL) 274 return (false); 275 276 struct sockaddr_dl sdl = { 277 .sdl_len = sizeof(struct sockaddr_dl), 278 .sdl_family = AF_LINK, 279 .sdl_type = convert_iftype(link->ifi_type), 280 .sdl_alen = NLA_DATA_LEN(link->ifla_address), 281 }; 282 return (match_ether(&sdl)); 283 } else if (args->afp->af_af == AF_LINK) 284 /* 285 * The rtnetlink(4) RTM_GETADDR does not list link level 286 * addresses, so latter cycle won't match anything. Short 287 * circuit on RTM_GETLINK has provided us an address. 288 */ 289 return (link->ifla_address != NULL); 290 291 for (struct ifa *ifa = iface->ifa; ifa != NULL; ifa = ifa->next) { 292 if (args->afp->af_af == ifa->addr.ifa_family) 293 return (true); 294 } 295 296 return (false); 297 } 298 299 /* Sort according to the kernel-provided order */ 300 static int 301 cmp_iface(const void *_a, const void *_b) 302 { 303 const struct iface *a = *((const void * const *)_a); 304 const struct iface *b = *((const void * const *)_b); 305 306 return ((a->idx > b->idx) * 2 - 1); 307 } 308 309 static int 310 cmp_ifaddr(const void *_a, const void *_b) 311 { 312 const struct ifa *a = *((const void * const *)_a); 313 const struct ifa *b = *((const void * const *)_b); 314 315 if (a->addr.ifa_family != b->addr.ifa_family) 316 return ((a->addr.ifa_family > b->addr.ifa_family) * 2 - 1); 317 return ((a->idx > b->idx) * 2 - 1); 318 } 319 320 static void 321 sort_iface_ifaddrs(struct snl_state *ss, struct iface *iface) 322 { 323 if (iface->ifa_count == 0) 324 return; 325 326 struct ifa **sorted_ifaddrs = snl_allocz(ss, iface->ifa_count * sizeof(void *)); 327 struct ifa *ifa = iface->ifa; 328 329 for (uint32_t i = 0; i < iface->ifa_count; i++) { 330 struct ifa *ifa_next = ifa->next; 331 332 sorted_ifaddrs[i] = ifa; 333 ifa->next = NULL; 334 ifa = ifa_next; 335 } 336 qsort(sorted_ifaddrs, iface->ifa_count, sizeof(void *), cmp_ifaddr); 337 ifa = sorted_ifaddrs[0]; 338 iface->ifa = ifa; 339 for (uint32_t i = 1; i < iface->ifa_count; i++) { 340 ifa->next = sorted_ifaddrs[i]; 341 ifa = sorted_ifaddrs[i]; 342 } 343 } 344 345 static void 346 print_ifcaps(if_ctx *ctx, if_link_t *link) 347 { 348 uint32_t sz_u32 = roundup2(link->iflaf_caps.nla_bitset_size, 32) / 32; 349 350 if (sz_u32 > 0) { 351 uint32_t *caps = link->iflaf_caps.nla_bitset_value; 352 353 printf("\toptions=%x", caps[0]); 354 print_bits("IFCAPS", caps, sz_u32, ifcap_bit_names, nitems(ifcap_bit_names)); 355 putchar('\n'); 356 } 357 358 if (ctx->args->supmedia && sz_u32 > 0) { 359 uint32_t *caps = link->iflaf_caps.nla_bitset_mask; 360 361 printf("\tcapabilities=%x", caps[0]); 362 print_bits("IFCAPS", caps, sz_u32, ifcap_bit_names, nitems(ifcap_bit_names)); 363 putchar('\n'); 364 } 365 } 366 367 static void 368 status_nl(if_ctx *ctx, struct iface *iface) 369 { 370 if_link_t *link = &iface->link; 371 struct ifconfig_args *args = ctx->args; 372 char *drivername = NULL; 373 374 printf("%s: ", link->ifla_ifname); 375 376 printf("flags=%x", link->ifi_flags); 377 print_bits("IFF", &link->ifi_flags, 1, IFFBITS, nitems(IFFBITS)); 378 379 print_metric(ctx); 380 printf(" mtu %d\n", link->ifla_mtu); 381 382 if (link->ifla_ifalias != NULL) 383 printf("\tdescription: %s\n", link->ifla_ifalias); 384 385 print_ifcaps(ctx, link); 386 tunnel_status(ctx); 387 388 if (args->allfamilies | (args->afp != NULL && args->afp->af_af == AF_LINK)) { 389 /* Start with link-level */ 390 const struct afswtch *p = af_getbyfamily(AF_LINK); 391 if (p != NULL && link->ifla_address != NULL) 392 p->af_status(ctx, link, NULL); 393 } 394 395 sort_iface_ifaddrs(ctx->io_ss, iface); 396 397 for (struct ifa *ifa = iface->ifa; ifa != NULL; ifa = ifa->next) { 398 if (args->allfamilies) { 399 const struct afswtch *p = af_getbyfamily(ifa->addr.ifa_family); 400 401 if (p != NULL) 402 p->af_status(ctx, link, &ifa->addr); 403 } else if (args->afp->af_af == ifa->addr.ifa_family) { 404 const struct afswtch *p = args->afp; 405 406 p->af_status(ctx, link, &ifa->addr); 407 } 408 } 409 410 /* TODO: convert to netlink */ 411 if (args->allfamilies) 412 af_other_status(ctx); 413 else if (args->afp->af_other_status != NULL) 414 args->afp->af_other_status(ctx); 415 416 print_ifstatus(ctx); 417 if (args->drivername || args->verbose) { 418 if (ifconfig_get_orig_name(lifh, link->ifla_ifname, 419 &drivername) != 0) { 420 if (ifconfig_err_errtype(lifh) == OTHER) 421 fprintf(stderr, "get original name: %s\n", 422 strerror(ifconfig_err_errno(lifh))); 423 else 424 fprintf(stderr, 425 "get original name: error type %d\n", 426 ifconfig_err_errtype(lifh)); 427 exit_code = 1; 428 } 429 if (drivername != NULL) 430 printf("\tdrivername: %s\n", drivername); 431 free(drivername); 432 } 433 if (args->verbose > 0) 434 sfp_status(ctx); 435 } 436 437 static int 438 get_local_socket(void) 439 { 440 int s = socket(AF_LOCAL, SOCK_DGRAM, 0); 441 442 if (s < 0) 443 err(1, "socket(family %u,SOCK_DGRAM)", AF_LOCAL); 444 return (s); 445 } 446 447 void 448 list_interfaces_nl(struct ifconfig_args *args) 449 { 450 struct snl_state ss = {}; 451 struct ifconfig_context _ctx = { 452 .args = args, 453 .io_s = get_local_socket(), 454 .io_ss = &ss, 455 }; 456 struct ifconfig_context *ctx = &_ctx; 457 458 nl_init_socket(&ss); 459 460 struct ifmap *ifmap = prepare_ifmap(&ss, args->ifname); 461 struct iface **sorted_ifaces = snl_allocz(&ss, ifmap->count * sizeof(void *)); 462 for (uint32_t i = 0, num = 0; i < ifmap->size; i++) { 463 if (ifmap->ifaces[i] != NULL) { 464 sorted_ifaces[num++] = ifmap->ifaces[i]; 465 if (num == ifmap->count) 466 break; 467 } 468 } 469 qsort(sorted_ifaces, ifmap->count, sizeof(void *), cmp_iface); 470 prepare_ifaddrs(&ss, ifmap); 471 472 for (uint32_t i = 0, num = 0; i < ifmap->count; i++) { 473 struct iface *iface = sorted_ifaces[i]; 474 475 if (!match_iface(args, iface)) 476 continue; 477 478 ctx->ifname = iface->link.ifla_ifname; 479 480 if (args->namesonly) { 481 if (num++ != 0) 482 printf(" "); 483 fputs(iface->link.ifla_ifname, stdout); 484 } else if (args->argc == 0) 485 status_nl(ctx, iface); 486 else 487 ifconfig_ioctl(ctx, 0, args->afp); 488 } 489 if (args->namesonly) 490 printf("\n"); 491 492 close(ctx->io_s); 493 snl_free(&ss); 494 } 495 496