odhcpd: Replace strerror(errno) with %m format
[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(struct netevent_handler_info *event_info)
133 {
134 struct odhcpd_ipaddr *addr = NULL;
135 struct interface *iface = event_info->iface;
136 ssize_t len = netlink_get_interface_addrs(iface->ifindex, false, &addr);
137
138 if (len < 0)
139 return;
140
141 bool change = len != (ssize_t)iface->addr4_len;
142 for (ssize_t i = 0; !change && i < len; ++i)
143 if (addr[i].addr.in.s_addr != iface->addr4[i].addr.in.s_addr)
144 change = true;
145
146 event_info->addrs_old.addrs = iface->addr4;
147 event_info->addrs_old.len = iface->addr4_len;
148
149 iface->addr4 = addr;
150 iface->addr4_len = len;
151
152 if (change)
153 call_netevent_handler_list(NETEV_ADDRLIST_CHANGE, event_info);
154
155 free(event_info->addrs_old.addrs);
156 }
157
158 static void refresh_iface_addr6(struct netevent_handler_info *event_info)
159 {
160 struct odhcpd_ipaddr *addr = NULL;
161 struct interface *iface = event_info->iface;
162 ssize_t len = netlink_get_interface_addrs(iface->ifindex, true, &addr);
163
164 if (len < 0)
165 return;
166
167 bool change = len != (ssize_t)iface->addr6_len;
168 for (ssize_t i = 0; !change && i < len; ++i)
169 if (!IN6_ARE_ADDR_EQUAL(&addr[i].addr.in6, &iface->addr6[i].addr.in6) ||
170 (addr[i].preferred > 0) != (iface->addr6[i].preferred > 0) ||
171 addr[i].valid < iface->addr6[i].valid ||
172 addr[i].preferred < iface->addr6[i].preferred)
173 change = true;
174
175 event_info->addrs_old.addrs = iface->addr6;
176 event_info->addrs_old.len = iface->addr6_len;
177
178 iface->addr6 = addr;
179 iface->addr6_len = len;
180
181 if (change)
182 call_netevent_handler_list(NETEV_ADDR6LIST_CHANGE, event_info);
183
184 free(event_info->addrs_old.addrs);
185 }
186
187 // Handler for neighbor cache entries from the kernel. This is our source
188 // to learn and unlearn hosts on interfaces.
189 static int cb_rtnl_valid(struct nl_msg *msg, _unused void *arg)
190 {
191 struct nlmsghdr *hdr = nlmsg_hdr(msg);
192 struct netevent_handler_info event_info;
193 bool add = false;
194 char ipbuf[INET6_ADDRSTRLEN];
195
196 memset(&event_info, 0, sizeof(event_info));
197 switch (hdr->nlmsg_type) {
198 case RTM_NEWLINK: {
199 struct ifinfomsg *ifi = nlmsg_data(hdr);
200 struct nlattr *nla[__IFLA_MAX];
201
202 if (!nlmsg_valid_hdr(hdr, sizeof(*ifi)) ||
203 ifi->ifi_family != AF_UNSPEC)
204 return NL_SKIP;
205
206 nlmsg_parse(hdr, sizeof(*ifi), nla, __IFLA_MAX - 1, NULL);
207 if (!nla[IFLA_IFNAME])
208 return NL_SKIP;
209
210 event_info.iface = odhcpd_get_interface_by_name(nla_get_string(nla[IFLA_IFNAME]));
211 if (!event_info.iface)
212 return NL_SKIP;
213
214 if (event_info.iface->ifindex != ifi->ifi_index) {
215 event_info.iface->ifindex = ifi->ifi_index;
216 call_netevent_handler_list(NETEV_IFINDEX_CHANGE, &event_info);
217 }
218 break;
219 }
220
221 case RTM_NEWROUTE:
222 add = true;
223 /* fall through */
224 case RTM_DELROUTE: {
225 struct rtmsg *rtm = nlmsg_data(hdr);
226 struct nlattr *nla[__RTA_MAX];
227
228 if (!nlmsg_valid_hdr(hdr, sizeof(*rtm)) ||
229 rtm->rtm_family != AF_INET6)
230 return NL_SKIP;
231
232 nlmsg_parse(hdr, sizeof(*rtm), nla, __RTA_MAX - 1, NULL);
233
234 event_info.rt.dst_len = rtm->rtm_dst_len;
235 if (nla[RTA_DST])
236 nla_memcpy(&event_info.rt.dst, nla[RTA_DST],
237 sizeof(&event_info.rt.dst));
238
239 if (nla[RTA_OIF])
240 event_info.iface = odhcpd_get_interface_by_index(nla_get_u32(nla[RTA_OIF]));
241
242 if (nla[RTA_GATEWAY])
243 nla_memcpy(&event_info.rt.gateway, nla[RTA_GATEWAY],
244 sizeof(&event_info.rt.gateway));
245
246 call_netevent_handler_list(add ? NETEV_ROUTE6_ADD : NETEV_ROUTE6_DEL,
247 &event_info);
248 break;
249 }
250
251 case RTM_NEWADDR:
252 add = true;
253 /* fall through */
254 case RTM_DELADDR: {
255 struct ifaddrmsg *ifa = nlmsg_data(hdr);
256 struct nlattr *nla[__IFA_MAX];
257
258 if (!nlmsg_valid_hdr(hdr, sizeof(*ifa)) ||
259 (ifa->ifa_family != AF_INET6 &&
260 ifa->ifa_family != AF_INET))
261 return NL_SKIP;
262
263 event_info.iface = odhcpd_get_interface_by_index(ifa->ifa_index);
264 if (!event_info.iface)
265 return NL_SKIP;
266
267 nlmsg_parse(hdr, sizeof(*ifa), nla, __IFA_MAX - 1, NULL);
268
269 if (ifa->ifa_family == AF_INET6) {
270 if (!nla[IFA_ADDRESS])
271 return NL_SKIP;
272
273 nla_memcpy(&event_info.addr, nla[IFA_ADDRESS], sizeof(event_info.addr));
274
275 if (IN6_IS_ADDR_LINKLOCAL(&event_info.addr) ||
276 IN6_IS_ADDR_MULTICAST(&event_info.addr))
277 return NL_SKIP;
278
279 inet_ntop(AF_INET6, &event_info.addr, ipbuf, sizeof(ipbuf));
280 syslog(LOG_DEBUG, "Netlink %s %s%%%s", add ? "newaddr" : "deladdr",
281 ipbuf, event_info.iface->ifname);
282
283 call_netevent_handler_list(add ? NETEV_ADDR6_ADD : NETEV_ADDR6_DEL,
284 &event_info);
285
286 refresh_iface_addr6(&event_info);
287 } else {
288 if (!nla[IFA_LOCAL])
289 return NL_SKIP;
290
291 nla_memcpy(&event_info.addr, nla[IFA_LOCAL], sizeof(event_info.addr));
292
293 inet_ntop(AF_INET, &event_info.addr, ipbuf, sizeof(ipbuf));
294 syslog(LOG_DEBUG, "Netlink %s %s%%%s", add ? "newaddr" : "deladdr",
295 ipbuf, event_info.iface->ifname);
296
297 call_netevent_handler_list(add ? NETEV_ADDR_ADD : NETEV_ADDR_DEL,
298 &event_info);
299
300 refresh_iface_addr4(&event_info);
301 }
302 break;
303 }
304
305 case RTM_NEWNEIGH:
306 add = true;
307 /* fall through */
308 case RTM_DELNEIGH: {
309 struct ndmsg *ndm = nlmsg_data(hdr);
310 struct nlattr *nla[__NDA_MAX];
311
312 if (!nlmsg_valid_hdr(hdr, sizeof(*ndm)) ||
313 ndm->ndm_family != AF_INET6)
314 return NL_SKIP;
315
316 event_info.iface = odhcpd_get_interface_by_index(ndm->ndm_ifindex);
317 if (!event_info.iface)
318 return NL_SKIP;
319
320 nlmsg_parse(hdr, sizeof(*ndm), nla, __NDA_MAX - 1, NULL);
321 if (!nla[NDA_DST])
322 return NL_SKIP;
323
324 nla_memcpy(&event_info.neigh.dst, nla[NDA_DST], sizeof(event_info.neigh.dst));
325
326 if (IN6_IS_ADDR_LINKLOCAL(&event_info.neigh.dst) ||
327 IN6_IS_ADDR_MULTICAST(&event_info.neigh.dst))
328 return NL_SKIP;
329
330 inet_ntop(AF_INET6, &event_info.neigh.dst, ipbuf, sizeof(ipbuf));
331 syslog(LOG_DEBUG, "Netlink %s %s%%%s", true ? "newneigh" : "delneigh",
332 ipbuf, event_info.iface->ifname);
333
334 event_info.neigh.state = ndm->ndm_state;
335 event_info.neigh.flags = ndm->ndm_flags;
336
337 call_netevent_handler_list(add ? NETEV_NEIGH6_ADD : NETEV_NEIGH6_DEL,
338 &event_info);
339 break;
340 }
341
342 default:
343 return NL_SKIP;
344 }
345
346 return NL_OK;
347 }
348
349 static void catch_rtnl_err(struct odhcpd_event *e, int error)
350 {
351 struct event_socket *ev_sock = container_of(e, struct event_socket, ev);
352
353 if (error != ENOBUFS)
354 goto err;
355
356 /* Double netlink event buffer size */
357 ev_sock->sock_bufsize *= 2;
358
359 if (nl_socket_set_buffer_size(ev_sock->sock, ev_sock->sock_bufsize, 0))
360 goto err;
361
362 netlink_dump_addr_table(true);
363 return;
364
365 err:
366 odhcpd_deregister(e);
367 }
368
369 static struct nl_sock *create_socket(int protocol)
370 {
371 struct nl_sock *nl_sock;
372
373 nl_sock = nl_socket_alloc();
374 if (!nl_sock)
375 goto err;
376
377 if (nl_connect(nl_sock, protocol) < 0)
378 goto err;
379
380 return nl_sock;
381
382 err:
383 if (nl_sock)
384 nl_socket_free(nl_sock);
385
386 return NULL;
387 }
388
389
390 struct addr_info {
391 int ifindex;
392 int af;
393 struct odhcpd_ipaddr **addrs;
394 int pending;
395 ssize_t ret;
396 };
397
398
399 static int cb_valid_handler(struct nl_msg *msg, void *arg)
400 {
401 struct addr_info *ctxt = (struct addr_info *)arg;
402 struct odhcpd_ipaddr *addrs = *(ctxt->addrs);
403 struct nlmsghdr *hdr = nlmsg_hdr(msg);
404 struct ifaddrmsg *ifa;
405 struct nlattr *nla[__IFA_MAX], *nla_addr = NULL;
406
407 if (hdr->nlmsg_type != RTM_NEWADDR)
408 return NL_SKIP;
409
410 ifa = NLMSG_DATA(hdr);
411 if (ifa->ifa_scope != RT_SCOPE_UNIVERSE ||
412 (ctxt->af != ifa->ifa_family) ||
413 (ctxt->ifindex && ifa->ifa_index != (unsigned)ctxt->ifindex))
414 return NL_SKIP;
415
416 nlmsg_parse(hdr, sizeof(*ifa), nla, __IFA_MAX - 1, NULL);
417
418 switch (ifa->ifa_family) {
419 case AF_INET6:
420 if (nla[IFA_ADDRESS])
421 nla_addr = nla[IFA_ADDRESS];
422 break;
423
424 case AF_INET:
425 if (nla[IFA_LOCAL])
426 nla_addr = nla[IFA_LOCAL];
427 break;
428
429 default:
430 break;
431 }
432 if (!nla_addr)
433 return NL_SKIP;
434
435 addrs = realloc(addrs, sizeof(*addrs)*(ctxt->ret + 1));
436 if (!addrs)
437 return NL_SKIP;
438
439 memset(&addrs[ctxt->ret], 0, sizeof(addrs[ctxt->ret]));
440 addrs[ctxt->ret].prefix = ifa->ifa_prefixlen;
441
442 nla_memcpy(&addrs[ctxt->ret].addr, nla_addr,
443 sizeof(addrs[ctxt->ret].addr));
444
445 if (nla[IFA_BROADCAST])
446 nla_memcpy(&addrs[ctxt->ret].broadcast, nla[IFA_BROADCAST],
447 sizeof(addrs[ctxt->ret].broadcast));
448
449 if (nla[IFA_CACHEINFO]) {
450 struct ifa_cacheinfo *ifc = nla_data(nla[IFA_CACHEINFO]);
451
452 addrs[ctxt->ret].preferred = ifc->ifa_prefered;
453 addrs[ctxt->ret].valid = ifc->ifa_valid;
454 }
455
456 if (ifa->ifa_flags & IFA_F_DEPRECATED)
457 addrs[ctxt->ret].preferred = 0;
458
459 ctxt->ret++;
460 *(ctxt->addrs) = addrs;
461
462 return NL_OK;
463 }
464
465
466 static int cb_finish_handler(_unused struct nl_msg *msg, void *arg)
467 {
468 struct addr_info *ctxt = (struct addr_info *)arg;
469
470 ctxt->pending = 0;
471
472 return NL_STOP;
473 }
474
475
476 static int cb_error_handler(_unused struct sockaddr_nl *nla, struct nlmsgerr *err,
477 void *arg)
478 {
479 struct addr_info *ctxt = (struct addr_info *)arg;
480
481 ctxt->pending = 0;
482 ctxt->ret = err->error;
483
484 return NL_STOP;
485 }
486
487
488 static int prefix_cmp(const void *va, const void *vb)
489 {
490 const struct odhcpd_ipaddr *a = va, *b = vb;
491 int ret = 0;
492
493 if (a->prefix == b->prefix) {
494 ret = (ntohl(a->addr.in.s_addr) < ntohl(b->addr.in.s_addr)) ? 1 :
495 (ntohl(a->addr.in.s_addr) > ntohl(b->addr.in.s_addr)) ? -1 : 0;
496 } else
497 ret = a->prefix < b->prefix ? 1 : -1;
498
499 return ret;
500 }
501
502
503 // compare IPv6 prefixes
504 static int prefix6_cmp(const void *va, const void *vb)
505 {
506 const struct odhcpd_ipaddr *a = va, *b = vb;
507 uint32_t a_pref = IN6_IS_ADDR_ULA(&a->addr.in6) ? 1 : a->preferred;
508 uint32_t b_pref = IN6_IS_ADDR_ULA(&b->addr.in6) ? 1 : b->preferred;
509 return (a_pref < b_pref) ? 1 : (a_pref > b_pref) ? -1 : 0;
510 }
511
512
513 // Detect an IPV6-address currently assigned to the given interface
514 ssize_t netlink_get_interface_addrs(int ifindex, bool v6, struct odhcpd_ipaddr **addrs)
515 {
516 struct nl_msg *msg;
517 struct ifaddrmsg ifa = {
518 .ifa_family = v6? AF_INET6: AF_INET,
519 .ifa_prefixlen = 0,
520 .ifa_flags = 0,
521 .ifa_scope = 0,
522 .ifa_index = ifindex, };
523 struct nl_cb *cb = nl_cb_alloc(NL_CB_DEFAULT);
524 struct addr_info ctxt = {
525 .ifindex = ifindex,
526 .af = v6? AF_INET6: AF_INET,
527 .addrs = addrs,
528 .ret = 0,
529 .pending = 1,
530 };
531
532 if (!cb) {
533 ctxt.ret = -1;
534 goto out;
535 }
536
537 msg = nlmsg_alloc_simple(RTM_GETADDR, NLM_F_REQUEST | NLM_F_DUMP);
538
539 if (!msg) {
540 ctxt.ret = - 1;
541 goto out;
542 }
543
544 nlmsg_append(msg, &ifa, sizeof(ifa), 0);
545
546 nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, cb_valid_handler, &ctxt);
547 nl_cb_set(cb, NL_CB_FINISH, NL_CB_CUSTOM, cb_finish_handler, &ctxt);
548 nl_cb_err(cb, NL_CB_CUSTOM, cb_error_handler, &ctxt);
549
550 nl_send_auto_complete(rtnl_socket, msg);
551 while (ctxt.pending > 0)
552 nl_recvmsgs(rtnl_socket, cb);
553
554 nlmsg_free(msg);
555
556 if (ctxt.ret <= 0)
557 goto out;
558
559 time_t now = odhcpd_time();
560 struct odhcpd_ipaddr *addr = *addrs;
561
562 qsort(addr, ctxt.ret, sizeof(*addr), v6 ? prefix6_cmp : prefix_cmp);
563
564 for (ssize_t i = 0; i < ctxt.ret; ++i) {
565 if (addr[i].preferred < UINT32_MAX - now)
566 addr[i].preferred += now;
567
568 if (addr[i].valid < UINT32_MAX - now)
569 addr[i].valid += now;
570 }
571
572 out:
573 nl_cb_put(cb);
574
575 return ctxt.ret;
576 }
577
578
579 int netlink_setup_route(const struct in6_addr *addr, const int prefixlen,
580 const int ifindex, const struct in6_addr *gw,
581 const uint32_t metric, const bool add)
582 {
583 struct nl_msg *msg;
584 struct rtmsg rtm = {
585 .rtm_family = AF_INET6,
586 .rtm_dst_len = prefixlen,
587 .rtm_src_len = 0,
588 .rtm_table = RT_TABLE_MAIN,
589 .rtm_protocol = (add ? RTPROT_STATIC : RTPROT_UNSPEC),
590 .rtm_scope = (add ? (gw ? RT_SCOPE_UNIVERSE : RT_SCOPE_LINK) : RT_SCOPE_NOWHERE),
591 .rtm_type = (add ? RTN_UNICAST : RTN_UNSPEC),
592 };
593 int ret = 0;
594
595 msg = nlmsg_alloc_simple(add ? RTM_NEWROUTE : RTM_DELROUTE,
596 add ? NLM_F_CREATE | NLM_F_REPLACE : 0);
597 if (!msg)
598 return -1;
599
600 nlmsg_append(msg, &rtm, sizeof(rtm), 0);
601
602 nla_put(msg, RTA_DST, sizeof(*addr), addr);
603 nla_put_u32(msg, RTA_OIF, ifindex);
604 nla_put_u32(msg, RTA_PRIORITY, metric);
605
606 if (gw)
607 nla_put(msg, RTA_GATEWAY, sizeof(*gw), gw);
608
609 ret = nl_send_auto_complete(rtnl_socket, msg);
610 nlmsg_free(msg);
611
612 if (ret < 0)
613 return ret;
614
615 return nl_wait_for_ack(rtnl_socket);
616 }
617
618
619 int netlink_setup_proxy_neigh(const struct in6_addr *addr,
620 const int ifindex, const bool add)
621 {
622 struct nl_msg *msg;
623 struct ndmsg ndm = {
624 .ndm_family = AF_INET6,
625 .ndm_flags = NTF_PROXY,
626 .ndm_ifindex = ifindex,
627 };
628 int ret = 0, flags = NLM_F_REQUEST;
629
630 if (add)
631 flags |= NLM_F_REPLACE | NLM_F_CREATE;
632
633 msg = nlmsg_alloc_simple(add ? RTM_NEWNEIGH : RTM_DELNEIGH, flags);
634 if (!msg)
635 return -1;
636
637 nlmsg_append(msg, &ndm, sizeof(ndm), 0);
638
639 nla_put(msg, NDA_DST, sizeof(*addr), addr);
640
641 ret = nl_send_auto_complete(rtnl_socket, msg);
642 nlmsg_free(msg);
643
644 if (ret < 0)
645 return ret;
646
647 return nl_wait_for_ack(rtnl_socket);
648 }
649
650
651 int netlink_setup_addr(struct odhcpd_ipaddr *addr,
652 const int ifindex, const bool v6, const bool add)
653 {
654 struct nl_msg *msg;
655 struct ifaddrmsg ifa = {
656 .ifa_family = v6 ? AF_INET6 : AF_INET,
657 .ifa_prefixlen = addr->prefix,
658 .ifa_flags = 0,
659 .ifa_scope = 0,
660 .ifa_index = ifindex, };
661 int ret = 0, flags = NLM_F_REQUEST;
662
663 if (add)
664 flags |= NLM_F_REPLACE | NLM_F_CREATE;
665
666 msg = nlmsg_alloc_simple(add ? RTM_NEWADDR : RTM_DELADDR, 0);
667 if (!msg)
668 return -1;
669
670 nlmsg_append(msg, &ifa, sizeof(ifa), flags);
671 nla_put(msg, IFA_LOCAL, v6 ? 16 : 4, &addr->addr);
672 if (v6) {
673 struct ifa_cacheinfo cinfo = { .ifa_prefered = 0xffffffffU,
674 .ifa_valid = 0xffffffffU,
675 .cstamp = 0,
676 .tstamp = 0 };
677 time_t now = odhcpd_time();
678
679 if (addr->preferred) {
680 int64_t preferred = addr->preferred - now;
681 if (preferred < 0)
682 preferred = 0;
683 else if (preferred > UINT32_MAX)
684 preferred = UINT32_MAX;
685
686 cinfo.ifa_prefered = preferred;
687 }
688
689 if (addr->valid) {
690 int64_t valid = addr->valid - now;
691 if (valid <= 0) {
692 nlmsg_free(msg);
693 return -1;
694 }
695 else if (valid > UINT32_MAX)
696 valid = UINT32_MAX;
697
698 cinfo.ifa_valid = valid;
699 }
700
701 nla_put(msg, IFA_CACHEINFO, sizeof(cinfo), &cinfo);
702
703 nla_put_u32(msg, IFA_FLAGS, IFA_F_NOPREFIXROUTE);
704 } else {
705 if (addr->broadcast.s_addr)
706 nla_put_u32(msg, IFA_BROADCAST, addr->broadcast.s_addr);
707 }
708
709 ret = nl_send_auto_complete(rtnl_socket, msg);
710 nlmsg_free(msg);
711
712 if (ret < 0)
713 return ret;
714
715 return nl_wait_for_ack(rtnl_socket);
716 }
717
718 void netlink_dump_neigh_table(const bool proxy)
719 {
720 struct nl_msg *msg;
721 struct ndmsg ndm = {
722 .ndm_family = AF_INET6,
723 .ndm_flags = proxy ? NTF_PROXY : 0,
724 };
725
726 msg = nlmsg_alloc_simple(RTM_GETNEIGH, NLM_F_REQUEST | NLM_F_DUMP);
727 if (!msg)
728 return;
729
730 nlmsg_append(msg, &ndm, sizeof(ndm), 0);
731
732 nl_send_auto_complete(rtnl_event.sock, msg);
733
734 nlmsg_free(msg);
735 }
736
737 void netlink_dump_addr_table(const bool v6)
738 {
739 struct nl_msg *msg;
740 struct ifaddrmsg ifa = {
741 .ifa_family = v6 ? AF_INET6 : AF_INET,
742 };
743
744 msg = nlmsg_alloc_simple(RTM_GETADDR, NLM_F_REQUEST | NLM_F_DUMP);
745 if (!msg)
746 return;
747
748 nlmsg_append(msg, &ifa, sizeof(ifa), 0);
749
750 nl_send_auto_complete(rtnl_event.sock, msg);
751
752 nlmsg_free(msg);
753 }