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

This page was automatically generated by LXR 0.3.1.  •  OpenWrt