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