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
nl_init_socket(struct snl_state * ss)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
ifconfig_nl(if_ctx * ctx,int iscreate,const struct afswtch * uafp)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 *
prepare_ifmap(struct snl_state * ss,const char * ifname)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
if_nametoindex_nl(struct snl_state * ss,const char * ifname)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
convert_iftype(ifType 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
prepare_ifaddrs(struct snl_state * ss,struct ifmap * ifmap)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
match_iface(struct ifconfig_args * args,struct iface * iface)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
cmp_iface(const void * _a,const void * _b)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
cmp_ifaddr(const void * _a,const void * _b)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
sort_iface_ifaddrs(struct snl_state * ss,struct iface * iface)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
print_ifcaps(if_ctx * ctx,if_link_t * link)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
status_nl(if_ctx * ctx,struct iface * iface)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
get_local_socket(void)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
list_interfaces_nl(struct ifconfig_args * args)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