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