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