1 /* AirScan (a.k.a. eSCL) backend for SANE
2 *
3 * Copyright (C) 2019 and up by Alexander Pevzner (pzz@apevzner.com)
4 * See LICENSE for license terms and conditions
5 *
6 * Network interfaces addresses
7 */
8
9 #include "airscan.h"
10
11 #include <errno.h>
12 #include <string.h>
13 #include <unistd.h>
14
15 #include <arpa/inet.h>
16 #include <ifaddrs.h>
17 #ifdef OS_HAVE_RTNETLINK
18 #include <linux/netlink.h>
19 #include <linux/rtnetlink.h>
20 #endif
21 #ifdef OS_HAVE_AF_ROUTE
22 #include <net/route.h>
23 #endif
24 #include <net/if.h>
25 #include <sys/socket.h>
26
27 /* Static variables */
28 static int netif_rtnetlink_sock = -1;
29 static eloop_fdpoll *netif_rtnetlink_fdpoll;
30 static ll_head netif_notifier_list;
31 static struct ifaddrs *netif_ifaddrs;
32
33 /* Forward declarations */
34 static netif_addr*
35 netif_addr_list_sort (netif_addr *list);
36
37 /* Get distance to the target address
38 */
39 NETIF_DISTANCE
netif_distance_get(const struct sockaddr * addr)40 netif_distance_get (const struct sockaddr *addr)
41 {
42 struct ifaddrs *ifa;
43 struct in_addr addr4, ifaddr4, ifmask4;
44 struct in6_addr addr6, ifaddr6, ifmask6;
45 static struct in6_addr zero6;
46 size_t i;
47 NETIF_DISTANCE distance = NETIF_DISTANCE_ROUTED;
48
49 for (ifa = netif_ifaddrs; ifa != NULL; ifa = ifa->ifa_next) {
50 /* Skip interface without address or netmask */
51 if (ifa->ifa_addr == NULL || ifa->ifa_netmask == NULL) {
52 continue;
53 }
54
55 /* Compare address family */
56 if (addr->sa_family != ifa->ifa_addr->sa_family) {
57 continue;
58 }
59
60 /* Check direct reachability */
61 switch (addr->sa_family) {
62 case AF_INET:
63 addr4 = ((struct sockaddr_in*) addr)->sin_addr;
64 ifaddr4 = ((struct sockaddr_in*) ifa->ifa_addr)->sin_addr;
65 ifmask4 = ((struct sockaddr_in*) ifa->ifa_netmask)->sin_addr;
66
67 if (addr4.s_addr == ifaddr4.s_addr) {
68 return NETIF_DISTANCE_LOOPBACK;
69 }
70
71 if (((addr4.s_addr ^ ifaddr4.s_addr) & ifmask4.s_addr) == 0) {
72 distance = NETIF_DISTANCE_DIRECT;
73 }
74 break;
75
76 case AF_INET6:
77 addr6 = ((struct sockaddr_in6*) addr)->sin6_addr;
78 ifaddr6 = ((struct sockaddr_in6*) ifa->ifa_addr)->sin6_addr;
79 ifmask6 = ((struct sockaddr_in6*) ifa->ifa_netmask)->sin6_addr;
80
81 if (!memcmp(&addr6, &ifaddr6, sizeof(struct in6_addr))) {
82 return NETIF_DISTANCE_LOOPBACK;
83 }
84
85 for (i = 0; i < sizeof(struct in6_addr); i ++) {
86 addr6.s6_addr[i] ^= ifaddr6.s6_addr[i];
87 addr6.s6_addr[i] &= ifmask6.s6_addr[i];
88 }
89
90 if (!memcmp(&addr6, &zero6, sizeof(struct in6_addr))) {
91 distance = NETIF_DISTANCE_DIRECT;
92 }
93 break;
94 }
95 }
96
97 return distance;
98 }
99
100 /* Check that interface has non-link-local address
101 * of particular address family
102 */
103 bool
netif_has_non_link_local_addr(int af,int ifindex)104 netif_has_non_link_local_addr (int af, int ifindex)
105 {
106 struct ifaddrs *ifa;
107
108 for (ifa = netif_ifaddrs; ifa != NULL; ifa = ifa->ifa_next) {
109 struct sockaddr *addr;
110
111 /* Skip interface without address */
112 if ((addr = ifa->ifa_addr) == NULL) {
113 continue;
114 }
115
116 /* Check address family against requested */
117 if (addr->sa_family != af) {
118 continue;
119 }
120
121 /* Skip link-local addresses */
122 if (ip_sockaddr_is_linklocal(addr)) {
123 continue;
124 }
125
126 /* Check interface index */
127 if (ifindex == (int) if_nametoindex(ifa->ifa_name)) {
128 return true;
129 }
130 }
131
132 return false;
133 }
134
135 /* Get list of network interfaces addresses
136 */
137 netif_addr*
netif_addr_list_get(void)138 netif_addr_list_get (void)
139 {
140 struct ifaddrs *ifa;
141 netif_addr *list = NULL, *addr;
142
143 for (ifa = netif_ifaddrs; ifa != NULL; ifa = ifa->ifa_next) {
144 /* Skip interface without address */
145 if (ifa->ifa_addr == NULL) {
146 continue;
147 }
148
149 /* Skip loopback interface */
150 if ((ifa->ifa_flags & IFF_LOOPBACK) != 0) {
151 continue;
152 }
153
154 /* Obtain interface index. Skip address, if it failed */
155 int idx = if_nametoindex(ifa->ifa_name);
156 if (idx <= 0) {
157 continue;
158 }
159
160 /* Translate struct ifaddrs to netif_addr */
161 addr = mem_new(netif_addr, 1);
162 addr->next = list;
163 addr->ifindex = idx;
164 strncpy(addr->ifname.text, ifa->ifa_name,
165 sizeof(addr->ifname.text) - 1);
166
167 switch (ifa->ifa_addr->sa_family) {
168 case AF_INET:
169 addr->ip.v4 = ((struct sockaddr_in*) ifa->ifa_addr)->sin_addr;
170 inet_ntop(AF_INET, &addr->ip.v4,
171 addr->straddr, sizeof(addr->straddr));
172 break;
173
174 case AF_INET6:
175 addr->ipv6 = true;
176 addr->ip.v6 = ((struct sockaddr_in6*) ifa->ifa_addr)->sin6_addr;
177 inet_ntop(AF_INET6, &addr->ip.v6,
178 addr->straddr, sizeof(addr->straddr));
179 break;
180
181 default:
182 /* Paranoia; should not actually happen */
183 mem_free(addr);
184 addr = NULL;
185 break;
186 }
187
188 if (addr != NULL) {
189 addr->next = list;
190 list = addr;
191 }
192 }
193
194 return netif_addr_list_sort(list);
195 }
196
197 /* Free a single netif_addr
198 */
199 static void
netif_addr_free_single(netif_addr * addr)200 netif_addr_free_single (netif_addr *addr)
201 {
202 mem_free(addr);
203 }
204
205 /* Free list of network interfaces addresses
206 */
207 void
netif_addr_list_free(netif_addr * list)208 netif_addr_list_free (netif_addr *list)
209 {
210 while (list != NULL) {
211 netif_addr *next = list->next;
212 netif_addr_free_single(list);
213 list = next;
214 }
215 }
216
217 /* Compare two netif_addr addresses, for sorting
218 */
219 static int
netif_addr_cmp(netif_addr * a1,netif_addr * a2)220 netif_addr_cmp (netif_addr *a1, netif_addr *a2)
221 {
222 bool ll1, ll2;
223
224 /* Compare interface indices */
225 if (a1->ifindex != a2->ifindex) {
226 return a1->ifindex - a2->ifindex;
227 }
228
229 /* Prefer normal addresses, rather that link-local */
230 ll1 = ip_is_linklocal(a1->ipv6 ? AF_INET6 : AF_INET, &a1->ip);
231 ll2 = ip_is_linklocal(a2->ipv6 ? AF_INET6 : AF_INET, &a2->ip);
232
233 if (ll1 != ll2) {
234 return ll1 ? 1 : -1;
235 }
236
237 /* Be in trend: prefer IPv6 addresses */
238 if (a1->ipv6 != a2->ipv6) {
239 return (int) a2->ipv6 - (int) a1->ipv6;
240 }
241
242 /* Otherwise, sort lexicographically */
243 return strcmp(a1->straddr, a2->straddr);
244 }
245
246 /* Revert netif_addr list
247 */
248 static netif_addr*
netif_addr_list_revert(netif_addr * list)249 netif_addr_list_revert (netif_addr *list)
250 {
251 netif_addr *prev = NULL, *next;
252
253 while (list != NULL) {
254 next = list->next;
255 list->next = prev;
256 prev = list;
257 list = next;
258 }
259
260 return prev;
261 }
262
263 /* Sort list of addresses
264 */
265 static netif_addr*
netif_addr_list_sort(netif_addr * list)266 netif_addr_list_sort (netif_addr *list)
267 {
268 netif_addr *halves[2] = {NULL, NULL};
269 int half = 0;
270
271 if (list == NULL || list->next == NULL) {
272 return list;
273 }
274
275 /* Split list into halves */
276 while (list != NULL) {
277 netif_addr *next = list->next;
278
279 list->next = halves[half];
280 halves[half] = list;
281
282 half ^= 1;
283 list = next;
284 }
285
286 /* Sort each half, recursively */
287 for (half = 0; half < 2; half ++) {
288 halves[half] = netif_addr_list_sort(halves[half]);
289 }
290
291 /* Now merge the sorted halves */
292 list = NULL;
293 while (halves[0] != NULL || halves[1] != NULL) {
294 netif_addr *next;
295
296 if (halves[0] == NULL) {
297 half = 1;
298 } else if (halves[1] == NULL) {
299 half = 0;
300 } else if (netif_addr_cmp(halves[0], halves[1]) < 0) {
301 half = 0;
302 } else {
303 half = 1;
304 }
305
306 next = halves[half]->next;
307 halves[half]->next = list;
308 list = halves[half];
309 halves[half] = next;
310 }
311
312 /* And revert the list, as after merging it is reverted */
313 return netif_addr_list_revert(list);
314 }
315
316 /* Compute a difference between two lists of addresses.
317 *
318 * It works by tossing nodes between 3 output lists:
319 * * if node is present in list2 only, it is moved
320 * to netif_diff.added
321 * * if node is present in list1 only, it is moved
322 * to netif_diff.removed
323 * * if node is present in both lists, node from
324 * list1 is moved to preserved, and node from
325 * list2 is released
326 *
327 * It assumes, both lists are sorted, as returned
328 * by netif_addr_get(). Returned lists are also sorted
329 */
330 netif_diff
netif_diff_compute(netif_addr * list1,netif_addr * list2)331 netif_diff_compute (netif_addr *list1, netif_addr *list2)
332 {
333 netif_diff diff = {NULL, NULL, NULL};
334
335 while (list1 != NULL || list2 != NULL) {
336 netif_addr *addr;
337 int cmp;
338
339 if (list1 == NULL) {
340 cmp = 1;
341 } else if (list2 == NULL) {
342 cmp = -1;
343 } else {
344 cmp = netif_addr_cmp(list1, list2);
345 }
346
347 if (cmp < 0) {
348 addr = list1;
349 list1 = list1->next;
350 addr->next = diff.removed;
351 diff.removed = addr;
352 } else if (cmp > 0) {
353 addr = list2;
354 list2 = list2->next;
355 addr->next = diff.added;
356 diff.added = addr;
357 } else {
358 addr = list1;
359 list1 = list1->next;
360 addr->next = diff.preserved;
361 diff.preserved = addr;
362
363 addr = list2;
364 list2 = list2->next;
365 netif_addr_free_single(addr);
366 }
367 }
368
369 diff.added = netif_addr_list_revert(diff.added);
370 diff.removed = netif_addr_list_revert(diff.removed);
371 diff.preserved = netif_addr_list_revert(diff.preserved);
372
373 return diff;
374 }
375
376 /* Merge two lists of addresses
377 *
378 * Input lists are consumed and new list is created.
379 *
380 * Input lists are assumed to be sorted, and output
381 * list will be sorted as well
382 */
383 netif_addr*
netif_addr_list_merge(netif_addr * list1,netif_addr * list2)384 netif_addr_list_merge (netif_addr *list1, netif_addr *list2)
385 {
386 netif_addr *list = NULL;
387
388 while (list1 != NULL || list2 != NULL) {
389 netif_addr *addr;
390 int cmp;
391
392 if (list1 == NULL) {
393 cmp = 1;
394 } else if (list2 == NULL) {
395 cmp = -1;
396 } else {
397 cmp = netif_addr_cmp(list1, list2);
398 }
399
400 if (cmp < 0) {
401 addr = list1;
402 list1 = list1->next;
403 } else {
404 addr = list2;
405 list2 = list2->next;
406 }
407
408 addr->next = list;
409 list = addr;
410 }
411
412 return netif_addr_list_revert(list);
413 }
414
415 /* Network interfaces addresses change notifier
416 */
417 struct netif_notifier {
418 void (*callback)(void*); /* Notification callback */
419 void *data; /* Callback data */
420 ll_node list_node; /* in the netif_notifier_list */
421 };
422
423 /* Get a new list of network interfaces and notify the callbacks
424 */
425 static void
netif_refresh_ifaddrs(void)426 netif_refresh_ifaddrs (void)
427 {
428 struct ifaddrs *new_ifaddrs;
429 ll_node *node;
430 int rc;
431
432 rc = getifaddrs(&new_ifaddrs);
433 if (rc >= 0) {
434 if (netif_ifaddrs != NULL) {
435 freeifaddrs(netif_ifaddrs);
436 }
437
438 netif_ifaddrs = new_ifaddrs;
439 }
440
441 /* Call all registered callbacks */
442 for (LL_FOR_EACH(node, &netif_notifier_list)) {
443 netif_notifier *notifier;
444 notifier = OUTER_STRUCT(node, netif_notifier, list_node);
445 notifier->callback(notifier->data);
446 }
447 }
448
449 /* netif_notifier read callback
450 */
451 static void
netif_notifier_read_callback(int fd,void * data,ELOOP_FDPOLL_MASK mask)452 netif_notifier_read_callback (int fd, void *data, ELOOP_FDPOLL_MASK mask)
453 {
454 static uint8_t buf[16384];
455 int rc;
456
457 (void) fd;
458 (void) data;
459 (void) mask;
460
461 /* Get rtnetlink message */
462 rc = read(netif_rtnetlink_sock, buf, sizeof(buf));
463 if (rc < 0) {
464 return;
465 }
466
467 #if defined(OS_HAVE_RTNETLINK)
468 struct nlmsghdr *p;
469 size_t sz;
470
471 /* Parse rtnetlink message, to suppress unneeded (and relatively
472 * expensive) netif_refresh_ifaddrs() calls. We are only interested
473 * in RTM_NEWADDR/RTM_DELADDR notifications
474 */
475 sz = (size_t) rc;
476 for (p = (struct nlmsghdr*) buf;
477 sz >= sizeof(struct nlmsghdr); p = NLMSG_NEXT(p, sz)) {
478
479 if (!NLMSG_OK(p, sz) || sz < p->nlmsg_len) {
480 return;
481 }
482
483 switch (p->nlmsg_type) {
484 case NLMSG_DONE:
485 return;
486
487 case RTM_NEWADDR:
488 case RTM_DELADDR:
489 netif_refresh_ifaddrs();
490 return;
491 }
492 }
493 #elif defined(OS_HAVE_AF_ROUTE)
494 /* Note, on OpenBSD we have ROUTE_MSGFILTER, but FreeBSD lacks
495 * this feature, so we have to filter received routing messages
496 * manually, to avoid relatively expensive netif_refresh_ifaddrs()
497 * calls
498 */
499 struct rt_msghdr *rtm = (struct rt_msghdr*) buf;
500 if (rc >= (int) sizeof(struct rt_msghdr)) {
501 switch (rtm->rtm_type) {
502 case RTM_NEWADDR:
503 case RTM_DELADDR:
504 netif_refresh_ifaddrs();
505 break;
506 }
507 }
508 #endif
509 }
510
511 /* Create netif_notifier
512 */
513 netif_notifier*
netif_notifier_create(void (* callback)(void *),void * data)514 netif_notifier_create (void (*callback) (void*), void *data)
515 {
516 netif_notifier *notifier = mem_new(netif_notifier, 1);
517
518 notifier->callback = callback;
519 notifier->data = data;
520
521 ll_push_end(&netif_notifier_list, ¬ifier->list_node);
522
523 return notifier;
524 }
525
526 /* Destroy netif_notifier
527 */
528 void
netif_notifier_free(netif_notifier * notifier)529 netif_notifier_free (netif_notifier *notifier)
530 {
531 ll_del(¬ifier->list_node);
532 mem_free(notifier);
533 }
534
535 /* Start/stop callback
536 */
537 static void
netif_start_stop_callback(bool start)538 netif_start_stop_callback (bool start)
539 {
540 if (start) {
541 netif_rtnetlink_fdpoll = eloop_fdpoll_new(netif_rtnetlink_sock,
542 netif_notifier_read_callback, NULL);
543 eloop_fdpoll_set_mask(netif_rtnetlink_fdpoll, ELOOP_FDPOLL_READ);
544 } else {
545 eloop_fdpoll_free(netif_rtnetlink_fdpoll);
546 netif_rtnetlink_fdpoll = NULL;
547 }
548 }
549
550 /* Initialize network interfaces monitoring
551 */
552 SANE_Status
netif_init(void)553 netif_init (void)
554 {
555 ll_init(&netif_notifier_list);
556
557 #if defined(OS_HAVE_RTNETLINK)
558 struct sockaddr_nl addr;
559 int rc;
560
561 /* Create AF_NETLINK socket */
562 netif_rtnetlink_sock = socket(AF_NETLINK,
563 SOCK_RAW | SOCK_CLOEXEC | SOCK_NONBLOCK, NETLINK_ROUTE);
564
565 if (netif_rtnetlink_sock < 0) {
566 log_debug(NULL, "can't open AF_NETLINK socket: %s", strerror(errno));
567 return SANE_STATUS_IO_ERROR;
568 }
569
570 /* Subscribe to notifications */
571 memset(&addr, 0, sizeof(addr));
572 addr.nl_family = AF_NETLINK;
573 addr.nl_groups = RTMGRP_IPV4_IFADDR | RTMGRP_IPV6_IFADDR;
574
575 rc = bind(netif_rtnetlink_sock, (struct sockaddr*) &addr, sizeof(addr));
576 if (rc < 0) {
577 log_debug(NULL, "can't bind AF_NETLINK socket: %s", strerror(errno));
578 close(netif_rtnetlink_sock);
579 return SANE_STATUS_IO_ERROR;
580 }
581 #elif defined(OS_HAVE_AF_ROUTE)
582 /* Create AF_ROUTE socket */
583 netif_rtnetlink_sock = socket(AF_ROUTE,
584 SOCK_RAW | SOCK_CLOEXEC | SOCK_NONBLOCK, AF_UNSPEC);
585
586 if (netif_rtnetlink_sock < 0) {
587 log_debug(NULL, "can't open AF_ROUTE socket: %s", strerror(errno));
588 return SANE_STATUS_IO_ERROR;
589 }
590
591 #ifdef ROUTE_MSGFILTER
592 unsigned int rtfilter =
593 ROUTE_FILTER(RTM_NEWADDR) | ROUTE_FILTER(RTM_DELADDR);
594 if (setsockopt(netif_rtnetlink_sock, AF_ROUTE, ROUTE_MSGFILTER,
595 &rtfilter, sizeof(rtfilter)) < 0) {
596 /* Note, this error is not fatal for us, it is enough to
597 * log it and continue
598 */
599 log_debug(NULL, "can't set ROUTE_MSGFILTER: %s", strerror(errno));
600 }
601 #endif
602 #endif
603
604 /* Initialize netif_ifaddrs */
605 if (getifaddrs(&netif_ifaddrs) < 0) {
606 log_debug(NULL, "getifaddrs(): %s", strerror(errno));
607 close(netif_rtnetlink_sock);
608 return SANE_STATUS_IO_ERROR;
609 }
610
611 /* Register start/stop callback */
612 eloop_add_start_stop_callback(netif_start_stop_callback);
613
614 return SANE_STATUS_GOOD;
615 }
616
617 /* Cleanup network interfaces monitoring
618 */
619 void
netif_cleanup(void)620 netif_cleanup (void)
621 {
622 if (netif_ifaddrs != NULL) {
623 freeifaddrs(netif_ifaddrs);
624 netif_ifaddrs = NULL;
625 }
626
627 if (netif_rtnetlink_sock >= 0) {
628 close(netif_rtnetlink_sock);
629 netif_rtnetlink_sock = -1;
630 }
631 }
632
633 /* vim:ts=8:sw=4:et
634 */
635