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