• 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                 /* ifa_prefixlen is 0..32. A /0 prefix turns "32 - prefix" into a
592                  * 32-bit shift on a 32-bit type, which is undefined behaviour;
593                  * compute the host mask in 64-bit and truncate so /0 yields a
594                  * zero netmask as expected. */
595                 uint32_t host_bits = (uint32_t)((1ULL << (32 - ifa->ifa_prefixlen)) - 1);
596                 oaddrs[ctxt->ret].netmask = htonl(~host_bits);
597         }
598 
599         nla_memcpy(&oaddrs[ctxt->ret].addr, nla_addr, sizeof(oaddrs[ctxt->ret].addr));
600 
601         if (nla[IFA_BROADCAST])
602                 nla_memcpy(&oaddrs[ctxt->ret].broadcast, nla[IFA_BROADCAST],
603                            sizeof(oaddrs[ctxt->ret].broadcast));
604 
605         if (nla[IFA_CACHEINFO]) {
606                 struct ifa_cacheinfo *ifc = nla_data(nla[IFA_CACHEINFO]);
607 
608                 oaddrs[ctxt->ret].preferred_lt = ifc->ifa_prefered;
609                 oaddrs[ctxt->ret].valid_lt = ifc->ifa_valid;
610         }
611 
612         if (ifa->ifa_flags & IFA_F_DEPRECATED)
613                 oaddrs[ctxt->ret].preferred_lt = 0;
614 
615         if (ifa->ifa_family == AF_INET6 &&
616             ifa->ifa_flags & IFA_F_TENTATIVE)
617                 oaddrs[ctxt->ret].tentative = true;
618 
619         ctxt->ret++;
620         *(ctxt->oaddrs) = oaddrs;
621 
622         return NL_OK;
623 }
624 
625 
626 static int cb_addr_finish(_o_unused struct nl_msg *msg, void *arg)
627 {
628         struct addr_info *ctxt = (struct addr_info *)arg;
629 
630         ctxt->pending = false;
631 
632         return NL_STOP;
633 }
634 
635 
636 static int cb_addr_error(_o_unused struct sockaddr_nl *nla, struct nlmsgerr *err,
637                 void *arg)
638 {
639         struct addr_info *ctxt = (struct addr_info *)arg;
640 
641         ctxt->pending = false;
642         ctxt->ret = err->error;
643 
644         return NL_STOP;
645 }
646 
647 
648 static int prefix_cmp(const void *va, const void *vb)
649 {
650         const struct odhcpd_ipaddr *a = va, *b = vb;
651 
652         if (a->prefix_len != b->prefix_len)
653                 return a->prefix_len < b->prefix_len ? 1 : -1;
654 
655         if (ntohl(a->addr.in.s_addr) == ntohl(b->addr.in.s_addr))
656                 return 0;
657 
658         return ntohl(a->addr.in.s_addr) < ntohl(b->addr.in.s_addr) ? 1 : -1;
659 }
660 
661 
662 /* compare IPv6 prefixes */
663 static int prefix6_cmp(const void *va, const void *vb)
664 {
665         const struct odhcpd_ipaddr *a = va, *b = vb;
666         uint32_t a_pref_lt = IN6_IS_ADDR_ULA(&a->addr.in6) ? 1 : a->preferred_lt;
667         uint32_t b_pref_lt = IN6_IS_ADDR_ULA(&b->addr.in6) ? 1 : b->preferred_lt;
668         return (a_pref_lt < b_pref_lt) ? 1 : (a_pref_lt > b_pref_lt) ? -1 : 0;
669 }
670 
671 
672 /* Detect all IPv[46]-addresses currently assigned to the given interface */
673 ssize_t netlink_get_interface_addrs(int ifindex, bool v6, struct odhcpd_ipaddr **oaddrs)
674 {
675         struct nl_msg *msg;
676         struct ifaddrmsg ifa = {
677                 .ifa_family = v6? AF_INET6: AF_INET,
678                 .ifa_prefixlen = 0,
679                 .ifa_flags = 0,
680                 .ifa_scope = 0,
681                 .ifa_index = ifindex,
682         };
683         struct nl_cb *cb = nl_cb_alloc(NL_CB_DEFAULT);
684         struct addr_info ctxt = {
685                 .ifindex = ifindex,
686                 .af = v6? AF_INET6: AF_INET,
687                 .oaddrs = oaddrs,
688                 .ret = 0,
689                 .pending = true,
690         };
691 
692         if (!cb) {
693                 ctxt.ret = -1;
694                 goto out;
695         }
696 
697         msg = nlmsg_alloc_simple(RTM_GETADDR, NLM_F_REQUEST | NLM_F_DUMP);
698 
699         if (!msg) {
700                 ctxt.ret = - 1;
701                 goto out;
702         }
703 
704         nlmsg_append(msg, &ifa, sizeof(ifa), 0);
705 
706         nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, cb_addr_valid, &ctxt);
707         nl_cb_set(cb, NL_CB_FINISH, NL_CB_CUSTOM, cb_addr_finish, &ctxt);
708         nl_cb_err(cb, NL_CB_CUSTOM, cb_addr_error, &ctxt);
709 
710         ctxt.ret = nl_send_auto_complete(rtnl_socket, msg);
711         if (ctxt.ret < 0)
712                 goto free;
713 
714         ctxt.ret = 0;
715         while (ctxt.pending)
716                 nl_recvmsgs(rtnl_socket, cb);
717 
718         if (ctxt.ret <= 0)
719                 goto free;
720 
721         time_t now = odhcpd_time();
722         struct odhcpd_ipaddr *oaddr = *oaddrs;
723 
724         qsort(oaddr, ctxt.ret, sizeof(*oaddr), v6 ? prefix6_cmp : prefix_cmp);
725 
726         for (ssize_t i = 0; i < ctxt.ret; ++i) {
727                 if (oaddr[i].preferred_lt < UINT32_MAX - now)
728                         oaddr[i].preferred_lt += now;
729 
730                 if (oaddr[i].valid_lt < UINT32_MAX - now)
731                         oaddr[i].valid_lt += now;
732         }
733 
734 free:
735         nlmsg_free(msg);
736 out:
737         nl_cb_put(cb);
738 
739         return ctxt.ret;
740 }
741 
742 
743 static int cb_linklocal_valid(struct nl_msg *msg, void *arg)
744 {
745         struct addr_info *ctxt = (struct addr_info *)arg;
746         struct odhcpd_ipaddr *oaddrs;
747         struct nlmsghdr *hdr = nlmsg_hdr(msg);
748         struct ifaddrmsg *ifa;
749         struct nlattr *nla[__IFA_MAX], *nla_addr = NULL;
750         struct in6_addr addr;
751 
752         if (hdr->nlmsg_type != RTM_NEWADDR)
753                 return NL_SKIP;
754 
755         ifa = NLMSG_DATA(hdr);
756         if (ifa->ifa_scope != RT_SCOPE_LINK ||
757                         (ctxt->af != ifa->ifa_family) ||
758                         (ctxt->ifindex && ifa->ifa_index != (unsigned)ctxt->ifindex))
759                 return NL_SKIP;
760 
761         nlmsg_parse(hdr, sizeof(*ifa), nla, __IFA_MAX - 1, NULL);
762 
763         switch (ifa->ifa_family) {
764         case AF_INET6:
765                 if (nla[IFA_ADDRESS])
766                         nla_addr = nla[IFA_ADDRESS];
767                 break;
768 
769         default:
770                 break;
771         }
772         if (!nla_addr)
773                 return NL_SKIP;
774 
775         nla_memcpy(&addr, nla_addr, sizeof(addr));
776 
777         if (!IN6_IS_ADDR_LINKLOCAL(&addr))
778                 return NL_SKIP;
779 
780         oaddrs = realloc(*(ctxt->oaddrs), sizeof(*oaddrs) * (ctxt->ret + 1));
781         if (!oaddrs)
782                 return NL_SKIP;
783 
784         memset(&oaddrs[ctxt->ret], 0, sizeof(oaddrs[ctxt->ret]));
785         memcpy(&oaddrs[ctxt->ret].addr, &addr, sizeof(oaddrs[ctxt->ret].addr));
786 
787         if (ifa->ifa_flags & IFA_F_TENTATIVE)
788                 oaddrs[ctxt->ret].tentative = true;
789 
790         ctxt->ret++;
791         *(ctxt->oaddrs) = oaddrs;
792 
793         return NL_OK;
794 }
795 
796 
797 static int cb_linklocal_finish(_o_unused struct nl_msg *msg, void *arg)
798 {
799         struct addr_info *ctxt = (struct addr_info *)arg;
800 
801         ctxt->pending = false;
802 
803         return NL_STOP;
804 }
805 
806 
807 static int cb_linklocal_error(_o_unused struct sockaddr_nl *nla, struct nlmsgerr *err,
808                 void *arg)
809 {
810         struct addr_info *ctxt = (struct addr_info *)arg;
811 
812         ctxt->pending = false;
813         ctxt->ret = err->error;
814 
815         return NL_STOP;
816 }
817 
818 
819 /* Detect link-local IPv6-addresses currently assigned to the given interface */
820 ssize_t netlink_get_interface_linklocal(int ifindex, struct odhcpd_ipaddr **oaddrs)
821 {
822         struct nl_msg *msg;
823         struct ifaddrmsg ifa = {
824                 .ifa_family = AF_INET6,
825                 .ifa_prefixlen = 0,
826                 .ifa_flags = 0,
827                 .ifa_scope = 0,
828                 .ifa_index = ifindex,
829         };
830         struct nl_cb *cb = nl_cb_alloc(NL_CB_DEFAULT);
831         struct addr_info ctxt = {
832                 .ifindex = ifindex,
833                 .af = AF_INET6,
834                 .oaddrs = oaddrs,
835                 .ret = 0,
836                 .pending = true,
837         };
838 
839         if (!cb) {
840                 ctxt.ret = -1;
841                 goto out;
842         }
843 
844         msg = nlmsg_alloc_simple(RTM_GETADDR, NLM_F_REQUEST | NLM_F_DUMP);
845 
846         if (!msg) {
847                 ctxt.ret = - 1;
848                 goto out;
849         }
850 
851         nlmsg_append(msg, &ifa, sizeof(ifa), 0);
852 
853         nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, cb_linklocal_valid, &ctxt);
854         nl_cb_set(cb, NL_CB_FINISH, NL_CB_CUSTOM, cb_linklocal_finish, &ctxt);
855         nl_cb_err(cb, NL_CB_CUSTOM, cb_linklocal_error, &ctxt);
856 
857         ctxt.ret = nl_send_auto_complete(rtnl_socket, msg);
858         if (ctxt.ret < 0)
859                 goto free;
860 
861         ctxt.ret = 0;
862         while (ctxt.pending)
863                 nl_recvmsgs(rtnl_socket, cb);
864 
865         if (ctxt.ret <= 0)
866                 goto free;
867 
868 free:
869         nlmsg_free(msg);
870 out:
871         nl_cb_put(cb);
872 
873         return ctxt.ret;
874 }
875 
876 
877 struct neigh_info {
878         int ifindex;
879         bool pending;
880         const struct in6_addr *addr;
881         int ret;
882 };
883 
884 
885 static int cb_proxy_neigh_valid(struct nl_msg *msg, void *arg)
886 {
887         struct neigh_info *ctxt = (struct neigh_info *)arg;
888         struct nlmsghdr *hdr = nlmsg_hdr(msg);
889         struct ndmsg *ndm;
890         struct nlattr *nla_dst;
891 
892         if (hdr->nlmsg_type != RTM_NEWNEIGH)
893                 return NL_SKIP;
894 
895         ndm = NLMSG_DATA(hdr);
896         if (ndm->ndm_family != AF_INET6 ||
897                         (ctxt->ifindex && ndm->ndm_ifindex != ctxt->ifindex))
898                 return NL_SKIP;
899 
900         if (!(ndm->ndm_flags & NTF_PROXY))
901                 return NL_SKIP;
902 
903         nla_dst = nlmsg_find_attr(hdr, sizeof(*ndm), NDA_DST);
904         if (!nla_dst)
905                 return NL_SKIP;
906 
907         if (nla_memcmp(nla_dst,ctxt->addr, 16) == 0)
908                 ctxt->ret = 1;
909 
910         return NL_OK;
911 }
912 
913 
914 static int cb_proxy_neigh_finish(_o_unused struct nl_msg *msg, void *arg)
915 {
916         struct neigh_info *ctxt = (struct neigh_info *)arg;
917 
918         ctxt->pending = false;
919 
920         return NL_STOP;
921 }
922 
923 
924 static int cb_proxy_neigh_error(_o_unused struct sockaddr_nl *nla, struct nlmsgerr *err,
925                 void *arg)
926 {
927         struct neigh_info *ctxt = (struct neigh_info *)arg;
928 
929         ctxt->pending = false;
930         ctxt->ret = err->error;
931 
932         return NL_STOP;
933 }
934 
935 /* Detect an IPV6-address proxy neighbor for the given interface */
936 int netlink_get_interface_proxy_neigh(int ifindex, const struct in6_addr *addr)
937 {
938         struct nl_msg *msg;
939         struct ndmsg ndm = {
940                 .ndm_family = AF_INET6,
941                 .ndm_flags = NTF_PROXY,
942                 .ndm_ifindex = ifindex,
943         };
944         struct nl_cb *cb = nl_cb_alloc(NL_CB_DEFAULT);
945         struct neigh_info ctxt = {
946                 .ifindex = ifindex,
947                 .addr = addr,
948                 .ret = 0,
949                 .pending = true,
950         };
951 
952         if (!cb) {
953                 ctxt.ret = -1;
954                 goto out;
955         }
956 
957         msg = nlmsg_alloc_simple(RTM_GETNEIGH, NLM_F_REQUEST | NLM_F_MATCH);
958 
959         if (!msg) {
960                 ctxt.ret = -1;
961                 goto out;
962         }
963 
964         nlmsg_append(msg, &ndm, sizeof(ndm), 0);
965         nla_put(msg, NDA_DST, sizeof(*addr), addr);
966 
967         nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, cb_proxy_neigh_valid, &ctxt);
968         nl_cb_set(cb, NL_CB_FINISH, NL_CB_CUSTOM, cb_proxy_neigh_finish, &ctxt);
969         nl_cb_err(cb, NL_CB_CUSTOM, cb_proxy_neigh_error, &ctxt);
970 
971         ctxt.ret = nl_send_auto_complete(rtnl_socket, msg);
972         if (ctxt.ret < 0)
973                 goto free;
974 
975         while (ctxt.pending)
976                 nl_recvmsgs(rtnl_socket, cb);
977 
978 free:
979         nlmsg_free(msg);
980 out:
981         nl_cb_put(cb);
982 
983         return ctxt.ret;
984 }
985 
986 
987 int netlink_setup_route(const struct in6_addr *addr, const int prefixlen,
988                 const int ifindex, const struct in6_addr *gw,
989                 const uint32_t metric, const bool add)
990 {
991         struct nl_msg *msg;
992         struct rtmsg rtm = {
993                 .rtm_family = AF_INET6,
994                 .rtm_dst_len = prefixlen,
995                 .rtm_src_len = 0,
996                 .rtm_table = RT_TABLE_MAIN,
997                 .rtm_protocol = (add ? RTPROT_STATIC : RTPROT_UNSPEC),
998                 .rtm_scope = (add ? (gw ? RT_SCOPE_UNIVERSE : RT_SCOPE_LINK) : RT_SCOPE_NOWHERE),
999                 .rtm_type = (add ? RTN_UNICAST : RTN_UNSPEC),
1000         };
1001         int ret = 0;
1002 
1003         msg = nlmsg_alloc_simple(add ? RTM_NEWROUTE : RTM_DELROUTE,
1004                                         add ? NLM_F_CREATE | NLM_F_REPLACE : 0);
1005         if (!msg)
1006                 return -1;
1007 
1008         nlmsg_append(msg, &rtm, sizeof(rtm), 0);
1009 
1010         nla_put(msg, RTA_DST, sizeof(*addr), addr);
1011         nla_put_u32(msg, RTA_OIF, ifindex);
1012         nla_put_u32(msg, RTA_PRIORITY, metric);
1013 
1014         if (gw)
1015                 nla_put(msg, RTA_GATEWAY, sizeof(*gw), gw);
1016 
1017         ret = nl_send_auto_complete(rtnl_socket, msg);
1018         nlmsg_free(msg);
1019 
1020         if (ret < 0)
1021                 return ret;
1022 
1023         return nl_wait_for_ack(rtnl_socket);
1024 }
1025 
1026 
1027 int netlink_setup_proxy_neigh(const struct in6_addr *addr,
1028                 const int ifindex, const bool add)
1029 {
1030         struct nl_msg *msg;
1031         struct ndmsg ndm = {
1032                 .ndm_family = AF_INET6,
1033                 .ndm_flags = NTF_PROXY,
1034                 .ndm_ifindex = ifindex,
1035         };
1036         int ret = 0, flags = NLM_F_REQUEST;
1037 
1038         if (add)
1039                 flags |= NLM_F_REPLACE | NLM_F_CREATE;
1040 
1041         msg = nlmsg_alloc_simple(add ? RTM_NEWNEIGH : RTM_DELNEIGH, flags);
1042         if (!msg)
1043                 return -1;
1044 
1045         nlmsg_append(msg, &ndm, sizeof(ndm), 0);
1046 
1047         nla_put(msg, NDA_DST, sizeof(*addr), addr);
1048 
1049         ret = nl_send_auto_complete(rtnl_socket, msg);
1050         nlmsg_free(msg);
1051 
1052         if (ret < 0)
1053                 return ret;
1054 
1055         return nl_wait_for_ack(rtnl_socket);
1056 }
1057 
1058 
1059 int netlink_setup_addr(struct odhcpd_ipaddr *oaddr,
1060                        const int ifindex, const bool v6, const bool add)
1061 {
1062         struct nl_msg *msg;
1063         struct ifaddrmsg ifa = {
1064                 .ifa_family = v6 ? AF_INET6 : AF_INET,
1065                 .ifa_prefixlen = oaddr->prefix_len,
1066                 .ifa_flags = 0,
1067                 .ifa_scope = 0,
1068                 .ifa_index = ifindex,
1069         };
1070         int ret = 0, flags = NLM_F_REQUEST;
1071 
1072         if (add)
1073                 flags |= NLM_F_REPLACE | NLM_F_CREATE;
1074 
1075         msg = nlmsg_alloc_simple(add ? RTM_NEWADDR : RTM_DELADDR, 0);
1076         if (!msg)
1077                 return -1;
1078 
1079         nlmsg_append(msg, &ifa, sizeof(ifa), flags);
1080         nla_put(msg, IFA_LOCAL, v6 ? 16 : 4, &oaddr->addr);
1081         if (v6) {
1082                 struct ifa_cacheinfo cinfo = {
1083                         .ifa_prefered = 0xffffffffU,
1084                         .ifa_valid = 0xffffffffU,
1085                         .cstamp = 0,
1086                         .tstamp = 0,
1087                 };
1088                 time_t now = odhcpd_time();
1089 
1090                 if (oaddr->preferred_lt) {
1091                         int64_t preferred_lt = oaddr->preferred_lt - now;
1092                         if (preferred_lt < 0)
1093                                 preferred_lt = 0;
1094                         else if (preferred_lt > UINT32_MAX)
1095                                 preferred_lt = UINT32_MAX;
1096 
1097                         cinfo.ifa_prefered = preferred_lt;
1098                 }
1099 
1100                 if (oaddr->valid_lt) {
1101                         int64_t valid_lt = oaddr->valid_lt - now;
1102                         if (valid_lt <= 0) {
1103                                 nlmsg_free(msg);
1104                                 return -1;
1105                         }
1106                         else if (valid_lt > UINT32_MAX)
1107                                 valid_lt = UINT32_MAX;
1108 
1109                         cinfo.ifa_valid = valid_lt;
1110                 }
1111 
1112                 nla_put(msg, IFA_CACHEINFO, sizeof(cinfo), &cinfo);
1113 
1114                 nla_put_u32(msg, IFA_FLAGS, IFA_F_NOPREFIXROUTE);
1115         } else {
1116                 if (oaddr->broadcast.s_addr)
1117                         nla_put_u32(msg, IFA_BROADCAST, oaddr->broadcast.s_addr);
1118         }
1119 
1120         ret = nl_send_auto_complete(rtnl_socket, msg);
1121         nlmsg_free(msg);
1122 
1123         if (ret < 0)
1124                 return ret;
1125 
1126         return nl_wait_for_ack(rtnl_socket);
1127 }
1128 
1129 void netlink_dump_neigh_table(const bool proxy)
1130 {
1131         struct nl_msg *msg;
1132         struct ndmsg ndm = {
1133                 .ndm_family = AF_INET6,
1134                 .ndm_flags = proxy ? NTF_PROXY : 0,
1135         };
1136 
1137         msg = nlmsg_alloc_simple(RTM_GETNEIGH, NLM_F_REQUEST | NLM_F_DUMP);
1138         if (!msg)
1139                 return;
1140 
1141         nlmsg_append(msg, &ndm, sizeof(ndm), 0);
1142 
1143         nl_send_auto_complete(rtnl_event.sock, msg);
1144 
1145         nlmsg_free(msg);
1146 }
1147 
1148 void netlink_dump_addr_table(const bool v6)
1149 {
1150         struct nl_msg *msg;
1151         struct ifaddrmsg ifa = {
1152                 .ifa_family = v6 ? AF_INET6 : AF_INET,
1153         };
1154 
1155         msg = nlmsg_alloc_simple(RTM_GETADDR, NLM_F_REQUEST | NLM_F_DUMP);
1156         if (!msg)
1157                 return;
1158 
1159         nlmsg_append(msg, &ifa, sizeof(ifa), 0);
1160 
1161         nl_send_auto_complete(rtnl_event.sock, msg);
1162 
1163         nlmsg_free(msg);
1164 }
1165 

This page was automatically generated by LXR 0.3.1.  •  OpenWrt