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_types.h> 52 #include "ifconfig.h" 53 #include "ifconfig_netlink.h" 54 55 static const char *IFFBITS[] = { 56 "UP", /* 00:0x1 IFF_UP*/ 57 "BROADCAST", /* 01:0x2 IFF_BROADCAST*/ 58 "DEBUG", /* 02:0x4 IFF_DEBUG*/ 59 "LOOPBACK", /* 03:0x8 IFF_LOOPBACK*/ 60 "POINTOPOINT", /* 04:0x10 IFF_POINTOPOINT*/ 61 "NEEDSEPOCH", /* 05:0x20 IFF_NEEDSEPOCH*/ 62 "RUNNING", /* 06:0x40 IFF_DRV_RUNNING*/ 63 "NOARP", /* 07:0x80 IFF_NOARP*/ 64 "PROMISC", /* 08:0x100 IFF_PROMISC*/ 65 "ALLMULTI", /* 09:0x200 IFF_ALLMULTI*/ 66 "DRV_OACTIVE", /* 10:0x400 IFF_DRV_OACTIVE*/ 67 "SIMPLEX", /* 11:0x800 IFF_SIMPLEX*/ 68 "LINK0", /* 12:0x1000 IFF_LINK0*/ 69 "LINK1", /* 13:0x2000 IFF_LINK1*/ 70 "LINK2", /* 14:0x4000 IFF_LINK2*/ 71 "MULTICAST", /* 15:0x8000 IFF_MULTICAST*/ 72 "CANTCONFIG", /* 16:0x10000 IFF_CANTCONFIG*/ 73 "PPROMISC", /* 17:0x20000 IFF_PPROMISC*/ 74 "MONITOR", /* 18:0x40000 IFF_MONITOR*/ 75 "STATICARP", /* 19:0x80000 IFF_STATICARP*/ 76 "STICKYARP", /* 20:0x100000 IFF_STICKYARP*/ 77 "DYING", /* 21:0x200000 IFF_DYING*/ 78 "RENAMING", /* 22:0x400000 IFF_RENAMING*/ 79 "NOGROUP", /* 23:0x800000 IFF_NOGROUP*/ 80 "LOWER_UP", /* 24:0x1000000 IFF_NETLINK_1*/ 81 }; 82 83 static void 84 print_bits(const char *btype, uint32_t *v, const int v_count, 85 const char **names, const int n_count) 86 { 87 int num = 0; 88 89 for (int i = 0; i < v_count * 32; i++) { 90 bool is_set = v[i / 32] & (1 << (i % 32)); 91 if (i == 31) 92 v++; 93 if (is_set) { 94 if (num++ == 0) 95 printf("<"); 96 if (num != 1) 97 printf(","); 98 if (i < n_count) 99 printf("%s", names[i]); 100 else 101 printf("%s_%d", btype, i); 102 } 103 } 104 if (num > 0) 105 printf(">"); 106 } 107 108 static void 109 nl_init_socket(struct snl_state *ss) 110 { 111 if (snl_init(ss, NETLINK_ROUTE)) 112 return; 113 114 if (modfind("netlink") == -1 && errno == ENOENT) { 115 /* Try to load */ 116 if (kldload("netlink") == -1) 117 err(1, "netlink is not loaded and load attempt failed"); 118 if (snl_init(ss, NETLINK_ROUTE)) 119 return; 120 } 121 122 err(1, "unable to open netlink socket"); 123 } 124 125 struct ifa { 126 struct ifa *next; 127 uint32_t count; 128 uint32_t idx; 129 struct snl_parsed_addr addr; 130 }; 131 132 struct iface { 133 struct snl_parsed_link link; 134 struct ifa *ifa; 135 uint32_t ifa_count; 136 uint32_t idx; 137 }; 138 139 struct ifmap { 140 uint32_t size; 141 uint32_t count; 142 struct iface **ifaces; 143 }; 144 145 /* 146 * Returns ifmap ifindex->snl_parsed_link. 147 * Memory is allocated using snl temporary buffers 148 */ 149 static struct ifmap * 150 prepare_ifmap(struct snl_state *ss) 151 { 152 struct snl_writer nw = {}; 153 154 snl_init_writer(ss, &nw); 155 struct nlmsghdr *hdr = snl_create_msg_request(&nw, RTM_GETLINK); 156 hdr->nlmsg_flags |= NLM_F_DUMP; 157 snl_reserve_msg_object(&nw, struct ifinfomsg); 158 159 if (!snl_finalize_msg(&nw) || !snl_send_message(ss, hdr)) 160 return (NULL); 161 162 uint32_t nlmsg_seq = hdr->nlmsg_seq; 163 struct ifmap *ifmap = snl_allocz(ss, sizeof(*ifmap)); 164 struct snl_errmsg_data e = {}; 165 166 while ((hdr = snl_read_reply_multi(ss, nlmsg_seq, &e)) != NULL) { 167 struct iface *iface = snl_allocz(ss, sizeof(*iface)); 168 169 if (!snl_parse_nlmsg(ss, hdr, &snl_rtm_link_parser, &iface->link)) 170 continue; 171 if (iface->link.ifi_index >= ifmap->size) { 172 size_t new_size = MAX(ifmap->size, 32); 173 174 while (new_size <= iface->link.ifi_index + 1) 175 new_size *= 2; 176 177 struct iface **ifaces= snl_allocz(ss, new_size * sizeof(void *)); 178 memcpy(ifaces, ifmap->ifaces, ifmap->size * sizeof(void *)); 179 ifmap->ifaces = ifaces; 180 ifmap->size = new_size; 181 } 182 ifmap->ifaces[iface->link.ifi_index] = iface; 183 ifmap->count++; 184 iface->idx = ifmap->count; 185 } 186 return (ifmap); 187 } 188 189 static void 190 prepare_ifaddrs(struct snl_state *ss, struct ifmap *ifmap) 191 { 192 struct snl_writer nw = {}; 193 194 snl_init_writer(ss, &nw); 195 struct nlmsghdr *hdr = snl_create_msg_request(&nw, RTM_GETADDR); 196 hdr->nlmsg_flags |= NLM_F_DUMP; 197 snl_reserve_msg_object(&nw, struct ifaddrmsg); 198 199 if (!snl_finalize_msg(&nw) || !snl_send_message(ss, hdr)) 200 return; 201 202 uint32_t nlmsg_seq = hdr->nlmsg_seq; 203 struct snl_errmsg_data e = {}; 204 uint32_t count = 0; 205 206 while ((hdr = snl_read_reply_multi(ss, nlmsg_seq, &e)) != NULL) { 207 struct ifa *ifa = snl_allocz(ss, sizeof(*ifa)); 208 209 if (!snl_parse_nlmsg(ss, hdr, &snl_rtm_addr_parser, &ifa->addr)) 210 continue; 211 212 const uint32_t ifindex = ifa->addr.ifa_index; 213 if (ifindex >= ifmap->size || ifmap->ifaces[ifindex] == NULL) 214 continue; 215 struct iface *iface = ifmap->ifaces[ifindex]; 216 ifa->next = iface->ifa; 217 ifa->count = ++count; 218 iface->ifa = ifa; 219 iface->ifa_count++; 220 } 221 } 222 223 static bool 224 match_iface(struct ifconfig_args *args, struct iface *iface) 225 { 226 if_link_t *link = &iface->link; 227 228 if (args->ifname != NULL && strcmp(args->ifname, link->ifla_ifname)) 229 return (false); 230 231 if (!match_if_flags(args, link->ifi_flags)) 232 return (false); 233 234 if (!group_member(link->ifla_ifname, args->matchgroup, args->nogroup)) 235 return (false); 236 237 if (args->afp == NULL) 238 return (true); 239 240 if (!strcmp(args->afp->af_name, "ether")) { 241 if (link->ifla_address == NULL) 242 return (false); 243 244 struct sockaddr_dl sdl = { 245 .sdl_len = sizeof(struct sockaddr_dl), 246 .sdl_family = AF_LINK, 247 .sdl_type = link->ifi_type, 248 .sdl_alen = NLA_DATA_LEN(link->ifla_address), 249 }; 250 return (match_ether(&sdl)); 251 } 252 253 for (struct ifa *ifa = iface->ifa; ifa != NULL; ifa = ifa->next) { 254 if (args->afp->af_af == ifa->addr.ifa_family) 255 return (true); 256 } 257 258 return (false); 259 } 260 261 /* Sort according to the kernel-provided order */ 262 static int 263 cmp_iface(const void *_a, const void *_b) 264 { 265 const struct iface *a = *((const void * const *)_a); 266 const struct iface *b = *((const void * const *)_b); 267 268 return ((a->idx > b->idx) * 2 - 1); 269 } 270 271 static int 272 cmp_ifaddr(const void *_a, const void *_b) 273 { 274 const struct ifa *a = *((const void * const *)_a); 275 const struct ifa *b = *((const void * const *)_b); 276 277 if (a->addr.ifa_family != b->addr.ifa_family) 278 return ((a->addr.ifa_family > b->addr.ifa_family) * 2 - 1); 279 return ((a->idx > b->idx) * 2 - 1); 280 } 281 282 static void 283 sort_iface_ifaddrs(struct snl_state *ss, struct iface *iface) 284 { 285 if (iface->ifa_count == 0) 286 return; 287 288 struct ifa **sorted_ifaddrs = snl_allocz(ss, iface->ifa_count * sizeof(void *)); 289 struct ifa *ifa = iface->ifa; 290 291 for (int i = 0; i < iface->ifa_count; i++) { 292 struct ifa *ifa_next = ifa->next; 293 294 sorted_ifaddrs[i] = ifa; 295 ifa->next = NULL; 296 ifa = ifa_next; 297 } 298 qsort(sorted_ifaddrs, iface->ifa_count, sizeof(void *), cmp_ifaddr); 299 ifa = sorted_ifaddrs[0]; 300 iface->ifa = ifa; 301 for (int i = 1; i < iface->ifa_count; i++) { 302 ifa->next = sorted_ifaddrs[i]; 303 ifa = sorted_ifaddrs[i]; 304 } 305 } 306 307 static void 308 status_nl(struct ifconfig_args *args, struct io_handler *h, struct iface *iface) 309 { 310 if_link_t *link = &iface->link; 311 312 printf("%s: ", link->ifla_ifname); 313 314 printf("flags=%x", link->ifi_flags); 315 print_bits("IFF", &link->ifi_flags, 1, IFFBITS, nitems(IFFBITS)); 316 317 print_metric(h->s); 318 printf(" mtu %d\n", link->ifla_mtu); 319 320 if (link->ifla_ifalias != NULL) 321 printf("\tdescription: %s\n", link->ifla_ifalias); 322 323 /* TODO: convert to netlink */ 324 strlcpy(ifr.ifr_name, link->ifla_ifname, sizeof(ifr.ifr_name)); 325 print_ifcap(args, h->s); 326 tunnel_status(h->s); 327 328 if (args->allfamilies | (args->afp != NULL && args->afp->af_af == AF_LINK)) { 329 /* Start with link-level */ 330 const struct afswtch *p = af_getbyfamily(AF_LINK); 331 if (p != NULL && link->ifla_address != NULL) 332 p->af_status_nl(args, h, link, NULL); 333 } 334 335 sort_iface_ifaddrs(h->ss, iface); 336 337 for (struct ifa *ifa = iface->ifa; ifa != NULL; ifa = ifa->next) { 338 if (args->allfamilies) { 339 const struct afswtch *p = af_getbyfamily(ifa->addr.ifa_family); 340 341 if (p != NULL) 342 p->af_status_nl(args, h, link, &ifa->addr); 343 } else if (args->afp->af_af == ifa->addr.ifa_family) { 344 const struct afswtch *p = args->afp; 345 346 p->af_status_nl(args, h, link, &ifa->addr); 347 } 348 } 349 350 /* TODO: convert to netlink */ 351 if (args->allfamilies) 352 af_other_status(h->s); 353 else if (args->afp->af_other_status != NULL) 354 args->afp->af_other_status(h->s); 355 356 print_ifstatus(h->s); 357 if (args->verbose > 0) 358 sfp_status(h->s, &ifr, args->verbose); 359 } 360 361 static int 362 get_local_socket(void) 363 { 364 int s = socket(AF_LOCAL, SOCK_DGRAM, 0); 365 366 if (s < 0) 367 err(1, "socket(family %u,SOCK_DGRAM)", AF_LOCAL); 368 return (s); 369 } 370 371 static void 372 set_global_ifname(if_link_t *link) 373 { 374 int iflen = strlcpy(name, link->ifla_ifname, sizeof(name)); 375 if (iflen >= sizeof(name)) 376 errx(1, "%s: cloning name too long", link->ifla_ifname); 377 strlcpy(ifr.ifr_name, link->ifla_ifname, sizeof(ifr.ifr_name)); 378 } 379 380 void 381 list_interfaces_nl(struct ifconfig_args *args) 382 { 383 struct snl_state ss = {}; 384 385 nl_init_socket(&ss); 386 387 struct ifmap *ifmap = prepare_ifmap(&ss); 388 struct iface **sorted_ifaces = snl_allocz(&ss, ifmap->count * sizeof(void *)); 389 for (int i = 0, num = 0; i < ifmap->size; i++) { 390 if (ifmap->ifaces[i] != NULL) { 391 sorted_ifaces[num++] = ifmap->ifaces[i]; 392 if (num == ifmap->count) 393 break; 394 } 395 } 396 qsort(sorted_ifaces, ifmap->count, sizeof(void *), cmp_iface); 397 prepare_ifaddrs(&ss, ifmap); 398 399 struct io_handler h = { 400 .s = get_local_socket(), 401 .ss = &ss, 402 }; 403 404 for (int i = 0, num = 0; i < ifmap->count; i++) { 405 struct iface *iface = sorted_ifaces[i]; 406 407 if (!match_iface(args, iface)) 408 continue; 409 410 set_global_ifname(&iface->link); 411 412 if (args->namesonly) { 413 if (num++ != 0) 414 printf(" "); 415 fputs(iface->link.ifla_ifname, stdout); 416 } else if (args->argc == 0) 417 status_nl(args, &h, iface); 418 else 419 ifconfig(args->argc, args->argv, 0, args->afp); 420 } 421 if (args->namesonly) 422 printf("\n"); 423 424 close(h.s); 425 snl_free(&ss); 426 } 427 428