1 /* $NetBSD: grabmyaddr.c,v 1.40 2023/02/27 13:39:09 kardel Exp $ */
2 /*
3 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
4 * Copyright (C) 2008 Timo Teras <timo.teras@iki.fi>.
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. Neither the name of the project nor the names of its contributors
16 * may be used to endorse or promote products derived from this software
17 * without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
30 */
31
32 #include "config.h"
33
34 #include <errno.h>
35 #include <fcntl.h>
36 #include <unistd.h>
37 #include <string.h>
38 #include <sys/types.h>
39 #include <sys/queue.h>
40 #include <sys/socket.h>
41
42 #ifdef __linux__
43 #include <linux/netlink.h>
44 #include <linux/rtnetlink.h>
45 #define USE_NETLINK
46 #else
47 #include <net/route.h>
48 #include <net/if.h>
49 #include <net/if_dl.h>
50 #include <sys/sysctl.h>
51 #define USE_ROUTE
52 #endif
53
54 #include "var.h"
55 #include "misc.h"
56 #include "vmbuf.h"
57 #include "plog.h"
58 #include "sockmisc.h"
59 #include "session.h"
60 #include "debug.h"
61
62 #include "localconf.h"
63 #include "handler.h"
64 #include "grabmyaddr.h"
65 #include "sockmisc.h"
66 #include "isakmp_var.h"
67 #include "gcmalloc.h"
68 #include "nattraversal.h"
69
70 static int kernel_receive __P((void *ctx, int fd));
71 static int kernel_open_socket __P((void));
72 static void kernel_sync __P((void));
73
74 struct myaddr {
75 LIST_ENTRY(myaddr) chain;
76 struct sockaddr_storage addr;
77 int fd;
78 int udp_encap;
79 };
80
LIST_HEAD(_myaddr_list_,myaddr)81 static LIST_HEAD(_myaddr_list_, myaddr) configured, opened;
82
83 static void
84 myaddr_delete(struct myaddr *my)
85 {
86 if (my->fd != -1)
87 isakmp_close(my->fd);
88 LIST_REMOVE(my, chain);
89 racoon_free(my);
90 }
91
92 static int
myaddr_configured(struct sockaddr * addr)93 myaddr_configured(struct sockaddr *addr)
94 {
95 struct myaddr *cfg;
96
97 if (LIST_EMPTY(&configured))
98 return TRUE;
99
100 LIST_FOREACH(cfg, &configured, chain) {
101 if (cmpsaddr(addr, (struct sockaddr *) &cfg->addr) <= CMPSADDR_WILDPORT_MATCH)
102 return TRUE;
103 }
104
105 return FALSE;
106 }
107
108 static int
myaddr_open(struct sockaddr * addr,int udp_encap)109 myaddr_open(struct sockaddr *addr, int udp_encap)
110 {
111 struct myaddr *my;
112
113 /* Already open? */
114 LIST_FOREACH(my, &opened, chain) {
115 if (cmpsaddr(addr, (struct sockaddr *) &my->addr) <= CMPSADDR_WILDPORT_MATCH)
116 return TRUE;
117 }
118
119 my = racoon_calloc(1, sizeof(struct myaddr));
120 if (my == NULL)
121 return FALSE;
122
123 memcpy(&my->addr, addr, sysdep_sa_len(addr));
124 my->fd = isakmp_open(addr, udp_encap);
125 if (my->fd < 0) {
126 racoon_free(my);
127 return FALSE;
128 }
129 my->udp_encap = udp_encap;
130 LIST_INSERT_HEAD(&opened, my, chain);
131 return TRUE;
132 }
133
134 static int
myaddr_open_all_configured(struct sockaddr * addr)135 myaddr_open_all_configured(struct sockaddr *addr)
136 {
137 /* create all configured, not already opened addresses */
138 struct myaddr *cfg;
139
140 if (addr != NULL) {
141 switch (addr->sa_family) {
142 case AF_INET:
143 #ifdef INET6
144 case AF_INET6:
145 #endif
146 break;
147 default:
148 return FALSE;
149 }
150 }
151
152 LIST_FOREACH(cfg, &configured, chain) {
153 if (addr != NULL &&
154 cmpsaddr(addr, (struct sockaddr *) &cfg->addr) > CMPSADDR_WILDPORT_MATCH)
155 continue;
156 if (!myaddr_open((struct sockaddr *) &cfg->addr, cfg->udp_encap))
157 return FALSE;
158 }
159 if (LIST_EMPTY(&configured)) {
160 #ifdef ENABLE_HYBRID
161 /* Exclude any address we got through ISAKMP mode config */
162 if (exclude_cfg_addr(addr) == 0)
163 return FALSE;
164 #endif
165 set_port(addr, lcconf->port_isakmp);
166 myaddr_open(addr, FALSE);
167 #ifdef ENABLE_NATT
168 set_port(addr, lcconf->port_isakmp_natt);
169 myaddr_open(addr, TRUE);
170 #endif
171 }
172 return TRUE;
173 }
174
175 static void
myaddr_close_all_open(struct sockaddr * addr)176 myaddr_close_all_open(struct sockaddr *addr)
177 {
178 /* delete all matching open sockets */
179 struct myaddr *my, *next;
180
181 for (my = LIST_FIRST(&opened); my; my = next) {
182 next = LIST_NEXT(my, chain);
183
184 if (cmpsaddr((struct sockaddr *) addr,
185 (struct sockaddr *) &my->addr)
186 <= CMPSADDR_WOP_MATCH)
187 myaddr_delete(my);
188 }
189 }
190
191 static void
myaddr_flush_list(struct _myaddr_list_ * list)192 myaddr_flush_list(struct _myaddr_list_ *list)
193 {
194 struct myaddr *my, *next;
195
196 for (my = LIST_FIRST(list); my; my = next) {
197 next = LIST_NEXT(my, chain);
198 myaddr_delete(my);
199 }
200 }
201
202 void
myaddr_flush()203 myaddr_flush()
204 {
205 myaddr_flush_list(&configured);
206 }
207
208 int
myaddr_listen(addr,udp_encap)209 myaddr_listen(addr, udp_encap)
210 struct sockaddr *addr;
211 int udp_encap;
212 {
213 struct myaddr *my;
214
215 if (sysdep_sa_len(addr) > sizeof(my->addr)) {
216 plog(LLV_ERROR, LOCATION, NULL,
217 "sockaddr size larger than sockaddr_storage\n");
218 return -1;
219 }
220
221 my = racoon_calloc(1, sizeof(struct myaddr));
222 if (my == NULL)
223 return -1;
224
225 memcpy(&my->addr, addr, sysdep_sa_len(addr));
226 my->udp_encap = udp_encap;
227 my->fd = -1;
228 LIST_INSERT_HEAD(&configured, my, chain);
229
230 return 0;
231 }
232
233 void
myaddr_sync()234 myaddr_sync()
235 {
236 struct myaddr *my, *next;
237
238 if (!lcconf->strict_address) {
239 kernel_sync();
240
241 /* delete all existing listeners which are not configured */
242 for (my = LIST_FIRST(&opened); my; my = next) {
243 next = LIST_NEXT(my, chain);
244
245 if (!myaddr_configured((struct sockaddr *) &my->addr))
246 myaddr_delete(my);
247 }
248 }
249 }
250
251 int
myaddr_getfd(addr)252 myaddr_getfd(addr)
253 struct sockaddr *addr;
254 {
255 struct myaddr *my;
256
257 LIST_FOREACH(my, &opened, chain) {
258 if (cmpsaddr((struct sockaddr *) &my->addr, addr) <= CMPSADDR_WILDPORT_MATCH)
259 return my->fd;
260 }
261
262 return -1;
263 }
264
265 int
myaddr_getsport(addr)266 myaddr_getsport(addr)
267 struct sockaddr *addr;
268 {
269 struct myaddr *my;
270 int port = 0, wport;
271
272 LIST_FOREACH(my, &opened, chain) {
273 switch (cmpsaddr((struct sockaddr *) &my->addr, addr)) {
274 case CMPSADDR_MATCH:
275 return extract_port((struct sockaddr *) &my->addr);
276 case CMPSADDR_WILDPORT_MATCH:
277 wport = extract_port((struct sockaddr *) &my->addr);
278 if (port == 0 || wport < port)
279 port = wport;
280 break;
281 }
282 }
283
284 if (port == 0)
285 port = PORT_ISAKMP;
286
287 return port;
288 }
289
290 void
myaddr_init_lists()291 myaddr_init_lists()
292 {
293 LIST_INIT(&configured);
294 LIST_INIT(&opened);
295 }
296
297 int
myaddr_init()298 myaddr_init()
299 {
300 if (!lcconf->strict_address) {
301 lcconf->rtsock = kernel_open_socket();
302 if (lcconf->rtsock < 0)
303 return -1;
304 monitor_fd(lcconf->rtsock, kernel_receive, NULL, 0);
305 } else {
306 lcconf->rtsock = -1;
307 if (!myaddr_open_all_configured(NULL))
308 return -1;
309 }
310 return 0;
311 }
312
313 void
myaddr_close()314 myaddr_close()
315 {
316 myaddr_flush_list(&configured);
317 myaddr_flush_list(&opened);
318 if (lcconf->rtsock != -1) {
319 unmonitor_fd(lcconf->rtsock);
320 close(lcconf->rtsock);
321 }
322 }
323
324 #if defined(USE_NETLINK)
325
326 static int netlink_fd = -1;
327
328 #define NLMSG_TAIL(nmsg) \
329 ((struct rtattr *) (((void *) (nmsg)) + NLMSG_ALIGN((nmsg)->nlmsg_len)))
330
331 static void
parse_rtattr(struct rtattr * tb[],int max,struct rtattr * rta,int len)332 parse_rtattr(struct rtattr *tb[], int max, struct rtattr *rta, int len)
333 {
334 memset(tb, 0, sizeof(struct rtattr *) * (max + 1));
335 while (RTA_OK(rta, len)) {
336 if (rta->rta_type <= max)
337 tb[rta->rta_type] = rta;
338 rta = RTA_NEXT(rta,len);
339 }
340 }
341
342 static int
netlink_add_rtattr_l(struct nlmsghdr * n,int maxlen,int type,const void * data,int alen)343 netlink_add_rtattr_l(struct nlmsghdr *n, int maxlen, int type,
344 const void *data, int alen)
345 {
346 int len = RTA_LENGTH(alen);
347 struct rtattr *rta;
348
349 if (NLMSG_ALIGN(n->nlmsg_len) + RTA_ALIGN(len) > maxlen)
350 return FALSE;
351
352 rta = NLMSG_TAIL(n);
353 rta->rta_type = type;
354 rta->rta_len = len;
355 memcpy(RTA_DATA(rta), data, alen);
356 n->nlmsg_len = NLMSG_ALIGN(n->nlmsg_len) + RTA_ALIGN(len);
357 return TRUE;
358 }
359
360 static int
netlink_enumerate(fd,family,type)361 netlink_enumerate(fd, family, type)
362 int fd;
363 int family;
364 int type;
365 {
366 struct {
367 struct nlmsghdr nlh;
368 struct rtgenmsg g;
369 } req;
370 struct sockaddr_nl addr;
371 static __u32 seq = 0;
372
373 memset(&addr, 0, sizeof(addr));
374 addr.nl_family = AF_NETLINK;
375
376 memset(&req, 0, sizeof(req));
377 req.nlh.nlmsg_len = sizeof(req);
378 req.nlh.nlmsg_type = type;
379 req.nlh.nlmsg_flags = NLM_F_ROOT | NLM_F_MATCH | NLM_F_REQUEST;
380 req.nlh.nlmsg_pid = 0;
381 req.nlh.nlmsg_seq = ++seq;
382 req.g.rtgen_family = family;
383
384 return sendto(fd, (void *) &req, sizeof(req), 0,
385 (struct sockaddr *) &addr, sizeof(addr)) >= 0;
386 }
387
388 static void
netlink_add_del_address(int add,struct sockaddr * saddr)389 netlink_add_del_address(int add, struct sockaddr *saddr)
390 {
391 plog(LLV_DEBUG, LOCATION, NULL,
392 "Netlink: address %s %s\n",
393 saddrwop2str((struct sockaddr *) saddr),
394 add ? "added" : "deleted");
395
396 if (add)
397 myaddr_open_all_configured(saddr);
398 else
399 myaddr_close_all_open(saddr);
400 }
401
402 #ifdef INET6
403 static int
netlink_process_addr(struct nlmsghdr * h)404 netlink_process_addr(struct nlmsghdr *h)
405 {
406 struct sockaddr_storage addr;
407 struct ifaddrmsg *ifa;
408 struct rtattr *rta[IFA_MAX+1];
409 struct sockaddr_in6 *sin6;
410
411 ifa = NLMSG_DATA(h);
412 parse_rtattr(rta, IFA_MAX, IFA_RTA(ifa), IFA_PAYLOAD(h));
413
414 if (ifa->ifa_family != AF_INET6)
415 return 0;
416 if (ifa->ifa_flags & IFA_F_TENTATIVE)
417 return 0;
418 if (rta[IFA_LOCAL] == NULL)
419 rta[IFA_LOCAL] = rta[IFA_ADDRESS];
420 if (rta[IFA_LOCAL] == NULL)
421 return 0;
422
423 memset(&addr, 0, sizeof(addr));
424 addr.ss_family = ifa->ifa_family;
425 sin6 = (struct sockaddr_in6 *) &addr;
426 memcpy(&sin6->sin6_addr, RTA_DATA(rta[IFA_LOCAL]),
427 sizeof(sin6->sin6_addr));
428 if (!IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr))
429 return 0;
430 sin6->sin6_scope_id = ifa->ifa_index;
431
432 netlink_add_del_address(h->nlmsg_type == RTM_NEWADDR,
433 (struct sockaddr *) &addr);
434
435 return 0;
436 }
437 #endif
438
439 static int
netlink_route_is_local(int family,const unsigned char * addr,size_t addr_len)440 netlink_route_is_local(int family, const unsigned char *addr, size_t addr_len)
441 {
442 struct {
443 struct nlmsghdr n;
444 struct rtmsg r;
445 char buf[1024];
446 } req;
447 struct rtmsg *r = NLMSG_DATA(&req.n);
448 struct rtattr *rta[RTA_MAX+1];
449 struct sockaddr_nl nladdr;
450 ssize_t rlen;
451
452 memset(&req, 0, sizeof(req));
453 req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
454 req.n.nlmsg_flags = NLM_F_REQUEST;
455 req.n.nlmsg_type = RTM_GETROUTE;
456 req.r.rtm_family = family;
457 netlink_add_rtattr_l(&req.n, sizeof(req), RTA_DST,
458 addr, addr_len);
459 req.r.rtm_dst_len = addr_len * 8;
460
461 memset(&nladdr, 0, sizeof(nladdr));
462 nladdr.nl_family = AF_NETLINK;
463
464 if (sendto(netlink_fd, &req, sizeof(req), 0,
465 (struct sockaddr *) &nladdr, sizeof(nladdr)) < 0)
466 return 0;
467 rlen = recv(netlink_fd, &req, sizeof(req), 0);
468 if (rlen < 0)
469 return 0;
470
471 return req.n.nlmsg_type == RTM_NEWROUTE &&
472 req.r.rtm_type == RTN_LOCAL;
473 }
474
475 static int
netlink_process_route(struct nlmsghdr * h)476 netlink_process_route(struct nlmsghdr *h)
477 {
478 struct sockaddr_storage addr;
479 struct rtmsg *rtm;
480 struct rtattr *rta[RTA_MAX+1];
481 struct sockaddr_in *sin;
482 #ifdef INET6
483 struct sockaddr_in6 *sin6;
484 #endif
485
486 rtm = NLMSG_DATA(h);
487
488 /* local IP addresses get local route in the local table */
489 if (rtm->rtm_type != RTN_LOCAL ||
490 rtm->rtm_table != RT_TABLE_LOCAL)
491 return 0;
492
493 parse_rtattr(rta, IFA_MAX, RTM_RTA(rtm), IFA_PAYLOAD(h));
494 if (rta[RTA_DST] == NULL)
495 return 0;
496
497 /* setup the socket address */
498 memset(&addr, 0, sizeof(addr));
499 addr.ss_family = rtm->rtm_family;
500 switch (rtm->rtm_family) {
501 case AF_INET:
502 sin = (struct sockaddr_in *) &addr;
503 memcpy(&sin->sin_addr, RTA_DATA(rta[RTA_DST]),
504 sizeof(sin->sin_addr));
505 break;
506 #ifdef INET6
507 case AF_INET6:
508 sin6 = (struct sockaddr_in6 *) &addr;
509 memcpy(&sin6->sin6_addr, RTA_DATA(rta[RTA_DST]),
510 sizeof(sin6->sin6_addr));
511 /* Link-local addresses are handled with RTM_NEWADDR
512 * notifications */
513 if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr))
514 return 0;
515 break;
516 #endif
517 default:
518 return 0;
519 }
520
521 /* If local route was deleted, check if there is still local
522 * route for the same IP on another interface */
523 if (h->nlmsg_type == RTM_DELROUTE &&
524 netlink_route_is_local(rtm->rtm_family,
525 RTA_DATA(rta[RTA_DST]),
526 RTA_PAYLOAD(rta[RTA_DST]))) {
527 plog(LLV_DEBUG, LOCATION, NULL,
528 "Netlink: not deleting %s yet, it exists still\n",
529 saddrwop2str((struct sockaddr *) &addr));
530 return 0;
531 }
532
533 netlink_add_del_address(h->nlmsg_type == RTM_NEWROUTE,
534 (struct sockaddr *) &addr);
535 return 0;
536 }
537
538 static int
netlink_process(struct nlmsghdr * h)539 netlink_process(struct nlmsghdr *h)
540 {
541 switch (h->nlmsg_type) {
542 #ifdef INET6
543 case RTM_NEWADDR:
544 case RTM_DELADDR:
545 return netlink_process_addr(h);
546 #endif
547 case RTM_NEWROUTE:
548 case RTM_DELROUTE:
549 return netlink_process_route(h);
550 }
551 return 0;
552 }
553
554 static int
kernel_receive(ctx,fd)555 kernel_receive(ctx, fd)
556 void *ctx;
557 int fd;
558 {
559 struct sockaddr_nl nladdr;
560 struct iovec iov;
561 struct msghdr msg = {
562 .msg_name = &nladdr,
563 .msg_namelen = sizeof(nladdr),
564 .msg_iov = &iov,
565 .msg_iovlen = 1,
566 };
567 struct nlmsghdr *h;
568 int len, status;
569 char buf[16*1024];
570
571 iov.iov_base = buf;
572 while (1) {
573 iov.iov_len = sizeof(buf);
574 status = recvmsg(fd, &msg, MSG_DONTWAIT);
575 if (status < 0) {
576 if (errno == EINTR)
577 continue;
578 if (errno == EAGAIN)
579 return FALSE;
580 continue;
581 }
582 if (status == 0)
583 return FALSE;
584
585 h = (struct nlmsghdr *) buf;
586 while (NLMSG_OK(h, status)) {
587 netlink_process(h);
588 h = NLMSG_NEXT(h, status);
589 }
590 }
591
592 return TRUE;
593 }
594
595 static int
netlink_open_socket()596 netlink_open_socket()
597 {
598 int fd;
599
600 fd = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
601 if (fd < 0) {
602 plog(LLV_ERROR, LOCATION, NULL,
603 "socket(PF_NETLINK) failed: %s",
604 strerror(errno));
605 return -1;
606 }
607 close_on_exec(fd);
608 if (fcntl(fd, F_SETFL, O_NONBLOCK) == -1)
609 plog(LLV_WARNING, LOCATION, NULL,
610 "failed to put socket in non-blocking mode\n");
611
612 return fd;
613 }
614
615 static int
kernel_open_socket()616 kernel_open_socket()
617 {
618 struct sockaddr_nl nl;
619 int fd;
620
621 if (netlink_fd < 0) {
622 netlink_fd = netlink_open_socket();
623 if (netlink_fd < 0)
624 return -1;
625 }
626
627 fd = netlink_open_socket();
628 if (fd < 0)
629 return fd;
630
631 /* We monitor IPv4 addresses using RTMGRP_IPV4_ROUTE group
632 * the get the RTN_LOCAL routes which are automatically added
633 * by kernel. This is because:
634 * - Linux kernel has a bug that calling bind() immediately
635 * after IPv4 RTM_NEWADDR event can fail
636 * - if IP is configured in multiple interfaces, we get
637 * RTM_DELADDR for each of them. RTN_LOCAL gets deleted only
638 * after the last IP address is deconfigured.
639 * The latter reason is also why I chose to use route
640 * notifications for IPv6. However, we do need to use RTM_NEWADDR
641 * for the link-local IPv6 addresses to get the interface index
642 * that is needed in bind().
643 */
644 memset(&nl, 0, sizeof(nl));
645 nl.nl_family = AF_NETLINK;
646 nl.nl_groups = RTMGRP_IPV4_ROUTE
647 #ifdef INET6
648 | RTMGRP_IPV6_IFADDR | RTMGRP_IPV6_ROUTE
649 #endif
650 ;
651 if (bind(fd, (struct sockaddr*) &nl, sizeof(nl)) < 0) {
652 plog(LLV_ERROR, LOCATION, NULL,
653 "bind(PF_NETLINK) failed: %s\n",
654 strerror(errno));
655 close(fd);
656 return -1;
657 }
658 return fd;
659 }
660
661 static void
kernel_sync()662 kernel_sync()
663 {
664 int fd = lcconf->rtsock;
665
666 /* refresh addresses */
667 if (!netlink_enumerate(fd, PF_UNSPEC, RTM_GETROUTE)) {
668 plog(LLV_ERROR, LOCATION, NULL,
669 "unable to enumerate addresses: %s\n",
670 strerror(errno));
671 }
672 while (kernel_receive(NULL, fd) == TRUE);
673
674 #ifdef INET6
675 if (!netlink_enumerate(fd, PF_INET6, RTM_GETADDR)) {
676 plog(LLV_ERROR, LOCATION, NULL,
677 "unable to enumerate addresses: %s\n",
678 strerror(errno));
679 }
680 while (kernel_receive(NULL, fd) == TRUE);
681 #endif
682 }
683
684 #elif defined(USE_ROUTE)
685
686 #ifndef RT_ROUNDUP
687 #define RT_ROUNDUP(a) \
688 ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
689 #endif
690 #define SAROUNDUP(X) RT_ROUNDUP(((struct sockaddr *)(X))->sa_len)
691
692
693 static size_t
parse_address(caddr_t start,caddr_t end,struct sockaddr_storage * dest)694 parse_address(caddr_t start, caddr_t end, struct sockaddr_storage *dest)
695 {
696 int len;
697
698 if (start >= end)
699 return 0;
700
701 len = SAROUNDUP(start);
702 if (start + len > end)
703 return end - start;
704
705 if (dest != NULL && len <= sizeof(struct sockaddr_storage))
706 memcpy(dest, start, len);
707
708 return len;
709 }
710
711 static void
parse_addresses(start,end,flags,addr)712 parse_addresses(start, end, flags, addr)
713 caddr_t start;
714 caddr_t end;
715 int flags;
716 struct sockaddr_storage *addr;
717 {
718 memset(addr, 0, sizeof(*addr));
719 if (flags & RTA_DST)
720 start += parse_address(start, end, NULL);
721 if (flags & RTA_GATEWAY)
722 start += parse_address(start, end, NULL);
723 if (flags & RTA_NETMASK)
724 start += parse_address(start, end, NULL);
725 if (flags & RTA_GENMASK)
726 start += parse_address(start, end, NULL);
727 if (flags & RTA_IFP)
728 start += parse_address(start, end, NULL);
729 if (flags & RTA_IFA)
730 start += parse_address(start, end, addr);
731 if (flags & RTA_AUTHOR)
732 start += parse_address(start, end, NULL);
733 if (flags & RTA_BRD)
734 start += parse_address(start, end, NULL);
735 }
736
737 static void
kernel_handle_message(caddr_t msg)738 kernel_handle_message(caddr_t msg)
739 {
740 struct rt_msghdr *rtm = (struct rt_msghdr *) msg;
741 struct ifa_msghdr *ifa = (struct ifa_msghdr *) msg;
742 struct sockaddr_storage addr;
743
744 switch (rtm->rtm_type) {
745 case RTM_NEWADDR:
746 parse_addresses(ifa + 1, msg + ifa->ifam_msglen,
747 ifa->ifam_addrs, &addr);
748 myaddr_open_all_configured((struct sockaddr *) &addr);
749 break;
750 case RTM_DELADDR:
751 parse_addresses(ifa + 1, msg + ifa->ifam_msglen,
752 ifa->ifam_addrs, &addr);
753 myaddr_close_all_open((struct sockaddr *) &addr);
754 break;
755 case RTM_ADD:
756 case RTM_DELETE:
757 case RTM_CHANGE:
758 case RTM_GET:
759 case RTM_MISS:
760 #ifdef RTM_LOSING
761 case RTM_LOSING:
762 #endif
763 #ifdef RTM_REDIRECT
764 case RTM_REDIRECT:
765 #endif
766 case RTM_IFINFO:
767 #ifdef RTM_OIFINFO
768 case RTM_OIFINFO:
769 #endif
770 #ifdef RTM_NEWMADDR
771 case RTM_NEWMADDR:
772 case RTM_DELMADDR:
773 #endif
774 #ifdef RTM_IFANNOUNCE
775 case RTM_IFANNOUNCE:
776 #endif
777 #ifdef RTM_IEEE80211
778 case RTM_IEEE80211:
779 #endif
780 break;
781 default:
782 plog(LLV_WARNING, LOCATION, NULL,
783 "unrecognized route message with rtm_type: %d\n",
784 rtm->rtm_type);
785 break;
786 }
787 }
788
789 static int
kernel_receive(ctx,fd)790 kernel_receive(ctx, fd)
791 void *ctx;
792 int fd;
793 {
794 char buf[16*1024];
795 struct rt_msghdr *rtm = (struct rt_msghdr *) buf;
796 int len;
797
798 len = read(fd, &buf, sizeof(buf));
799 if (len <= 0) {
800 if (len < 0 && errno != EWOULDBLOCK && errno != EAGAIN)
801 plog(LLV_WARNING, LOCATION, NULL,
802 "routing socket error: %s", strerror(errno));
803 return FALSE;
804 }
805
806 if (rtm->rtm_msglen != len) {
807 plog(LLV_WARNING, LOCATION, NULL,
808 "kernel_receive: rtm->rtm_msglen %d, len %d, type %d\n",
809 rtm->rtm_msglen, len, rtm->rtm_type);
810 return FALSE;
811 }
812
813 kernel_handle_message(buf);
814 return TRUE;
815 }
816
817 static int
kernel_open_socket()818 kernel_open_socket()
819 {
820 int fd;
821 #ifdef RO_MSGFILTER
822 unsigned char msgfilter[] = { RTM_NEWADDR, RTM_DELADDR };
823 #endif
824
825 fd = socket(PF_ROUTE, SOCK_RAW, 0);
826 if (fd < 0) {
827 plog(LLV_ERROR, LOCATION, NULL,
828 "socket(PF_ROUTE) failed: %s",
829 strerror(errno));
830 return -1;
831 }
832 #ifdef RO_MSGFILTER
833 if (setsockopt(fd, PF_ROUTE, RO_MSGFILTER,
834 &msgfilter, sizeof(msgfilter)) < 0)
835 plog(LLV_WARNING, LOCATION, NULL,
836 "setsockopt(RO_MSGFILER) failed: %s",
837 strerror(errno));
838 #endif
839 close_on_exec(fd);
840 if (fcntl(fd, F_SETFL, O_NONBLOCK) == -1)
841 plog(LLV_WARNING, LOCATION, NULL,
842 "failed to put socket in non-blocking mode\n");
843
844 return fd;
845 }
846
847 static void
kernel_sync()848 kernel_sync()
849 {
850 caddr_t ref, buf, end;
851 size_t bufsiz;
852 struct rt_msghdr *rtm;
853
854 #define MIBSIZ 6
855 int mib[MIBSIZ] = {
856 CTL_NET,
857 PF_ROUTE,
858 0,
859 0, /* AF_INET & AF_INET6 */
860 NET_RT_IFLIST,
861 0
862 };
863
864 if (sysctl(mib, MIBSIZ, NULL, &bufsiz, NULL, 0) < 0) {
865 plog(LLV_WARNING, LOCATION, NULL,
866 "sysctl() error: %s", strerror(errno));
867 return;
868 }
869
870 ref = buf = racoon_malloc(bufsiz);
871
872 if (sysctl(mib, MIBSIZ, buf, &bufsiz, NULL, 0) >= 0) {
873 /* Parse both interfaces and addresses. */
874 for (end = buf + bufsiz; buf < end; buf += rtm->rtm_msglen) {
875 rtm = (struct rt_msghdr *) buf;
876 if (rtm->rtm_version != RTM_VERSION)
877 continue;
878 kernel_handle_message(buf);
879 }
880 } else {
881 plog(LLV_WARNING, LOCATION, NULL,
882 "sysctl() error: %s", strerror(errno));
883 }
884
885 racoon_free(ref);
886 }
887
888 #else
889
890 #error No supported interface to monitor local addresses.
891
892 #endif
893