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

This page was automatically generated by LXR 0.3.1.  •  OpenWrt