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

This page was automatically generated by LXR 0.3.1.  •  OpenWrt