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