1 /*        $NetBSD: grabmyaddr.c,v 1.42 2025/03/08 16:39:08 christos 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(void *ctx, int fd);
71 static int kernel_open_socket(void);
72 static void kernel_sync(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(void)203 myaddr_flush(void)
204 {
205           myaddr_flush_list(&configured);
206 }
207 
208 int
myaddr_listen(struct sockaddr * addr,int udp_encap)209 myaddr_listen(struct sockaddr *addr, int udp_encap)
210 {
211           struct myaddr *my;
212 
213           if (sysdep_sa_len(addr) > sizeof(my->addr)) {
214                     plog(LLV_ERROR, LOCATION, NULL,
215                          "sockaddr size larger than sockaddr_storage\n");
216                     return -1;
217           }
218 
219           my = racoon_calloc(1, sizeof(struct myaddr));
220           if (my == NULL)
221                     return -1;
222 
223           memcpy(&my->addr, addr, sysdep_sa_len(addr));
224           my->udp_encap = udp_encap;
225           my->fd = -1;
226           LIST_INSERT_HEAD(&configured, my, chain);
227 
228           return 0;
229 }
230 
231 void
myaddr_sync()232 myaddr_sync()
233 {
234           struct myaddr *my, *next;
235 
236           if (!lcconf->strict_address) {
237                     kernel_sync();
238 
239                     /* delete all existing listeners which are not configured */
240                     for (my = LIST_FIRST(&opened); my; my = next) {
241                               next = LIST_NEXT(my, chain);
242 
243                               if (!myaddr_configured((struct sockaddr *) &my->addr))
244                                         myaddr_delete(my);
245                     }
246           }
247 }
248 
249 int
myaddr_getfd(struct sockaddr * addr)250 myaddr_getfd(struct sockaddr *addr)
251 {
252           struct myaddr *my;
253 
254           LIST_FOREACH(my, &opened, chain) {
255                     if (cmpsaddr((struct sockaddr *) &my->addr, addr) <= CMPSADDR_WILDPORT_MATCH)
256                               return my->fd;
257           }
258 
259           return -1;
260 }
261 
262 int
myaddr_getsport(struct sockaddr * addr)263 myaddr_getsport(struct sockaddr *addr)
264 {
265           struct myaddr *my;
266           int port = 0, wport;
267 
268           LIST_FOREACH(my, &opened, chain) {
269                     switch (cmpsaddr((struct sockaddr *) &my->addr, addr)) {
270                     case CMPSADDR_MATCH:
271                               return extract_port((struct sockaddr *) &my->addr);
272                     case CMPSADDR_WILDPORT_MATCH:
273                               wport = extract_port((struct sockaddr *) &my->addr);
274                               if (port == 0 || wport < port)
275                                         port = wport;
276                               break;
277                     }
278           }
279 
280           if (port == 0)
281                     port = PORT_ISAKMP;
282 
283           return port;
284 }
285 
286 void
myaddr_init_lists()287 myaddr_init_lists()
288 {
289           LIST_INIT(&configured);
290           LIST_INIT(&opened);
291 }
292 
293 int
myaddr_init()294 myaddr_init()
295 {
296         if (!lcconf->strict_address) {
297                     lcconf->rtsock = kernel_open_socket();
298                     if (lcconf->rtsock < 0)
299                               return -1;
300                     monitor_fd(lcconf->rtsock, kernel_receive, NULL, 0);
301           } else {
302                     lcconf->rtsock = -1;
303                     if (!myaddr_open_all_configured(NULL))
304                               return -1;
305           }
306           return 0;
307 }
308 
309 void
myaddr_close()310 myaddr_close()
311 {
312           myaddr_flush_list(&configured);
313           myaddr_flush_list(&opened);
314           if (lcconf->rtsock != -1) {
315                     unmonitor_fd(lcconf->rtsock);
316                     close(lcconf->rtsock);
317           }
318 }
319 
320 #if defined(USE_NETLINK)
321 
322 static int netlink_fd = -1;
323 
324 #define NLMSG_TAIL(nmsg) \
325           ((struct rtattr *) (((void *) (nmsg)) + NLMSG_ALIGN((nmsg)->nlmsg_len)))
326 
327 static void
parse_rtattr(struct rtattr * tb[],int max,struct rtattr * rta,int len)328 parse_rtattr(struct rtattr *tb[], int max, struct rtattr *rta, int len)
329 {
330           memset(tb, 0, sizeof(struct rtattr *) * (max + 1));
331           while (RTA_OK(rta, len)) {
332                     if (rta->rta_type <= max)
333                               tb[rta->rta_type] = rta;
334                     rta = RTA_NEXT(rta,len);
335           }
336 }
337 
338 static int
netlink_add_rtattr_l(struct nlmsghdr * n,int maxlen,int type,const void * data,int alen)339 netlink_add_rtattr_l(struct nlmsghdr *n, int maxlen, int type,
340                          const void *data, int alen)
341 {
342           int len = RTA_LENGTH(alen);
343           struct rtattr *rta;
344 
345           if (NLMSG_ALIGN(n->nlmsg_len) + RTA_ALIGN(len) > maxlen)
346                     return FALSE;
347 
348           rta = NLMSG_TAIL(n);
349           rta->rta_type = type;
350           rta->rta_len = len;
351           memcpy(RTA_DATA(rta), data, alen);
352           n->nlmsg_len = NLMSG_ALIGN(n->nlmsg_len) + RTA_ALIGN(len);
353           return TRUE;
354 }
355 
356 static int
netlink_enumerate(fd,family,type)357 netlink_enumerate(fd, family, type)
358           int fd;
359           int family;
360           int type;
361 {
362           struct {
363                     struct nlmsghdr nlh;
364                     struct rtgenmsg g;
365           } req;
366           struct sockaddr_nl addr;
367           static __u32 seq = 0;
368 
369           memset(&addr, 0, sizeof(addr));
370           addr.nl_family = AF_NETLINK;
371 
372           memset(&req, 0, sizeof(req));
373           req.nlh.nlmsg_len = sizeof(req);
374           req.nlh.nlmsg_type = type;
375           req.nlh.nlmsg_flags = NLM_F_ROOT | NLM_F_MATCH | NLM_F_REQUEST;
376           req.nlh.nlmsg_pid = 0;
377           req.nlh.nlmsg_seq = ++seq;
378           req.g.rtgen_family = family;
379 
380           return sendto(fd, (void *) &req, sizeof(req), 0,
381                           (struct sockaddr *) &addr, sizeof(addr)) >= 0;
382 }
383 
384 static void
netlink_add_del_address(int add,struct sockaddr * saddr)385 netlink_add_del_address(int add, struct sockaddr *saddr)
386 {
387           plog(LLV_DEBUG, LOCATION, NULL,
388                "Netlink: address %s %s\n",
389                saddrwop2str((struct sockaddr *) saddr),
390                add ? "added" : "deleted");
391 
392           if (add)
393                     myaddr_open_all_configured(saddr);
394           else
395                     myaddr_close_all_open(saddr);
396 }
397 
398 #ifdef INET6
399 static int
netlink_process_addr(struct nlmsghdr * h)400 netlink_process_addr(struct nlmsghdr *h)
401 {
402           struct sockaddr_storage addr;
403           struct ifaddrmsg *ifa;
404           struct rtattr *rta[IFA_MAX+1];
405           struct sockaddr_in6 *sin6;
406 
407           ifa = NLMSG_DATA(h);
408           parse_rtattr(rta, IFA_MAX, IFA_RTA(ifa), IFA_PAYLOAD(h));
409 
410           if (ifa->ifa_family != AF_INET6)
411                     return 0;
412           if (ifa->ifa_flags & IFA_F_TENTATIVE)
413                     return 0;
414           if (rta[IFA_LOCAL] == NULL)
415                     rta[IFA_LOCAL] = rta[IFA_ADDRESS];
416           if (rta[IFA_LOCAL] == NULL)
417                     return 0;
418 
419           memset(&addr, 0, sizeof(addr));
420           addr.ss_family = ifa->ifa_family;
421           sin6 = (struct sockaddr_in6 *) &addr;
422           memcpy(&sin6->sin6_addr, RTA_DATA(rta[IFA_LOCAL]),
423                     sizeof(sin6->sin6_addr));
424           if (!IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr))
425                     return 0;
426           sin6->sin6_scope_id = ifa->ifa_index;
427 
428           netlink_add_del_address(h->nlmsg_type == RTM_NEWADDR,
429                                         (struct sockaddr *) &addr);
430 
431           return 0;
432 }
433 #endif
434 
435 static int
netlink_route_is_local(int family,const unsigned char * addr,size_t addr_len)436 netlink_route_is_local(int family, const unsigned char *addr, size_t addr_len)
437 {
438           struct {
439                     struct nlmsghdr n;
440                     struct rtmsg    r;
441                     char            buf[1024];
442           } req;
443           struct rtmsg *r = NLMSG_DATA(&req.n);
444           struct rtattr *rta[RTA_MAX+1];
445           struct sockaddr_nl nladdr;
446           ssize_t rlen;
447 
448           memset(&req, 0, sizeof(req));
449           req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
450           req.n.nlmsg_flags = NLM_F_REQUEST;
451           req.n.nlmsg_type = RTM_GETROUTE;
452           req.r.rtm_family = family;
453           netlink_add_rtattr_l(&req.n, sizeof(req), RTA_DST,
454                                    addr, addr_len);
455           req.r.rtm_dst_len = addr_len * 8;
456 
457           memset(&nladdr, 0, sizeof(nladdr));
458           nladdr.nl_family = AF_NETLINK;
459 
460           if (sendto(netlink_fd, &req, sizeof(req), 0,
461                        (struct sockaddr *) &nladdr, sizeof(nladdr)) < 0)
462                     return 0;
463           rlen = recv(netlink_fd, &req, sizeof(req), 0);
464           if (rlen < 0)
465                     return 0;
466 
467           return  req.n.nlmsg_type == RTM_NEWROUTE &&
468                     req.r.rtm_type == RTN_LOCAL;
469 }
470 
471 static int
netlink_process_route(struct nlmsghdr * h)472 netlink_process_route(struct nlmsghdr *h)
473 {
474           struct sockaddr_storage addr;
475           struct rtmsg *rtm;
476           struct rtattr *rta[RTA_MAX+1];
477           struct sockaddr_in *sin;
478 #ifdef INET6
479           struct sockaddr_in6 *sin6;
480 #endif
481 
482           rtm = NLMSG_DATA(h);
483 
484           /* local IP addresses get local route in the local table */
485           if (rtm->rtm_type != RTN_LOCAL ||
486               rtm->rtm_table != RT_TABLE_LOCAL)
487                     return 0;
488 
489           parse_rtattr(rta, IFA_MAX, RTM_RTA(rtm), IFA_PAYLOAD(h));
490           if (rta[RTA_DST] == NULL)
491                     return 0;
492 
493           /* setup the socket address */
494           memset(&addr, 0, sizeof(addr));
495           addr.ss_family = rtm->rtm_family;
496           switch (rtm->rtm_family) {
497           case AF_INET:
498                     sin = (struct sockaddr_in *) &addr;
499                     memcpy(&sin->sin_addr, RTA_DATA(rta[RTA_DST]),
500                               sizeof(sin->sin_addr));
501                     break;
502 #ifdef INET6
503           case AF_INET6:
504                     sin6 = (struct sockaddr_in6 *) &addr;
505                     memcpy(&sin6->sin6_addr, RTA_DATA(rta[RTA_DST]),
506                               sizeof(sin6->sin6_addr));
507                     /* Link-local addresses are handled with RTM_NEWADDR
508                      * notifications */
509                     if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr))
510                               return 0;
511                     break;
512 #endif
513           default:
514                     return 0;
515           }
516 
517           /* If local route was deleted, check if there is still local
518            * route for the same IP on another interface */
519           if (h->nlmsg_type == RTM_DELROUTE &&
520               netlink_route_is_local(rtm->rtm_family,
521                                            RTA_DATA(rta[RTA_DST]),
522                                            RTA_PAYLOAD(rta[RTA_DST]))) {
523                     plog(LLV_DEBUG, LOCATION, NULL,
524                               "Netlink: not deleting %s yet, it exists still\n",
525                               saddrwop2str((struct sockaddr *) &addr));
526                     return 0;
527           }
528 
529           netlink_add_del_address(h->nlmsg_type == RTM_NEWROUTE,
530                                         (struct sockaddr *) &addr);
531           return 0;
532 }
533 
534 static int
netlink_process(struct nlmsghdr * h)535 netlink_process(struct nlmsghdr *h)
536 {
537           switch (h->nlmsg_type) {
538 #ifdef INET6
539           case RTM_NEWADDR:
540           case RTM_DELADDR:
541                     return netlink_process_addr(h);
542 #endif
543           case RTM_NEWROUTE:
544           case RTM_DELROUTE:
545                     return netlink_process_route(h);
546           }
547           return 0;
548 }
549 
550 static int
kernel_receive(ctx,fd)551 kernel_receive(ctx, fd)
552           void *ctx;
553           int fd;
554 {
555           struct sockaddr_nl nladdr;
556           struct iovec iov;
557           struct msghdr msg = {
558                     .msg_name = &nladdr,
559                     .msg_namelen = sizeof(nladdr),
560                     .msg_iov = &iov,
561                     .msg_iovlen = 1,
562           };
563           struct nlmsghdr *h;
564           int len, status;
565           char buf[16*1024];
566 
567           iov.iov_base = buf;
568           while (1) {
569                     iov.iov_len = sizeof(buf);
570                     status = recvmsg(fd, &msg, MSG_DONTWAIT);
571                     if (status < 0) {
572                               if (errno == EINTR)
573                                         continue;
574                               if (errno == EAGAIN)
575                                         return FALSE;
576                               continue;
577                     }
578                     if (status == 0)
579                               return FALSE;
580 
581                     h = (struct nlmsghdr *) buf;
582                     while (NLMSG_OK(h, status)) {
583                               netlink_process(h);
584                               h = NLMSG_NEXT(h, status);
585                     }
586           }
587 
588           return TRUE;
589 }
590 
591 static int
netlink_open_socket()592 netlink_open_socket()
593 {
594           int fd;
595 
596           fd = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
597           if (fd < 0) {
598                     plog(LLV_ERROR, LOCATION, NULL,
599                               "socket(PF_NETLINK) failed: %s",
600                               strerror(errno));
601                     return -1;
602           }
603           close_on_exec(fd);
604           if (fcntl(fd, F_SETFL, O_NONBLOCK) == -1)
605                     plog(LLV_WARNING, LOCATION, NULL,
606                          "failed to put socket in non-blocking mode\n");
607 
608           return fd;
609 }
610 
611 static int
kernel_open_socket()612 kernel_open_socket()
613 {
614           struct sockaddr_nl nl;
615           int fd;
616 
617           if (netlink_fd < 0) {
618                     netlink_fd = netlink_open_socket();
619                     if (netlink_fd < 0)
620                               return -1;
621           }
622 
623           fd = netlink_open_socket();
624           if (fd < 0)
625                     return fd;
626 
627           /* We monitor IPv4 addresses using RTMGRP_IPV4_ROUTE group
628            * the get the RTN_LOCAL routes which are automatically added
629            * by kernel. This is because:
630            *  - Linux kernel has a bug that calling bind() immediately
631            *    after IPv4 RTM_NEWADDR event can fail
632            *  - if IP is configured in multiple interfaces, we get
633            *    RTM_DELADDR for each of them. RTN_LOCAL gets deleted only
634            *    after the last IP address is deconfigured.
635            * The latter reason is also why I chose to use route
636            * notifications for IPv6. However, we do need to use RTM_NEWADDR
637            * for the link-local IPv6 addresses to get the interface index
638            * that is needed in bind().
639            */
640           memset(&nl, 0, sizeof(nl));
641           nl.nl_family = AF_NETLINK;
642           nl.nl_groups = RTMGRP_IPV4_ROUTE
643 #ifdef INET6
644                               | RTMGRP_IPV6_IFADDR | RTMGRP_IPV6_ROUTE
645 #endif
646                               ;
647           if (bind(fd, (struct sockaddr*) &nl, sizeof(nl)) < 0) {
648                     plog(LLV_ERROR, LOCATION, NULL,
649                          "bind(PF_NETLINK) failed: %s\n",
650                          strerror(errno));
651                     close(fd);
652                     return -1;
653           }
654           return fd;
655 }
656 
657 static void
kernel_sync()658 kernel_sync()
659 {
660           int fd = lcconf->rtsock;
661 
662           /* refresh addresses */
663           if (!netlink_enumerate(fd, PF_UNSPEC, RTM_GETROUTE)) {
664                     plog(LLV_ERROR, LOCATION, NULL,
665                          "unable to enumerate addresses: %s\n",
666                          strerror(errno));
667           }
668           while (kernel_receive(NULL, fd) == TRUE);
669 
670 #ifdef INET6
671           if (!netlink_enumerate(fd, PF_INET6, RTM_GETADDR)) {
672                     plog(LLV_ERROR, LOCATION, NULL,
673                          "unable to enumerate addresses: %s\n",
674                          strerror(errno));
675           }
676           while (kernel_receive(NULL, fd) == TRUE);
677 #endif
678 }
679 
680 #elif defined(USE_ROUTE)
681 
682 #ifndef RT_ROUNDUP
683 #define RT_ROUNDUP(a) \
684   ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
685 #endif
686 #define SAROUNDUP(X)   RT_ROUNDUP(((struct sockaddr *)(X))->sa_len)
687 
688 
689 static size_t
parse_address(caddr_t start,caddr_t end,struct sockaddr_storage * dest)690 parse_address(caddr_t start, caddr_t end, struct sockaddr_storage *dest)
691 {
692           size_t len;
693 
694           if (start >= end)
695                     return 0;
696 
697           len = SAROUNDUP(start);
698           if (start + len > end)
699                     return end - start;
700 
701           if (dest != NULL && len <= sizeof(struct sockaddr_storage))
702                     memcpy(dest, start, len);
703 
704           return len;
705 }
706 
707 static void
parse_addresses(caddr_t start,caddr_t end,int flags,struct sockaddr_storage * addr)708 parse_addresses(caddr_t start, caddr_t end, int flags,
709     struct sockaddr_storage *addr)
710 {
711           memset(addr, 0, sizeof(*addr));
712           if (flags & RTA_DST)
713                     start += parse_address(start, end, NULL);
714           if (flags & RTA_GATEWAY)
715                     start += parse_address(start, end, NULL);
716           if (flags & RTA_NETMASK)
717                     start += parse_address(start, end, NULL);
718           if (flags & RTA_GENMASK)
719                     start += parse_address(start, end, NULL);
720           if (flags & RTA_IFP)
721                     start += parse_address(start, end, NULL);
722           if (flags & RTA_IFA)
723                     start += parse_address(start, end, addr);
724           if (flags & RTA_AUTHOR)
725                     start += parse_address(start, end, NULL);
726           if (flags & RTA_BRD)
727                     start += parse_address(start, end, NULL);
728 }
729 
730 static void
kernel_handle_message(caddr_t msg)731 kernel_handle_message(caddr_t msg)
732 {
733           struct rt_msghdr *rtm = (struct rt_msghdr *) msg;
734           struct ifa_msghdr *ifa = (struct ifa_msghdr *) msg;
735           struct sockaddr_storage addr;
736 
737           switch (rtm->rtm_type) {
738           case RTM_NEWADDR:
739                     parse_addresses((caddr_t)(ifa + 1), msg + ifa->ifam_msglen,
740                                         ifa->ifam_addrs, &addr);
741                     myaddr_open_all_configured((struct sockaddr *) &addr);
742                     break;
743           case RTM_DELADDR:
744                     parse_addresses((caddr_t)(ifa + 1), msg + ifa->ifam_msglen,
745                                         ifa->ifam_addrs, &addr);
746                     myaddr_close_all_open((struct sockaddr *) &addr);
747                     break;
748           case RTM_ADD:
749           case RTM_DELETE:
750           case RTM_CHANGE:
751           case RTM_GET:
752           case RTM_MISS:
753 #ifdef RTM_LOSING
754           case RTM_LOSING:
755 #endif
756 #ifdef RTM_REDIRECT
757           case RTM_REDIRECT:
758 #endif
759           case RTM_IFINFO:
760 #ifdef RTM_OIFINFO
761           case RTM_OIFINFO:
762 #endif
763 #ifdef RTM_NEWMADDR
764           case RTM_NEWMADDR:
765           case RTM_DELMADDR:
766 #endif
767 #ifdef RTM_IFANNOUNCE
768           case RTM_IFANNOUNCE:
769 #endif
770 #ifdef RTM_IEEE80211
771           case RTM_IEEE80211:
772 #endif
773                     break;
774           default:
775                     plog(LLV_WARNING, LOCATION, NULL,
776                          "unrecognized route message with rtm_type: %d\n",
777                          rtm->rtm_type);
778                     break;
779           }
780 }
781 
782 /*ARGSUSED*/
783 static int
kernel_receive(void * ctx __unused,int fd)784 kernel_receive(void *ctx __unused, int fd)
785 {
786           char buf[16*1024];
787           struct rt_msghdr *rtm = (struct rt_msghdr *) buf;
788           ssize_t len;
789 
790           len = read(fd, &buf, sizeof(buf));
791           if (len <= 0) {
792                     if (len < 0 && errno != EWOULDBLOCK && errno != EAGAIN)
793                               plog(LLV_WARNING, LOCATION, NULL,
794                                    "routing socket error: %s", strerror(errno));
795                     return FALSE;
796           }
797 
798           if (rtm->rtm_msglen != len) {
799                     plog(LLV_WARNING, LOCATION, NULL,
800                          "kernel_receive: rtm->rtm_msglen %d, len %zd, type %d\n",
801                          rtm->rtm_msglen, len, rtm->rtm_type);
802                     return FALSE;
803           }
804 
805           kernel_handle_message(buf);
806           return TRUE;
807 }
808 
809 static int
kernel_open_socket()810 kernel_open_socket()
811 {
812           int fd;
813 #ifdef RO_MSGFILTER
814           unsigned char msgfilter[] = { RTM_NEWADDR, RTM_DELADDR };
815 #endif
816 
817           fd = socket(PF_ROUTE, SOCK_RAW, 0);
818           if (fd < 0) {
819                     plog(LLV_ERROR, LOCATION, NULL,
820                               "socket(PF_ROUTE) failed: %s",
821                               strerror(errno));
822                     return -1;
823           }
824 #ifdef RO_MSGFILTER
825           if (setsockopt(fd, PF_ROUTE, RO_MSGFILTER,
826               &msgfilter, sizeof(msgfilter)) < 0)
827                     plog(LLV_WARNING, LOCATION, NULL,
828                          "setsockopt(RO_MSGFILER) failed: %s",
829                          strerror(errno));
830 #endif
831           close_on_exec(fd);
832           if (fcntl(fd, F_SETFL, O_NONBLOCK) == -1)
833                     plog(LLV_WARNING, LOCATION, NULL,
834                          "failed to put socket in non-blocking mode\n");
835 
836           return fd;
837 }
838 
839 static void
kernel_sync()840 kernel_sync()
841 {
842           caddr_t ref, buf, end;
843           size_t bufsiz;
844           struct rt_msghdr *rtm;
845 
846 #define MIBSIZ 6
847           int mib[MIBSIZ] = {
848                     CTL_NET,
849                     PF_ROUTE,
850                     0,
851                     0, /*  AF_INET & AF_INET6 */
852                     NET_RT_IFLIST,
853                     0
854           };
855 
856           if (sysctl(mib, MIBSIZ, NULL, &bufsiz, NULL, 0) < 0) {
857                     plog(LLV_WARNING, LOCATION, NULL,
858                          "sysctl() error: %s", strerror(errno));
859                     return;
860           }
861 
862           ref = buf = racoon_malloc(bufsiz);
863 
864           if (sysctl(mib, MIBSIZ, buf, &bufsiz, NULL, 0) >= 0) {
865                     /* Parse both interfaces and addresses. */
866                     for (end = buf + bufsiz; buf < end; buf += rtm->rtm_msglen) {
867                               rtm = (struct rt_msghdr *) buf;
868                               if (rtm->rtm_version != RTM_VERSION)
869                                         continue;
870                               kernel_handle_message(buf);
871                     }
872           } else {
873                     plog(LLV_WARNING, LOCATION, NULL,
874                          "sysctl() error: %s", strerror(errno));
875           }
876 
877           racoon_free(ref);
878 }
879 
880 #else
881 
882 #error No supported interface to monitor local addresses.
883 
884 #endif
885