c6727482980225197179622a2970c75d0109c1ba
[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(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.iface = iface;
420 event_info.neigh.state = ndm->ndm_state;
421 event_info.neigh.flags = ndm->ndm_flags;
422
423 call_netevent_handler_list(add ? NETEV_NEIGH6_ADD : NETEV_NEIGH6_DEL,
424 &event_info);
425 }
426
427 return NL_OK;
428 }
429
430 /* Handler for neighbor cache entries from the kernel. This is our source
431 * to learn and unlearn hosts on interfaces. */
432 static int cb_rtnl_valid(struct nl_msg *msg, _unused void *arg)
433 {
434 struct nlmsghdr *hdr = nlmsg_hdr(msg);
435 int ret = NL_SKIP;
436 bool add = false;
437
438 switch (hdr->nlmsg_type) {
439 case RTM_NEWLINK:
440 ret = handle_rtm_link(hdr);
441 break;
442
443 case RTM_NEWROUTE:
444 add = true;
445 /* fall through */
446 case RTM_DELROUTE:
447 ret = handle_rtm_route(hdr, add);
448 break;
449
450 case RTM_NEWADDR:
451 add = true;
452 /* fall through */
453 case RTM_DELADDR:
454 ret = handle_rtm_addr(hdr, add);
455 break;
456
457 case RTM_NEWNEIGH:
458 add = true;
459 /* fall through */
460 case RTM_DELNEIGH:
461 ret = handle_rtm_neigh(hdr, add);
462 break;
463
464 default:
465 break;
466 }
467
468 return ret;
469 }
470
471 static void catch_rtnl_err(struct odhcpd_event *e, int error)
472 {
473 struct event_socket *ev_sock = container_of(e, struct event_socket, ev);
474
475 if (error != ENOBUFS)
476 goto err;
477
478 /* Double netlink event buffer size */
479 ev_sock->sock_bufsize *= 2;
480
481 if (nl_socket_set_buffer_size(ev_sock->sock, ev_sock->sock_bufsize, 0))
482 goto err;
483
484 netlink_dump_addr_table(true);
485 return;
486
487 err:
488 odhcpd_deregister(e);
489 }
490
491 static struct nl_sock *create_socket(int protocol)
492 {
493 struct nl_sock *nl_sock;
494
495 nl_sock = nl_socket_alloc();
496 if (!nl_sock)
497 goto err;
498
499 if (nl_connect(nl_sock, protocol) < 0)
500 goto err;
501
502 return nl_sock;
503
504 err:
505 if (nl_sock)
506 nl_socket_free(nl_sock);
507
508 return NULL;
509 }
510
511
512 struct addr_info {
513 int ifindex;
514 int af;
515 struct odhcpd_ipaddr **addrs;
516 int pending;
517 ssize_t ret;
518 };
519
520
521 static int cb_valid_handler(struct nl_msg *msg, void *arg)
522 {
523 struct addr_info *ctxt = (struct addr_info *)arg;
524 struct odhcpd_ipaddr *addrs = *(ctxt->addrs);
525 struct nlmsghdr *hdr = nlmsg_hdr(msg);
526 struct ifaddrmsg *ifa;
527 struct nlattr *nla[__IFA_MAX], *nla_addr = NULL;
528
529 if (hdr->nlmsg_type != RTM_NEWADDR)
530 return NL_SKIP;
531
532 ifa = NLMSG_DATA(hdr);
533 if (ifa->ifa_scope != RT_SCOPE_UNIVERSE ||
534 (ctxt->af != ifa->ifa_family) ||
535 (ctxt->ifindex && ifa->ifa_index != (unsigned)ctxt->ifindex))
536 return NL_SKIP;
537
538 nlmsg_parse(hdr, sizeof(*ifa), nla, __IFA_MAX - 1, NULL);
539
540 switch (ifa->ifa_family) {
541 case AF_INET6:
542 if (nla[IFA_ADDRESS])
543 nla_addr = nla[IFA_ADDRESS];
544 break;
545
546 case AF_INET:
547 if (nla[IFA_LOCAL])
548 nla_addr = nla[IFA_LOCAL];
549 break;
550
551 default:
552 break;
553 }
554 if (!nla_addr)
555 return NL_SKIP;
556
557 addrs = realloc(addrs, sizeof(*addrs)*(ctxt->ret + 1));
558 if (!addrs)
559 return NL_SKIP;
560
561 memset(&addrs[ctxt->ret], 0, sizeof(addrs[ctxt->ret]));
562 addrs[ctxt->ret].prefix = ifa->ifa_prefixlen;
563
564 nla_memcpy(&addrs[ctxt->ret].addr, nla_addr,
565 sizeof(addrs[ctxt->ret].addr));
566
567 if (nla[IFA_BROADCAST])
568 nla_memcpy(&addrs[ctxt->ret].broadcast, nla[IFA_BROADCAST],
569 sizeof(addrs[ctxt->ret].broadcast));
570
571 if (nla[IFA_CACHEINFO]) {
572 struct ifa_cacheinfo *ifc = nla_data(nla[IFA_CACHEINFO]);
573
574 addrs[ctxt->ret].preferred = ifc->ifa_prefered;
575 addrs[ctxt->ret].valid = ifc->ifa_valid;
576 }
577
578 if (ifa->ifa_flags & IFA_F_DEPRECATED)
579 addrs[ctxt->ret].preferred = 0;
580
581 ctxt->ret++;
582 *(ctxt->addrs) = addrs;
583
584 return NL_OK;
585 }
586
587
588 static int cb_finish_handler(_unused struct nl_msg *msg, void *arg)
589 {
590 struct addr_info *ctxt = (struct addr_info *)arg;
591
592 ctxt->pending = 0;
593
594 return NL_STOP;
595 }
596
597
598 static int cb_error_handler(_unused struct sockaddr_nl *nla, struct nlmsgerr *err,
599 void *arg)
600 {
601 struct addr_info *ctxt = (struct addr_info *)arg;
602
603 ctxt->pending = 0;
604 ctxt->ret = err->error;
605
606 return NL_STOP;
607 }
608
609
610 static int prefix_cmp(const void *va, const void *vb)
611 {
612 const struct odhcpd_ipaddr *a = va, *b = vb;
613 int ret = 0;
614
615 if (a->prefix == b->prefix) {
616 ret = (ntohl(a->addr.in.s_addr) < ntohl(b->addr.in.s_addr)) ? 1 :
617 (ntohl(a->addr.in.s_addr) > ntohl(b->addr.in.s_addr)) ? -1 : 0;
618 } else
619 ret = a->prefix < b->prefix ? 1 : -1;
620
621 return ret;
622 }
623
624
625 /* compare IPv6 prefixes */
626 static int prefix6_cmp(const void *va, const void *vb)
627 {
628 const struct odhcpd_ipaddr *a = va, *b = vb;
629 uint32_t a_pref = IN6_IS_ADDR_ULA(&a->addr.in6) ? 1 : a->preferred;
630 uint32_t b_pref = IN6_IS_ADDR_ULA(&b->addr.in6) ? 1 : b->preferred;
631 return (a_pref < b_pref) ? 1 : (a_pref > b_pref) ? -1 : 0;
632 }
633
634
635 /* Detect an IPV6-address currently assigned to the given interface */
636 ssize_t netlink_get_interface_addrs(int ifindex, bool v6, struct odhcpd_ipaddr **addrs)
637 {
638 struct nl_msg *msg;
639 struct ifaddrmsg ifa = {
640 .ifa_family = v6? AF_INET6: AF_INET,
641 .ifa_prefixlen = 0,
642 .ifa_flags = 0,
643 .ifa_scope = 0,
644 .ifa_index = ifindex, };
645 struct nl_cb *cb = nl_cb_alloc(NL_CB_DEFAULT);
646 struct addr_info ctxt = {
647 .ifindex = ifindex,
648 .af = v6? AF_INET6: AF_INET,
649 .addrs = addrs,
650 .ret = 0,
651 .pending = 1,
652 };
653
654 if (!cb) {
655 ctxt.ret = -1;
656 goto out;
657 }
658
659 msg = nlmsg_alloc_simple(RTM_GETADDR, NLM_F_REQUEST | NLM_F_DUMP);
660
661 if (!msg) {
662 ctxt.ret = - 1;
663 goto out;
664 }
665
666 nlmsg_append(msg, &ifa, sizeof(ifa), 0);
667
668 nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, cb_valid_handler, &ctxt);
669 nl_cb_set(cb, NL_CB_FINISH, NL_CB_CUSTOM, cb_finish_handler, &ctxt);
670 nl_cb_err(cb, NL_CB_CUSTOM, cb_error_handler, &ctxt);
671
672 nl_send_auto_complete(rtnl_socket, msg);
673 while (ctxt.pending > 0)
674 nl_recvmsgs(rtnl_socket, cb);
675
676 nlmsg_free(msg);
677
678 if (ctxt.ret <= 0)
679 goto out;
680
681 time_t now = odhcpd_time();
682 struct odhcpd_ipaddr *addr = *addrs;
683
684 qsort(addr, ctxt.ret, sizeof(*addr), v6 ? prefix6_cmp : prefix_cmp);
685
686 for (ssize_t i = 0; i < ctxt.ret; ++i) {
687 if (addr[i].preferred < UINT32_MAX - now)
688 addr[i].preferred += now;
689
690 if (addr[i].valid < UINT32_MAX - now)
691 addr[i].valid += now;
692 }
693
694 out:
695 nl_cb_put(cb);
696
697 return ctxt.ret;
698 }
699
700
701 int netlink_setup_route(const struct in6_addr *addr, const int prefixlen,
702 const int ifindex, const struct in6_addr *gw,
703 const uint32_t metric, const bool add)
704 {
705 struct nl_msg *msg;
706 struct rtmsg rtm = {
707 .rtm_family = AF_INET6,
708 .rtm_dst_len = prefixlen,
709 .rtm_src_len = 0,
710 .rtm_table = RT_TABLE_MAIN,
711 .rtm_protocol = (add ? RTPROT_STATIC : RTPROT_UNSPEC),
712 .rtm_scope = (add ? (gw ? RT_SCOPE_UNIVERSE : RT_SCOPE_LINK) : RT_SCOPE_NOWHERE),
713 .rtm_type = (add ? RTN_UNICAST : RTN_UNSPEC),
714 };
715 int ret = 0;
716
717 msg = nlmsg_alloc_simple(add ? RTM_NEWROUTE : RTM_DELROUTE,
718 add ? NLM_F_CREATE | NLM_F_REPLACE : 0);
719 if (!msg)
720 return -1;
721
722 nlmsg_append(msg, &rtm, sizeof(rtm), 0);
723
724 nla_put(msg, RTA_DST, sizeof(*addr), addr);
725 nla_put_u32(msg, RTA_OIF, ifindex);
726 nla_put_u32(msg, RTA_PRIORITY, metric);
727
728 if (gw)
729 nla_put(msg, RTA_GATEWAY, sizeof(*gw), gw);
730
731 ret = nl_send_auto_complete(rtnl_socket, msg);
732 nlmsg_free(msg);
733
734 if (ret < 0)
735 return ret;
736
737 return nl_wait_for_ack(rtnl_socket);
738 }
739
740
741 int netlink_setup_proxy_neigh(const struct in6_addr *addr,
742 const int ifindex, const bool add)
743 {
744 struct nl_msg *msg;
745 struct ndmsg ndm = {
746 .ndm_family = AF_INET6,
747 .ndm_flags = NTF_PROXY,
748 .ndm_ifindex = ifindex,
749 };
750 int ret = 0, flags = NLM_F_REQUEST;
751
752 if (add)
753 flags |= NLM_F_REPLACE | NLM_F_CREATE;
754
755 msg = nlmsg_alloc_simple(add ? RTM_NEWNEIGH : RTM_DELNEIGH, flags);
756 if (!msg)
757 return -1;
758
759 nlmsg_append(msg, &ndm, sizeof(ndm), 0);
760
761 nla_put(msg, NDA_DST, sizeof(*addr), addr);
762
763 ret = nl_send_auto_complete(rtnl_socket, msg);
764 nlmsg_free(msg);
765
766 if (ret < 0)
767 return ret;
768
769 return nl_wait_for_ack(rtnl_socket);
770 }
771
772
773 int netlink_setup_addr(struct odhcpd_ipaddr *addr,
774 const int ifindex, const bool v6, const bool add)
775 {
776 struct nl_msg *msg;
777 struct ifaddrmsg ifa = {
778 .ifa_family = v6 ? AF_INET6 : AF_INET,
779 .ifa_prefixlen = addr->prefix,
780 .ifa_flags = 0,
781 .ifa_scope = 0,
782 .ifa_index = ifindex, };
783 int ret = 0, flags = NLM_F_REQUEST;
784
785 if (add)
786 flags |= NLM_F_REPLACE | NLM_F_CREATE;
787
788 msg = nlmsg_alloc_simple(add ? RTM_NEWADDR : RTM_DELADDR, 0);
789 if (!msg)
790 return -1;
791
792 nlmsg_append(msg, &ifa, sizeof(ifa), flags);
793 nla_put(msg, IFA_LOCAL, v6 ? 16 : 4, &addr->addr);
794 if (v6) {
795 struct ifa_cacheinfo cinfo = { .ifa_prefered = 0xffffffffU,
796 .ifa_valid = 0xffffffffU,
797 .cstamp = 0,
798 .tstamp = 0 };
799 time_t now = odhcpd_time();
800
801 if (addr->preferred) {
802 int64_t preferred = addr->preferred - now;
803 if (preferred < 0)
804 preferred = 0;
805 else if (preferred > UINT32_MAX)
806 preferred = UINT32_MAX;
807
808 cinfo.ifa_prefered = preferred;
809 }
810
811 if (addr->valid) {
812 int64_t valid = addr->valid - now;
813 if (valid <= 0) {
814 nlmsg_free(msg);
815 return -1;
816 }
817 else if (valid > UINT32_MAX)
818 valid = UINT32_MAX;
819
820 cinfo.ifa_valid = valid;
821 }
822
823 nla_put(msg, IFA_CACHEINFO, sizeof(cinfo), &cinfo);
824
825 nla_put_u32(msg, IFA_FLAGS, IFA_F_NOPREFIXROUTE);
826 } else {
827 if (addr->broadcast.s_addr)
828 nla_put_u32(msg, IFA_BROADCAST, addr->broadcast.s_addr);
829 }
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 void netlink_dump_neigh_table(const bool proxy)
841 {
842 struct nl_msg *msg;
843 struct ndmsg ndm = {
844 .ndm_family = AF_INET6,
845 .ndm_flags = proxy ? NTF_PROXY : 0,
846 };
847
848 msg = nlmsg_alloc_simple(RTM_GETNEIGH, NLM_F_REQUEST | NLM_F_DUMP);
849 if (!msg)
850 return;
851
852 nlmsg_append(msg, &ndm, sizeof(ndm), 0);
853
854 nl_send_auto_complete(rtnl_event.sock, msg);
855
856 nlmsg_free(msg);
857 }
858
859 void netlink_dump_addr_table(const bool v6)
860 {
861 struct nl_msg *msg;
862 struct ifaddrmsg ifa = {
863 .ifa_family = v6 ? AF_INET6 : AF_INET,
864 };
865
866 msg = nlmsg_alloc_simple(RTM_GETADDR, NLM_F_REQUEST | NLM_F_DUMP);
867 if (!msg)
868 return;
869
870 nlmsg_append(msg, &ifa, sizeof(ifa), 0);
871
872 nl_send_auto_complete(rtnl_event.sock, msg);
873
874 nlmsg_free(msg);
875 }