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

This page was automatically generated by LXR 0.3.1.  •  OpenWrt