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

This page was automatically generated by LXR 0.3.1.  •  OpenWrt