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