ubus: fix invalid ipv6-prefix json
[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 }