• source navigation  • diff markup  • identifier search  • freetext search  • 

Sources/odhcpd/src/netlink.c

  1 /**
  2  * Copyright (C) 2017 Hans Dedecker <dedeckeh@gmail.com>
  3  *
  4  * This program is free software; you can redistribute it and/or modify
  5  * it under the terms of the GNU General Public License v2 as published by
  6  * the Free Software Foundation.
  7  *
  8  * This program is distributed in the hope that it will be useful,
  9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
 10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 11  * GNU General Public License for more details.
 12  *
 13  */
 14 
 15 #include <errno.h>
 16 #include <string.h>
 17 
 18 #include <linux/netlink.h>
 19 #include <linux/if_addr.h>
 20 #include <linux/neighbour.h>
 21 #include <linux/rtnetlink.h>
 22 
 23 #include <netlink/msg.h>
 24 #include <netlink/socket.h>
 25 #include <netlink/attr.h>
 26 
 27 #include <arpa/inet.h>
 28 #include <libubox/list.h>
 29 
 30 #include "odhcpd.h"
 31 
 32 struct event_socket {
 33         struct odhcpd_event ev;
 34         struct nl_sock *sock;
 35         int sock_bufsize;
 36 };
 37 
 38 static void handle_rtnl_event(struct odhcpd_event *ev);
 39 static int cb_rtnl_valid(struct nl_msg *msg, void *arg);
 40 static void catch_rtnl_err(struct odhcpd_event *e, int error);
 41 static struct nl_sock *create_socket(int protocol);
 42 
 43 static struct nl_sock *rtnl_socket = NULL;
 44 struct list_head netevent_handler_list = LIST_HEAD_INIT(netevent_handler_list);
 45 static struct event_socket rtnl_event = {
 46         .ev = {
 47                 .uloop = {.fd = - 1, },
 48                 .handle_dgram = NULL,
 49                 .handle_error = catch_rtnl_err,
 50                 .recv_msgs = handle_rtnl_event,
 51         },
 52         .sock = NULL,
 53         .sock_bufsize = 133120,
 54 };
 55 
 56 /* Shut down and free netlink sockets/registration. Safe to call multiple times. */
 57 static void netlink_shutdown(void)
 58 {
 59         /* Deregister event and free the event socket */
 60         if (rtnl_event.sock) {
 61                 odhcpd_deregister(&rtnl_event.ev);
 62 
 63                 if (rtnl_event.ev.uloop.fd >= 0) {
 64                         close(rtnl_event.ev.uloop.fd);
 65                         rtnl_event.ev.uloop.fd = -1;
 66                 }
 67 
 68                 nl_socket_free(rtnl_event.sock);
 69                 rtnl_event.sock = NULL;
 70         }
 71 
 72         /* Free the primary rtnl socket */
 73         if (rtnl_socket) {
 74                 nl_socket_free(rtnl_socket);
 75                 rtnl_socket = NULL;
 76         }
 77 }
 78 
 79 int netlink_init(void)
 80 {
 81         rtnl_socket = create_socket(NETLINK_ROUTE);
 82         if (!rtnl_socket) {
 83                 error("Unable to open nl socket: %m");
 84                 goto err;
 85         }
 86 
 87         rtnl_event.sock = create_socket(NETLINK_ROUTE);
 88         if (!rtnl_event.sock) {
 89                 error("Unable to open nl event socket: %m");
 90                 goto err;
 91         }
 92 
 93         rtnl_event.ev.uloop.fd = nl_socket_get_fd(rtnl_event.sock);
 94 
 95         if (nl_socket_set_buffer_size(rtnl_event.sock, rtnl_event.sock_bufsize, 0))
 96                 goto err;
 97 
 98         nl_socket_disable_seq_check(rtnl_event.sock);
 99 
100         nl_socket_modify_cb(rtnl_event.sock, NL_CB_VALID, NL_CB_CUSTOM,
101                         cb_rtnl_valid, NULL);
102 
103         /* Receive IPv4 address, IPv6 address, IPv6 routes and neighbor events */
104         if (nl_socket_add_memberships(rtnl_event.sock, RTNLGRP_IPV4_IFADDR,
105                                 RTNLGRP_IPV6_IFADDR, RTNLGRP_IPV6_ROUTE,
106                                 RTNLGRP_NEIGH, RTNLGRP_LINK, 0))
107                 goto err;
108 
109         odhcpd_register(&rtnl_event.ev);
110 
111         atexit(netlink_shutdown);
112 
113         return 0;
114 
115 err:
116         netlink_shutdown();
117 
118         return -1;
119 }
120 
121 
122 int netlink_add_netevent_handler(struct netevent_handler *handler)
123 {
124         if (!handler->cb)
125                 return -1;
126 
127         list_add(&handler->head, &netevent_handler_list);
128 
129         return 0;
130 }
131 
132 static void call_netevent_handler_list(unsigned long event, struct netevent_handler_info *info)
133 {
134         struct netevent_handler *handler;
135 
136         list_for_each_entry(handler, &netevent_handler_list, head)
137                 handler->cb(event, info);
138 }
139 
140 static void handle_rtnl_event(struct odhcpd_event *e)
141 {
142         struct event_socket *ev_sock = container_of(e, struct event_socket, ev);
143 
144         nl_recvmsgs_default(ev_sock->sock);
145 }
146 
147 static void refresh_iface_addr4(int ifindex)
148 {
149         struct odhcpd_ipaddr *oaddrs4 = NULL;
150         struct interface *iface;
151         ssize_t oaddrs4_cnt = netlink_get_interface_addrs(ifindex, false, &oaddrs4);
152         bool change = false;
153 
154         if (oaddrs4_cnt < 0)
155                 return;
156 
157         avl_for_each_element(&interfaces, iface, avl) {
158                 struct netevent_handler_info event_info;
159 
160                 if (iface->ifindex != ifindex)
161                         continue;
162 
163                 memset(&event_info, 0, sizeof(event_info));
164                 event_info.iface = iface;
165                 event_info.addrs_old.addrs = iface->oaddrs4;
166                 event_info.addrs_old.len = iface->oaddrs4_cnt;
167 
168                 if (!change) {
169                         change = oaddrs4_cnt != (ssize_t)iface->oaddrs4_cnt;
170                         for (ssize_t i = 0; !change && i < oaddrs4_cnt; i++) {
171                                 if (oaddrs4[i].addr.in.s_addr != iface->oaddrs4[i].addr.in.s_addr)
172                                         change = true;
173                         }
174                 }
175 
176                 iface->oaddrs4 = oaddrs4;
177                 iface->oaddrs4_cnt = oaddrs4_cnt;
178 
179                 if (change)
180                         call_netevent_handler_list(NETEV_ADDRLIST_CHANGE, &event_info);
181 
182                 free(event_info.addrs_old.addrs);
183 
184                 if (!oaddrs4_cnt)
185                         continue;
186 
187                 oaddrs4 = malloc(oaddrs4_cnt * sizeof(*oaddrs4));
188                 if (!oaddrs4)
189                         break;
190 
191                 memcpy(oaddrs4, iface->oaddrs4, oaddrs4_cnt * sizeof(*oaddrs4));
192         }
193 
194         free(oaddrs4);
195 }
196 
197 static void refresh_iface_addr6(int ifindex)
198 {
199         struct odhcpd_ipaddr *oaddrs6 = NULL;
200         struct interface *iface;
201         ssize_t oaddrs6_cnt = netlink_get_interface_addrs(ifindex, true, &oaddrs6);
202         time_t now = odhcpd_time();
203         bool change = false;
204 
205         if (oaddrs6_cnt < 0)
206                 return;
207 
208         avl_for_each_element(&interfaces, iface, avl) {
209                 struct netevent_handler_info event_info;
210 
211                 if (iface->ifindex != ifindex)
212                         continue;
213 
214                 memset(&event_info, 0, sizeof(event_info));
215                 event_info.iface = iface;
216                 event_info.addrs_old.addrs = iface->addr6;
217                 event_info.addrs_old.len = iface->addr6_len;
218 
219                 if (!change) {
220                         change = oaddrs6_cnt != (ssize_t)iface->addr6_len;
221                         for (ssize_t i = 0; !change && i < oaddrs6_cnt; ++i) {
222                                 if (!IN6_ARE_ADDR_EQUAL(&oaddrs6[i].addr.in6, &iface->addr6[i].addr.in6) ||
223                                     oaddrs6[i].prefix_len != iface->addr6[i].prefix_len ||
224                                     (oaddrs6[i].preferred_lt > (uint32_t)now) != (iface->addr6[i].preferred_lt > (uint32_t)now) ||
225                                     oaddrs6[i].valid_lt < iface->addr6[i].valid_lt || oaddrs6[i].preferred_lt < iface->addr6[i].preferred_lt)
226                                         change = true;
227                         }
228                 }
229 
230                 iface->addr6 = oaddrs6;
231                 iface->addr6_len = oaddrs6_cnt;
232 
233                 if (change)
234                         call_netevent_handler_list(NETEV_ADDR6LIST_CHANGE, &event_info);
235 
236                 free(event_info.addrs_old.addrs);
237 
238                 if (!oaddrs6_cnt)
239                         continue;
240 
241                 oaddrs6 = malloc(oaddrs6_cnt * sizeof(*oaddrs6));
242                 if (!oaddrs6)
243                         break;
244 
245                 memcpy(oaddrs6, iface->addr6, oaddrs6_cnt * sizeof(*oaddrs6));
246         }
247 
248         free(oaddrs6);
249 }
250 
251 static int handle_rtm_link(struct nlmsghdr *hdr)
252 {
253         struct ifinfomsg *ifi = nlmsg_data(hdr);
254         struct nlattr *nla[__IFLA_MAX];
255         struct interface *iface;
256         struct netevent_handler_info event_info;
257         const char *ifname;
258 
259         memset(&event_info, 0, sizeof(event_info));
260 
261         if (!nlmsg_valid_hdr(hdr, sizeof(*ifi)) || ifi->ifi_family != AF_UNSPEC)
262                 return NL_SKIP;
263 
264         nlmsg_parse(hdr, sizeof(*ifi), nla, __IFLA_MAX - 1, NULL);
265         if (!nla[IFLA_IFNAME])
266                 return NL_SKIP;
267 
268         ifname = nla_get_string(nla[IFLA_IFNAME]);
269 
270         avl_for_each_element(&interfaces, iface, avl) {
271                 if (strcmp(iface->ifname, ifname))
272                         continue;
273 
274                 iface->ifflags = ifi->ifi_flags;
275 
276                 /* store current MTU if available */
277                 if (nla[IFLA_MTU]) {
278                         iface->if_mtu = nla_get_u32(nla[IFLA_MTU]);
279                         debug("Netlink setting interface '%s' if_mtu MTU to %d",
280                                         iface->name, iface->if_mtu);
281                 }
282 
283                 /*
284                  * Assume for link event of the same index, that link changed
285                  * and reload services to enable or disable them based on the
286                  * RUNNING state of the interface.
287                  */
288                 if (iface->ifindex == ifi->ifi_index) {
289                         reload_services(iface);
290                         continue;
291                 }
292 
293                 iface->ifindex = ifi->ifi_index;
294                 event_info.iface = iface;
295                 call_netevent_handler_list(NETEV_IFINDEX_CHANGE, &event_info);
296         }
297 
298         return NL_OK;
299 }
300 
301 static int handle_rtm_route(struct nlmsghdr *hdr, bool add)
302 {
303         struct rtmsg *rtm = nlmsg_data(hdr);
304         struct nlattr *nla[__RTA_MAX];
305         struct interface *iface;
306         struct netevent_handler_info event_info;
307         int ifindex = 0;
308 
309         if (!nlmsg_valid_hdr(hdr, sizeof(*rtm)) || rtm->rtm_family != AF_INET6)
310                 return NL_SKIP;
311 
312         nlmsg_parse(hdr, sizeof(*rtm), nla, __RTA_MAX - 1, NULL);
313 
314         memset(&event_info, 0, sizeof(event_info));
315         event_info.rt.dst_len = rtm->rtm_dst_len;
316 
317         if (nla[RTA_DST])
318                 nla_memcpy(&event_info.rt.dst, nla[RTA_DST],
319                                 sizeof(event_info.rt.dst));
320 
321         if (nla[RTA_OIF])
322                 ifindex = nla_get_u32(nla[RTA_OIF]);
323 
324         if (nla[RTA_GATEWAY])
325                 nla_memcpy(&event_info.rt.gateway, nla[RTA_GATEWAY],
326                                 sizeof(event_info.rt.gateway));
327 
328         avl_for_each_element(&interfaces, iface, avl) {
329                 if (ifindex && iface->ifindex != ifindex)
330                         continue;
331 
332                 event_info.iface = ifindex ? iface : NULL;
333                 call_netevent_handler_list(add ? NETEV_ROUTE6_ADD : NETEV_ROUTE6_DEL,
334                                                 &event_info);
335         }
336 
337         return NL_OK;
338 }
339 
340 static int handle_rtm_addr(struct nlmsghdr *hdr, bool add)
341 {
342         struct ifaddrmsg *ifa = nlmsg_data(hdr);
343         struct nlattr *nla[__IFA_MAX];
344         struct interface *iface;
345         struct netevent_handler_info event_info;
346         char buf[INET6_ADDRSTRLEN];
347 
348         if (!nlmsg_valid_hdr(hdr, sizeof(*ifa)) ||
349                         (ifa->ifa_family != AF_INET6 &&
350                          ifa->ifa_family != AF_INET))
351                 return NL_SKIP;
352 
353         memset(&event_info, 0, sizeof(event_info));
354 
355         nlmsg_parse(hdr, sizeof(*ifa), nla, __IFA_MAX - 1, NULL);
356 
357         if (ifa->ifa_family == AF_INET6) {
358                 if (!nla[IFA_ADDRESS])
359                         return NL_SKIP;
360 
361                 nla_memcpy(&event_info.addr, nla[IFA_ADDRESS], sizeof(event_info.addr));
362 
363                 if (IN6_IS_ADDR_MULTICAST(&event_info.addr))
364                         return NL_SKIP;
365 
366                 inet_ntop(AF_INET6, &event_info.addr, buf, sizeof(buf));
367 
368                 avl_for_each_element(&interfaces, iface, avl) {
369                         if (iface->ifindex != (int)ifa->ifa_index)
370                                 continue;
371 
372                         if (add && IN6_IS_ADDR_LINKLOCAL(&event_info.addr)) {
373                                 iface->have_link_local = true;
374                                 return NL_SKIP;
375                         }
376 
377                         debug("Netlink %s %s on %s", add ? "newaddr" : "deladdr",
378                               buf, iface->name);
379 
380                         event_info.iface = iface;
381                         call_netevent_handler_list(add ? NETEV_ADDR6_ADD : NETEV_ADDR6_DEL,
382                                                         &event_info);
383                 }
384 
385                 refresh_iface_addr6(ifa->ifa_index);
386         } else {
387                 if (!nla[IFA_LOCAL])
388                         return NL_SKIP;
389 
390                 nla_memcpy(&event_info.addr, nla[IFA_LOCAL], sizeof(event_info.addr));
391 
392                 inet_ntop(AF_INET, &event_info.addr, buf, sizeof(buf));
393 
394                 avl_for_each_element(&interfaces, iface, avl) {
395                         if (iface->ifindex != (int)ifa->ifa_index)
396                                 continue;
397 
398                         debug("Netlink %s %s on %s", add ? "newaddr" : "deladdr",
399                               buf, iface->name);
400 
401                         event_info.iface = iface;
402                         call_netevent_handler_list(add ? NETEV_ADDR_ADD : NETEV_ADDR_DEL,
403                                                         &event_info);
404                 }
405 
406                 refresh_iface_addr4(ifa->ifa_index);
407         }
408 
409         return NL_OK;
410 }
411 
412 static int handle_rtm_neigh(struct nlmsghdr *hdr, bool add)
413 {
414         struct ndmsg *ndm = nlmsg_data(hdr);
415         struct nlattr *nla[__NDA_MAX];
416         struct interface *iface;
417         struct netevent_handler_info event_info;
418         char buf[INET6_ADDRSTRLEN];
419 
420         if (!nlmsg_valid_hdr(hdr, sizeof(*ndm)) ||
421                         ndm->ndm_family != AF_INET6)
422                 return NL_SKIP;
423 
424         nlmsg_parse(hdr, sizeof(*ndm), nla, __NDA_MAX - 1, NULL);
425         if (!nla[NDA_DST])
426                 return NL_SKIP;
427 
428         memset(&event_info, 0, sizeof(event_info));
429 
430         nla_memcpy(&event_info.neigh.dst, nla[NDA_DST], sizeof(event_info.neigh.dst));
431 
432         if (IN6_IS_ADDR_LINKLOCAL(&event_info.neigh.dst) ||
433                         IN6_IS_ADDR_MULTICAST(&event_info.neigh.dst))
434                 return NL_SKIP;
435 
436         inet_ntop(AF_INET6, &event_info.neigh.dst, buf, sizeof(buf));
437 
438         avl_for_each_element(&interfaces, iface, avl) {
439                 if (iface->ifindex != ndm->ndm_ifindex)
440                         continue;
441 
442                 debug("Netlink %s %s on %s", add ? "newneigh" : "delneigh",
443                       buf, iface->name);
444 
445                 event_info.iface = iface;
446                 event_info.neigh.state = ndm->ndm_state;
447                 event_info.neigh.flags = ndm->ndm_flags;
448 
449                 call_netevent_handler_list(add ? NETEV_NEIGH6_ADD : NETEV_NEIGH6_DEL,
450                                                 &event_info);
451         }
452 
453         return NL_OK;
454 }
455 
456 /* Handler for neighbor cache entries from the kernel. This is our source
457  * to learn and unlearn hosts on interfaces. */
458 static int cb_rtnl_valid(struct nl_msg *msg, _o_unused void *arg)
459 {
460         struct nlmsghdr *hdr = nlmsg_hdr(msg);
461         int ret = NL_SKIP;
462         bool add = false;
463 
464         switch (hdr->nlmsg_type) {
465         case RTM_NEWLINK:
466                 ret = handle_rtm_link(hdr);
467                 break;
468 
469         case RTM_NEWROUTE:
470                 add = true;
471                 _o_fallthrough;
472         case RTM_DELROUTE:
473                 ret = handle_rtm_route(hdr, add);
474                 break;
475 
476         case RTM_NEWADDR:
477                 add = true;
478                 _o_fallthrough;
479         case RTM_DELADDR:
480                 ret = handle_rtm_addr(hdr, add);
481                 break;
482 
483         case RTM_NEWNEIGH:
484                 add = true;
485                 _o_fallthrough;
486         case RTM_DELNEIGH:
487                 ret = handle_rtm_neigh(hdr, add);
488                 break;
489 
490         default:
491                 break;
492         }
493 
494         return ret;
495 }
496 
497 static void catch_rtnl_err(struct odhcpd_event *e, int error)
498 {
499         struct event_socket *ev_sock = container_of(e, struct event_socket, ev);
500 
501         if (error != ENOBUFS)
502                 goto err;
503 
504         /* Double netlink event buffer size */
505         ev_sock->sock_bufsize *= 2;
506 
507         if (nl_socket_set_buffer_size(ev_sock->sock, ev_sock->sock_bufsize, 0))
508                 goto err;
509 
510         netlink_dump_addr_table(true);
511         return;
512 
513 err:
514         odhcpd_deregister(e);
515 }
516 
517 static struct nl_sock *create_socket(int protocol)
518 {
519         struct nl_sock *nl_sock;
520 
521         nl_sock = nl_socket_alloc();
522         if (!nl_sock)
523                 goto err;
524 
525         if (nl_connect(nl_sock, protocol) < 0)
526                 goto err;
527 
528         return nl_sock;
529 
530 err:
531         if (nl_sock)
532                 nl_socket_free(nl_sock);
533 
534         return NULL;
535 }
536 
537 
538 struct addr_info {
539         int ifindex;
540         int af;
541         struct odhcpd_ipaddr **oaddrs;
542         bool pending;
543         ssize_t ret;
544 };
545 
546 
547 static int cb_addr_valid(struct nl_msg *msg, void *arg)
548 {
549         struct addr_info *ctxt = (struct addr_info *)arg;
550         struct odhcpd_ipaddr *oaddrs;
551         struct nlmsghdr *hdr = nlmsg_hdr(msg);
552         struct ifaddrmsg *ifa;
553         struct nlattr *nla[__IFA_MAX], *nla_addr = NULL;
554 
555         if (hdr->nlmsg_type != RTM_NEWADDR)
556                 return NL_SKIP;
557 
558         ifa = NLMSG_DATA(hdr);
559         if (ifa->ifa_scope != RT_SCOPE_UNIVERSE ||
560                         (ctxt->af != ifa->ifa_family) ||
561                         (ctxt->ifindex && ifa->ifa_index != (unsigned)ctxt->ifindex))
562                 return NL_SKIP;
563 
564         nlmsg_parse(hdr, sizeof(*ifa), nla, __IFA_MAX - 1, NULL);
565 
566         switch (ifa->ifa_family) {
567         case AF_INET6:
568                 if (nla[IFA_ADDRESS])
569                         nla_addr = nla[IFA_ADDRESS];
570                 break;
571 
572         case AF_INET:
573                 if (nla[IFA_LOCAL])
574                         nla_addr = nla[IFA_LOCAL];
575                 break;
576 
577         default:
578                 break;
579         }
580         if (!nla_addr)
581                 return NL_SKIP;
582 
583         oaddrs = realloc(*(ctxt->oaddrs), sizeof(*oaddrs) * (ctxt->ret + 1));
584         if (!oaddrs)
585                 return NL_SKIP;
586 
587         memset(&oaddrs[ctxt->ret], 0, sizeof(oaddrs[ctxt->ret]));
588         oaddrs[ctxt->ret].prefix_len = ifa->ifa_prefixlen;
589 
590         if (ifa->ifa_family == AF_INET)
591                 oaddrs[ctxt->ret].netmask = htonl(~((1U << (32 - ifa->ifa_prefixlen)) - 1));
592 
593         nla_memcpy(&oaddrs[ctxt->ret].addr, nla_addr, sizeof(oaddrs[ctxt->ret].addr));
594 
595         if (nla[IFA_BROADCAST])
596                 nla_memcpy(&oaddrs[ctxt->ret].broadcast, nla[IFA_BROADCAST],
597                            sizeof(oaddrs[ctxt->ret].broadcast));
598 
599         if (nla[IFA_CACHEINFO]) {
600                 struct ifa_cacheinfo *ifc = nla_data(nla[IFA_CACHEINFO]);
601 
602                 oaddrs[ctxt->ret].preferred_lt = ifc->ifa_prefered;
603                 oaddrs[ctxt->ret].valid_lt = ifc->ifa_valid;
604         }
605 
606         if (ifa->ifa_flags & IFA_F_DEPRECATED)
607                 oaddrs[ctxt->ret].preferred_lt = 0;
608 
609         if (ifa->ifa_family == AF_INET6 &&
610             ifa->ifa_flags & IFA_F_TENTATIVE)
611                 oaddrs[ctxt->ret].tentative = true;
612 
613         ctxt->ret++;
614         *(ctxt->oaddrs) = oaddrs;
615 
616         return NL_OK;
617 }
618 
619 
620 static int cb_addr_finish(_o_unused struct nl_msg *msg, void *arg)
621 {
622         struct addr_info *ctxt = (struct addr_info *)arg;
623 
624         ctxt->pending = false;
625 
626         return NL_STOP;
627 }
628 
629 
630 static int cb_addr_error(_o_unused struct sockaddr_nl *nla, struct nlmsgerr *err,
631                 void *arg)
632 {
633         struct addr_info *ctxt = (struct addr_info *)arg;
634 
635         ctxt->pending = false;
636         ctxt->ret = err->error;
637 
638         return NL_STOP;
639 }
640 
641 
642 static int prefix_cmp(const void *va, const void *vb)
643 {
644         const struct odhcpd_ipaddr *a = va, *b = vb;
645 
646         if (a->prefix_len != b->prefix_len)
647                 return a->prefix_len < b->prefix_len ? 1 : -1;
648 
649         if (ntohl(a->addr.in.s_addr) == ntohl(b->addr.in.s_addr))
650                 return 0;
651 
652         return ntohl(a->addr.in.s_addr) < ntohl(b->addr.in.s_addr) ? 1 : -1;
653 }
654 
655 
656 /* compare IPv6 prefixes */
657 static int prefix6_cmp(const void *va, const void *vb)
658 {
659         const struct odhcpd_ipaddr *a = va, *b = vb;
660         uint32_t a_pref_lt = IN6_IS_ADDR_ULA(&a->addr.in6) ? 1 : a->preferred_lt;
661         uint32_t b_pref_lt = IN6_IS_ADDR_ULA(&b->addr.in6) ? 1 : b->preferred_lt;
662         return (a_pref_lt < b_pref_lt) ? 1 : (a_pref_lt > b_pref_lt) ? -1 : 0;
663 }
664 
665 
666 /* Detect all IPv[46]-addresses currently assigned to the given interface */
667 ssize_t netlink_get_interface_addrs(int ifindex, bool v6, struct odhcpd_ipaddr **oaddrs)
668 {
669         struct nl_msg *msg;
670         struct ifaddrmsg ifa = {
671                 .ifa_family = v6? AF_INET6: AF_INET,
672                 .ifa_prefixlen = 0,
673                 .ifa_flags = 0,
674                 .ifa_scope = 0,
675                 .ifa_index = ifindex,
676         };
677         struct nl_cb *cb = nl_cb_alloc(NL_CB_DEFAULT);
678         struct addr_info ctxt = {
679                 .ifindex = ifindex,
680                 .af = v6? AF_INET6: AF_INET,
681                 .oaddrs = oaddrs,
682                 .ret = 0,
683                 .pending = true,
684         };
685 
686         if (!cb) {
687                 ctxt.ret = -1;
688                 goto out;
689         }
690 
691         msg = nlmsg_alloc_simple(RTM_GETADDR, NLM_F_REQUEST | NLM_F_DUMP);
692 
693         if (!msg) {
694                 ctxt.ret = - 1;
695                 goto out;
696         }
697 
698         nlmsg_append(msg, &ifa, sizeof(ifa), 0);
699 
700         nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, cb_addr_valid, &ctxt);
701         nl_cb_set(cb, NL_CB_FINISH, NL_CB_CUSTOM, cb_addr_finish, &ctxt);
702         nl_cb_err(cb, NL_CB_CUSTOM, cb_addr_error, &ctxt);
703 
704         ctxt.ret = nl_send_auto_complete(rtnl_socket, msg);
705         if (ctxt.ret < 0)
706                 goto free;
707 
708         ctxt.ret = 0;
709         while (ctxt.pending)
710                 nl_recvmsgs(rtnl_socket, cb);
711 
712         if (ctxt.ret <= 0)
713                 goto free;
714 
715         time_t now = odhcpd_time();
716         struct odhcpd_ipaddr *oaddr = *oaddrs;
717 
718         qsort(oaddr, ctxt.ret, sizeof(*oaddr), v6 ? prefix6_cmp : prefix_cmp);
719 
720         for (ssize_t i = 0; i < ctxt.ret; ++i) {
721                 if (oaddr[i].preferred_lt < UINT32_MAX - now)
722                         oaddr[i].preferred_lt += now;
723 
724                 if (oaddr[i].valid_lt < UINT32_MAX - now)
725                         oaddr[i].valid_lt += now;
726         }
727 
728 free:
729         nlmsg_free(msg);
730 out:
731         nl_cb_put(cb);
732 
733         return ctxt.ret;
734 }
735 
736 
737 static int cb_linklocal_valid(struct nl_msg *msg, void *arg)
738 {
739         struct addr_info *ctxt = (struct addr_info *)arg;
740         struct odhcpd_ipaddr *oaddrs;
741         struct nlmsghdr *hdr = nlmsg_hdr(msg);
742         struct ifaddrmsg *ifa;
743         struct nlattr *nla[__IFA_MAX], *nla_addr = NULL;
744         struct in6_addr addr;
745 
746         if (hdr->nlmsg_type != RTM_NEWADDR)
747                 return NL_SKIP;
748 
749         ifa = NLMSG_DATA(hdr);
750         if (ifa->ifa_scope != RT_SCOPE_LINK ||
751                         (ctxt->af != ifa->ifa_family) ||
752                         (ctxt->ifindex && ifa->ifa_index != (unsigned)ctxt->ifindex))
753                 return NL_SKIP;
754 
755         nlmsg_parse(hdr, sizeof(*ifa), nla, __IFA_MAX - 1, NULL);
756 
757         switch (ifa->ifa_family) {
758         case AF_INET6:
759                 if (nla[IFA_ADDRESS])
760                         nla_addr = nla[IFA_ADDRESS];
761                 break;
762 
763         default:
764                 break;
765         }
766         if (!nla_addr)
767                 return NL_SKIP;
768 
769         nla_memcpy(&addr, nla_addr, sizeof(addr));
770 
771         if (!IN6_IS_ADDR_LINKLOCAL(&addr))
772                 return NL_SKIP;
773 
774         oaddrs = realloc(*(ctxt->oaddrs), sizeof(*oaddrs) * (ctxt->ret + 1));
775         if (!oaddrs)
776                 return NL_SKIP;
777 
778         memset(&oaddrs[ctxt->ret], 0, sizeof(oaddrs[ctxt->ret]));
779         memcpy(&oaddrs[ctxt->ret].addr, &addr, sizeof(oaddrs[ctxt->ret].addr));
780 
781         if (ifa->ifa_flags & IFA_F_TENTATIVE)
782                 oaddrs[ctxt->ret].tentative = true;
783 
784         ctxt->ret++;
785         *(ctxt->oaddrs) = oaddrs;
786 
787         return NL_OK;
788 }
789 
790 
791 static int cb_linklocal_finish(_o_unused struct nl_msg *msg, void *arg)
792 {
793         struct addr_info *ctxt = (struct addr_info *)arg;
794 
795         ctxt->pending = false;
796 
797         return NL_STOP;
798 }
799 
800 
801 static int cb_linklocal_error(_o_unused struct sockaddr_nl *nla, struct nlmsgerr *err,
802                 void *arg)
803 {
804         struct addr_info *ctxt = (struct addr_info *)arg;
805 
806         ctxt->pending = false;
807         ctxt->ret = err->error;
808 
809         return NL_STOP;
810 }
811 
812 
813 /* Detect link-local IPv6-addresses currently assigned to the given interface */
814 ssize_t netlink_get_interface_linklocal(int ifindex, struct odhcpd_ipaddr **oaddrs)
815 {
816         struct nl_msg *msg;
817         struct ifaddrmsg ifa = {
818                 .ifa_family = AF_INET6,
819                 .ifa_prefixlen = 0,
820                 .ifa_flags = 0,
821                 .ifa_scope = 0,
822                 .ifa_index = ifindex,
823         };
824         struct nl_cb *cb = nl_cb_alloc(NL_CB_DEFAULT);
825         struct addr_info ctxt = {
826                 .ifindex = ifindex,
827                 .af = AF_INET6,
828                 .oaddrs = oaddrs,
829                 .ret = 0,
830                 .pending = true,
831         };
832 
833         if (!cb) {
834                 ctxt.ret = -1;
835                 goto out;
836         }
837 
838         msg = nlmsg_alloc_simple(RTM_GETADDR, NLM_F_REQUEST | NLM_F_DUMP);
839 
840         if (!msg) {
841                 ctxt.ret = - 1;
842                 goto out;
843         }
844 
845         nlmsg_append(msg, &ifa, sizeof(ifa), 0);
846 
847         nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, cb_linklocal_valid, &ctxt);
848         nl_cb_set(cb, NL_CB_FINISH, NL_CB_CUSTOM, cb_linklocal_finish, &ctxt);
849         nl_cb_err(cb, NL_CB_CUSTOM, cb_linklocal_error, &ctxt);
850 
851         ctxt.ret = nl_send_auto_complete(rtnl_socket, msg);
852         if (ctxt.ret < 0)
853                 goto free;
854 
855         ctxt.ret = 0;
856         while (ctxt.pending)
857                 nl_recvmsgs(rtnl_socket, cb);
858 
859         if (ctxt.ret <= 0)
860                 goto free;
861 
862 free:
863         nlmsg_free(msg);
864 out:
865         nl_cb_put(cb);
866 
867         return ctxt.ret;
868 }
869 
870 
871 struct neigh_info {
872         int ifindex;
873         bool pending;
874         const struct in6_addr *addr;
875         int ret;
876 };
877 
878 
879 static int cb_proxy_neigh_valid(struct nl_msg *msg, void *arg)
880 {
881         struct neigh_info *ctxt = (struct neigh_info *)arg;
882         struct nlmsghdr *hdr = nlmsg_hdr(msg);
883         struct ndmsg *ndm;
884         struct nlattr *nla_dst;
885 
886         if (hdr->nlmsg_type != RTM_NEWNEIGH)
887                 return NL_SKIP;
888 
889         ndm = NLMSG_DATA(hdr);
890         if (ndm->ndm_family != AF_INET6 ||
891                         (ctxt->ifindex && ndm->ndm_ifindex != ctxt->ifindex))
892                 return NL_SKIP;
893 
894         if (!(ndm->ndm_flags & NTF_PROXY))
895                 return NL_SKIP;
896 
897         nla_dst = nlmsg_find_attr(hdr, sizeof(*ndm), NDA_DST);
898         if (!nla_dst)
899                 return NL_SKIP;
900 
901         if (nla_memcmp(nla_dst,ctxt->addr, 16) == 0)
902                 ctxt->ret = 1;
903 
904         return NL_OK;
905 }
906 
907 
908 static int cb_proxy_neigh_finish(_o_unused struct nl_msg *msg, void *arg)
909 {
910         struct neigh_info *ctxt = (struct neigh_info *)arg;
911 
912         ctxt->pending = false;
913 
914         return NL_STOP;
915 }
916 
917 
918 static int cb_proxy_neigh_error(_o_unused struct sockaddr_nl *nla, struct nlmsgerr *err,
919                 void *arg)
920 {
921         struct neigh_info *ctxt = (struct neigh_info *)arg;
922 
923         ctxt->pending = false;
924         ctxt->ret = err->error;
925 
926         return NL_STOP;
927 }
928 
929 /* Detect an IPV6-address proxy neighbor for the given interface */
930 int netlink_get_interface_proxy_neigh(int ifindex, const struct in6_addr *addr)
931 {
932         struct nl_msg *msg;
933         struct ndmsg ndm = {
934                 .ndm_family = AF_INET6,
935                 .ndm_flags = NTF_PROXY,
936                 .ndm_ifindex = ifindex,
937         };
938         struct nl_cb *cb = nl_cb_alloc(NL_CB_DEFAULT);
939         struct neigh_info ctxt = {
940                 .ifindex = ifindex,
941                 .addr = addr,
942                 .ret = 0,
943                 .pending = true,
944         };
945 
946         if (!cb) {
947                 ctxt.ret = -1;
948                 goto out;
949         }
950 
951         msg = nlmsg_alloc_simple(RTM_GETNEIGH, NLM_F_REQUEST | NLM_F_MATCH);
952 
953         if (!msg) {
954                 ctxt.ret = -1;
955                 goto out;
956         }
957 
958         nlmsg_append(msg, &ndm, sizeof(ndm), 0);
959         nla_put(msg, NDA_DST, sizeof(*addr), addr);
960 
961         nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, cb_proxy_neigh_valid, &ctxt);
962         nl_cb_set(cb, NL_CB_FINISH, NL_CB_CUSTOM, cb_proxy_neigh_finish, &ctxt);
963         nl_cb_err(cb, NL_CB_CUSTOM, cb_proxy_neigh_error, &ctxt);
964 
965         ctxt.ret = nl_send_auto_complete(rtnl_socket, msg);
966         if (ctxt.ret < 0)
967                 goto free;
968 
969         while (ctxt.pending)
970                 nl_recvmsgs(rtnl_socket, cb);
971 
972 free:
973         nlmsg_free(msg);
974 out:
975         nl_cb_put(cb);
976 
977         return ctxt.ret;
978 }
979 
980 
981 int netlink_setup_route(const struct in6_addr *addr, const int prefixlen,
982                 const int ifindex, const struct in6_addr *gw,
983                 const uint32_t metric, const bool add)
984 {
985         struct nl_msg *msg;
986         struct rtmsg rtm = {
987                 .rtm_family = AF_INET6,
988                 .rtm_dst_len = prefixlen,
989                 .rtm_src_len = 0,
990                 .rtm_table = RT_TABLE_MAIN,
991                 .rtm_protocol = (add ? RTPROT_STATIC : RTPROT_UNSPEC),
992                 .rtm_scope = (add ? (gw ? RT_SCOPE_UNIVERSE : RT_SCOPE_LINK) : RT_SCOPE_NOWHERE),
993                 .rtm_type = (add ? RTN_UNICAST : RTN_UNSPEC),
994         };
995         int ret = 0;
996 
997         msg = nlmsg_alloc_simple(add ? RTM_NEWROUTE : RTM_DELROUTE,
998                                         add ? NLM_F_CREATE | NLM_F_REPLACE : 0);
999         if (!msg)
1000                 return -1;
1001 
1002         nlmsg_append(msg, &rtm, sizeof(rtm), 0);
1003 
1004         nla_put(msg, RTA_DST, sizeof(*addr), addr);
1005         nla_put_u32(msg, RTA_OIF, ifindex);
1006         nla_put_u32(msg, RTA_PRIORITY, metric);
1007 
1008         if (gw)
1009                 nla_put(msg, RTA_GATEWAY, sizeof(*gw), gw);
1010 
1011         ret = nl_send_auto_complete(rtnl_socket, msg);
1012         nlmsg_free(msg);
1013 
1014         if (ret < 0)
1015                 return ret;
1016 
1017         return nl_wait_for_ack(rtnl_socket);
1018 }
1019 
1020 
1021 int netlink_setup_proxy_neigh(const struct in6_addr *addr,
1022                 const int ifindex, const bool add)
1023 {
1024         struct nl_msg *msg;
1025         struct ndmsg ndm = {
1026                 .ndm_family = AF_INET6,
1027                 .ndm_flags = NTF_PROXY,
1028                 .ndm_ifindex = ifindex,
1029         };
1030         int ret = 0, flags = NLM_F_REQUEST;
1031 
1032         if (add)
1033                 flags |= NLM_F_REPLACE | NLM_F_CREATE;
1034 
1035         msg = nlmsg_alloc_simple(add ? RTM_NEWNEIGH : RTM_DELNEIGH, flags);
1036         if (!msg)
1037                 return -1;
1038 
1039         nlmsg_append(msg, &ndm, sizeof(ndm), 0);
1040 
1041         nla_put(msg, NDA_DST, sizeof(*addr), addr);
1042 
1043         ret = nl_send_auto_complete(rtnl_socket, msg);
1044         nlmsg_free(msg);
1045 
1046         if (ret < 0)
1047                 return ret;
1048 
1049         return nl_wait_for_ack(rtnl_socket);
1050 }
1051 
1052 
1053 int netlink_setup_addr(struct odhcpd_ipaddr *oaddr,
1054                        const int ifindex, const bool v6, const bool add)
1055 {
1056         struct nl_msg *msg;
1057         struct ifaddrmsg ifa = {
1058                 .ifa_family = v6 ? AF_INET6 : AF_INET,
1059                 .ifa_prefixlen = oaddr->prefix_len,
1060                 .ifa_flags = 0,
1061                 .ifa_scope = 0,
1062                 .ifa_index = ifindex,
1063         };
1064         int ret = 0, flags = NLM_F_REQUEST;
1065 
1066         if (add)
1067                 flags |= NLM_F_REPLACE | NLM_F_CREATE;
1068 
1069         msg = nlmsg_alloc_simple(add ? RTM_NEWADDR : RTM_DELADDR, 0);
1070         if (!msg)
1071                 return -1;
1072 
1073         nlmsg_append(msg, &ifa, sizeof(ifa), flags);
1074         nla_put(msg, IFA_LOCAL, v6 ? 16 : 4, &oaddr->addr);
1075         if (v6) {
1076                 struct ifa_cacheinfo cinfo = {
1077                         .ifa_prefered = 0xffffffffU,
1078                         .ifa_valid = 0xffffffffU,
1079                         .cstamp = 0,
1080                         .tstamp = 0,
1081                 };
1082                 time_t now = odhcpd_time();
1083 
1084                 if (oaddr->preferred_lt) {
1085                         int64_t preferred_lt = oaddr->preferred_lt - now;
1086                         if (preferred_lt < 0)
1087                                 preferred_lt = 0;
1088                         else if (preferred_lt > UINT32_MAX)
1089                                 preferred_lt = UINT32_MAX;
1090 
1091                         cinfo.ifa_prefered = preferred_lt;
1092                 }
1093 
1094                 if (oaddr->valid_lt) {
1095                         int64_t valid_lt = oaddr->valid_lt - now;
1096                         if (valid_lt <= 0) {
1097                                 nlmsg_free(msg);
1098                                 return -1;
1099                         }
1100                         else if (valid_lt > UINT32_MAX)
1101                                 valid_lt = UINT32_MAX;
1102 
1103                         cinfo.ifa_valid = valid_lt;
1104                 }
1105 
1106                 nla_put(msg, IFA_CACHEINFO, sizeof(cinfo), &cinfo);
1107 
1108                 nla_put_u32(msg, IFA_FLAGS, IFA_F_NOPREFIXROUTE);
1109         } else {
1110                 if (oaddr->broadcast.s_addr)
1111                         nla_put_u32(msg, IFA_BROADCAST, oaddr->broadcast.s_addr);
1112         }
1113 
1114         ret = nl_send_auto_complete(rtnl_socket, msg);
1115         nlmsg_free(msg);
1116 
1117         if (ret < 0)
1118                 return ret;
1119 
1120         return nl_wait_for_ack(rtnl_socket);
1121 }
1122 
1123 void netlink_dump_neigh_table(const bool proxy)
1124 {
1125         struct nl_msg *msg;
1126         struct ndmsg ndm = {
1127                 .ndm_family = AF_INET6,
1128                 .ndm_flags = proxy ? NTF_PROXY : 0,
1129         };
1130 
1131         msg = nlmsg_alloc_simple(RTM_GETNEIGH, NLM_F_REQUEST | NLM_F_DUMP);
1132         if (!msg)
1133                 return;
1134 
1135         nlmsg_append(msg, &ndm, sizeof(ndm), 0);
1136 
1137         nl_send_auto_complete(rtnl_event.sock, msg);
1138 
1139         nlmsg_free(msg);
1140 }
1141 
1142 void netlink_dump_addr_table(const bool v6)
1143 {
1144         struct nl_msg *msg;
1145         struct ifaddrmsg ifa = {
1146                 .ifa_family = v6 ? AF_INET6 : AF_INET,
1147         };
1148 
1149         msg = nlmsg_alloc_simple(RTM_GETADDR, NLM_F_REQUEST | NLM_F_DUMP);
1150         if (!msg)
1151                 return;
1152 
1153         nlmsg_append(msg, &ifa, sizeof(ifa), 0);
1154 
1155         nl_send_auto_complete(rtnl_event.sock, msg);
1156 
1157         nlmsg_free(msg);
1158 }
1159 

This page was automatically generated by LXR 0.3.1.  •  OpenWrt