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

This page was automatically generated by LXR 0.3.1.  •  OpenWrt