e3b2c3f0931c9c82a44cc32234024f492f2e6239
[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].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_valid_handler(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_finish_handler(_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_error_handler(_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_valid_handler, &ctxt);
655 nl_cb_set(cb, NL_CB_FINISH, NL_CB_CUSTOM, cb_finish_handler, &ctxt);
656 nl_cb_err(cb, NL_CB_CUSTOM, cb_error_handler, &ctxt);
657
658 nl_send_auto_complete(rtnl_socket, msg);
659 while (ctxt.pending > 0)
660 nl_recvmsgs(rtnl_socket, cb);
661
662 nlmsg_free(msg);
663
664 if (ctxt.ret <= 0)
665 goto out;
666
667 time_t now = odhcpd_time();
668 struct odhcpd_ipaddr *addr = *addrs;
669
670 qsort(addr, ctxt.ret, sizeof(*addr), v6 ? prefix6_cmp : prefix_cmp);
671
672 for (ssize_t i = 0; i < ctxt.ret; ++i) {
673 if (addr[i].preferred < UINT32_MAX - now)
674 addr[i].preferred += now;
675
676 if (addr[i].valid < UINT32_MAX - now)
677 addr[i].valid += now;
678 }
679
680 out:
681 nl_cb_put(cb);
682
683 return ctxt.ret;
684 }
685
686
687 struct neigh_info {
688 int ifindex;
689 int pending;
690 const struct in6_addr *addr;
691 int ret;
692 };
693
694
695 static int cb_valid_handler2(struct nl_msg *msg, void *arg)
696 {
697 struct neigh_info *ctxt = (struct neigh_info *)arg;
698 struct nlmsghdr *hdr = nlmsg_hdr(msg);
699 struct ndmsg *ndm;
700 struct nlattr *nla_dst;
701
702 if (hdr->nlmsg_type != RTM_NEWNEIGH)
703 return NL_SKIP;
704
705 ndm = NLMSG_DATA(hdr);
706 if (ndm->ndm_family != AF_INET6 ||
707 (ctxt->ifindex && ndm->ndm_ifindex != ctxt->ifindex))
708 return NL_SKIP;
709
710 if (!(ndm->ndm_flags & NTF_PROXY))
711 return NL_SKIP;
712
713 nla_dst = nlmsg_find_attr(hdr, sizeof(*ndm), NDA_DST);
714 if (!nla_dst)
715 return NL_SKIP;
716
717 if (nla_memcmp(nla_dst,ctxt->addr, 16) == 0)
718 ctxt->ret = 1;
719
720 return NL_OK;
721 }
722
723
724 static int cb_finish_handler2(_unused struct nl_msg *msg, void *arg)
725 {
726 struct neigh_info *ctxt = (struct neigh_info *)arg;
727
728 ctxt->pending = 0;
729
730 return NL_STOP;
731 }
732
733
734 static int cb_error_handler2(_unused struct sockaddr_nl *nla, struct nlmsgerr *err,
735 void *arg)
736 {
737 struct neigh_info *ctxt = (struct neigh_info *)arg;
738
739 ctxt->pending = 0;
740 ctxt->ret = err->error;
741
742 return NL_STOP;
743 }
744
745 /* Detect an IPV6-address proxy neighbor for the given interface */
746 int netlink_get_interface_proxy_neigh(int ifindex, const struct in6_addr *addr)
747 {
748 struct nl_msg *msg;
749 struct ndmsg ndm = {
750 .ndm_family = AF_INET6,
751 .ndm_flags = NTF_PROXY,
752 .ndm_ifindex = ifindex,
753 };
754 struct nl_cb *cb = nl_cb_alloc(NL_CB_DEFAULT);
755 struct neigh_info ctxt = {
756 .ifindex = ifindex,
757 .addr = addr,
758 .ret = 0,
759 .pending = 1,
760 };
761
762 if (!cb) {
763 ctxt.ret = -1;
764 goto out;
765 }
766
767 msg = nlmsg_alloc_simple(RTM_GETNEIGH, NLM_F_REQUEST | NLM_F_MATCH);
768
769 if (!msg) {
770 ctxt.ret = -1;
771 goto out;
772 }
773
774 nlmsg_append(msg, &ndm, sizeof(ndm), 0);
775 nla_put(msg, NDA_DST, sizeof(*addr), addr);
776
777 nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, cb_valid_handler2, &ctxt);
778 nl_cb_set(cb, NL_CB_FINISH, NL_CB_CUSTOM, cb_finish_handler2, &ctxt);
779 nl_cb_err(cb, NL_CB_CUSTOM, cb_error_handler2, &ctxt);
780
781 nl_send_auto_complete(rtnl_socket, msg);
782 while (ctxt.pending > 0)
783 nl_recvmsgs(rtnl_socket, cb);
784
785 nlmsg_free(msg);
786
787 out:
788 nl_cb_put(cb);
789
790 return ctxt.ret;
791 }
792
793
794 int netlink_setup_route(const struct in6_addr *addr, const int prefixlen,
795 const int ifindex, const struct in6_addr *gw,
796 const uint32_t metric, const bool add)
797 {
798 struct nl_msg *msg;
799 struct rtmsg rtm = {
800 .rtm_family = AF_INET6,
801 .rtm_dst_len = prefixlen,
802 .rtm_src_len = 0,
803 .rtm_table = RT_TABLE_MAIN,
804 .rtm_protocol = (add ? RTPROT_STATIC : RTPROT_UNSPEC),
805 .rtm_scope = (add ? (gw ? RT_SCOPE_UNIVERSE : RT_SCOPE_LINK) : RT_SCOPE_NOWHERE),
806 .rtm_type = (add ? RTN_UNICAST : RTN_UNSPEC),
807 };
808 int ret = 0;
809
810 msg = nlmsg_alloc_simple(add ? RTM_NEWROUTE : RTM_DELROUTE,
811 add ? NLM_F_CREATE | NLM_F_REPLACE : 0);
812 if (!msg)
813 return -1;
814
815 nlmsg_append(msg, &rtm, sizeof(rtm), 0);
816
817 nla_put(msg, RTA_DST, sizeof(*addr), addr);
818 nla_put_u32(msg, RTA_OIF, ifindex);
819 nla_put_u32(msg, RTA_PRIORITY, metric);
820
821 if (gw)
822 nla_put(msg, RTA_GATEWAY, sizeof(*gw), gw);
823
824 ret = nl_send_auto_complete(rtnl_socket, msg);
825 nlmsg_free(msg);
826
827 if (ret < 0)
828 return ret;
829
830 return nl_wait_for_ack(rtnl_socket);
831 }
832
833
834 int netlink_setup_proxy_neigh(const struct in6_addr *addr,
835 const int ifindex, const bool add)
836 {
837 struct nl_msg *msg;
838 struct ndmsg ndm = {
839 .ndm_family = AF_INET6,
840 .ndm_flags = NTF_PROXY,
841 .ndm_ifindex = ifindex,
842 };
843 int ret = 0, flags = NLM_F_REQUEST;
844
845 if (add)
846 flags |= NLM_F_REPLACE | NLM_F_CREATE;
847
848 msg = nlmsg_alloc_simple(add ? RTM_NEWNEIGH : RTM_DELNEIGH, flags);
849 if (!msg)
850 return -1;
851
852 nlmsg_append(msg, &ndm, sizeof(ndm), 0);
853
854 nla_put(msg, NDA_DST, sizeof(*addr), addr);
855
856 ret = nl_send_auto_complete(rtnl_socket, msg);
857 nlmsg_free(msg);
858
859 if (ret < 0)
860 return ret;
861
862 return nl_wait_for_ack(rtnl_socket);
863 }
864
865
866 int netlink_setup_addr(struct odhcpd_ipaddr *addr,
867 const int ifindex, const bool v6, const bool add)
868 {
869 struct nl_msg *msg;
870 struct ifaddrmsg ifa = {
871 .ifa_family = v6 ? AF_INET6 : AF_INET,
872 .ifa_prefixlen = addr->prefix,
873 .ifa_flags = 0,
874 .ifa_scope = 0,
875 .ifa_index = ifindex, };
876 int ret = 0, flags = NLM_F_REQUEST;
877
878 if (add)
879 flags |= NLM_F_REPLACE | NLM_F_CREATE;
880
881 msg = nlmsg_alloc_simple(add ? RTM_NEWADDR : RTM_DELADDR, 0);
882 if (!msg)
883 return -1;
884
885 nlmsg_append(msg, &ifa, sizeof(ifa), flags);
886 nla_put(msg, IFA_LOCAL, v6 ? 16 : 4, &addr->addr);
887 if (v6) {
888 struct ifa_cacheinfo cinfo = { .ifa_prefered = 0xffffffffU,
889 .ifa_valid = 0xffffffffU,
890 .cstamp = 0,
891 .tstamp = 0 };
892 time_t now = odhcpd_time();
893
894 if (addr->preferred) {
895 int64_t preferred = addr->preferred - now;
896 if (preferred < 0)
897 preferred = 0;
898 else if (preferred > UINT32_MAX)
899 preferred = UINT32_MAX;
900
901 cinfo.ifa_prefered = preferred;
902 }
903
904 if (addr->valid) {
905 int64_t valid = addr->valid - now;
906 if (valid <= 0) {
907 nlmsg_free(msg);
908 return -1;
909 }
910 else if (valid > UINT32_MAX)
911 valid = UINT32_MAX;
912
913 cinfo.ifa_valid = valid;
914 }
915
916 nla_put(msg, IFA_CACHEINFO, sizeof(cinfo), &cinfo);
917
918 nla_put_u32(msg, IFA_FLAGS, IFA_F_NOPREFIXROUTE);
919 } else {
920 if (addr->broadcast.s_addr)
921 nla_put_u32(msg, IFA_BROADCAST, addr->broadcast.s_addr);
922 }
923
924 ret = nl_send_auto_complete(rtnl_socket, msg);
925 nlmsg_free(msg);
926
927 if (ret < 0)
928 return ret;
929
930 return nl_wait_for_ack(rtnl_socket);
931 }
932
933 void netlink_dump_neigh_table(const bool proxy)
934 {
935 struct nl_msg *msg;
936 struct ndmsg ndm = {
937 .ndm_family = AF_INET6,
938 .ndm_flags = proxy ? NTF_PROXY : 0,
939 };
940
941 msg = nlmsg_alloc_simple(RTM_GETNEIGH, NLM_F_REQUEST | NLM_F_DUMP);
942 if (!msg)
943 return;
944
945 nlmsg_append(msg, &ndm, sizeof(ndm), 0);
946
947 nl_send_auto_complete(rtnl_event.sock, msg);
948
949 nlmsg_free(msg);
950 }
951
952 void netlink_dump_addr_table(const bool v6)
953 {
954 struct nl_msg *msg;
955 struct ifaddrmsg ifa = {
956 .ifa_family = v6 ? AF_INET6 : AF_INET,
957 };
958
959 msg = nlmsg_alloc_simple(RTM_GETADDR, NLM_F_REQUEST | NLM_F_DUMP);
960 if (!msg)
961 return;
962
963 nlmsg_append(msg, &ifa, sizeof(ifa), 0);
964
965 nl_send_auto_complete(rtnl_event.sock, msg);
966
967 nlmsg_free(msg);
968 }