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