1 /* $NetBSD: grabmyaddr.c,v 1.28 2011/03/14 17:18:12 tteras 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(my)
85 struct myaddr *my;
86 {
87 if (my->fd != -1)
88 isakmp_close(my->fd);
89 LIST_REMOVE(my, chain);
90 racoon_free(my);
91 }
92
93 static int
myaddr_configured(addr)94 myaddr_configured(addr)
95 struct sockaddr *addr;
96 {
97 struct myaddr *cfg;
98
99 if (LIST_EMPTY(&configured))
100 return TRUE;
101
102 LIST_FOREACH(cfg, &configured, chain) {
103 if (cmpsaddr(addr, (struct sockaddr *) &cfg->addr) <= CMPSADDR_WILDPORT_MATCH)
104 return TRUE;
105 }
106
107 return FALSE;
108 }
109
110 static int
myaddr_open(addr,udp_encap)111 myaddr_open(addr, udp_encap)
112 struct sockaddr *addr;
113 int udp_encap;
114 {
115 struct myaddr *my;
116
117 /* Already open? */
118 LIST_FOREACH(my, &opened, chain) {
119 if (cmpsaddr(addr, (struct sockaddr *) &my->addr) <= CMPSADDR_WILDPORT_MATCH)
120 return TRUE;
121 }
122
123 my = racoon_calloc(1, sizeof(struct myaddr));
124 if (my == NULL)
125 return FALSE;
126
127 memcpy(&my->addr, addr, sysdep_sa_len(addr));
128 my->fd = isakmp_open(addr, udp_encap);
129 if (my->fd < 0) {
130 racoon_free(my);
131 return FALSE;
132 }
133 my->udp_encap = udp_encap;
134 LIST_INSERT_HEAD(&opened, my, chain);
135 return TRUE;
136 }
137
138 static int
myaddr_open_all_configured(addr)139 myaddr_open_all_configured(addr)
140 struct sockaddr *addr;
141 {
142 /* create all configured, not already opened addresses */
143 struct myaddr *cfg, *my;
144
145 if (addr != NULL) {
146 switch (addr->sa_family) {
147 case AF_INET:
148 #ifdef INET6
149 case AF_INET6:
150 #endif
151 break;
152 default:
153 return FALSE;
154 }
155 }
156
157 LIST_FOREACH(cfg, &configured, chain) {
158 if (addr != NULL &&
159 cmpsaddr(addr, (struct sockaddr *) &cfg->addr) > CMPSADDR_WILDPORT_MATCH)
160 continue;
161 if (!myaddr_open((struct sockaddr *) &cfg->addr, cfg->udp_encap))
162 return FALSE;
163 }
164 if (LIST_EMPTY(&configured)) {
165 #ifdef ENABLE_HYBRID
166 /* Exclude any address we got through ISAKMP mode config */
167 if (exclude_cfg_addr(addr) == 0)
168 return FALSE;
169 #endif
170 set_port(addr, lcconf->port_isakmp);
171 myaddr_open(addr, FALSE);
172 #ifdef ENABLE_NATT
173 set_port(addr, lcconf->port_isakmp_natt);
174 myaddr_open(addr, TRUE);
175 #endif
176 }
177 return TRUE;
178 }
179
180 static void
myaddr_close_all_open(addr)181 myaddr_close_all_open(addr)
182 struct sockaddr *addr;
183 {
184 /* delete all matching open sockets */
185 struct myaddr *my, *next;
186
187 for (my = LIST_FIRST(&opened); my; my = next) {
188 next = LIST_NEXT(my, chain);
189
190 if (cmpsaddr((struct sockaddr *) addr,
191 (struct sockaddr *) &my->addr)
192 <= CMPSADDR_WOP_MATCH)
193 myaddr_delete(my);
194 }
195 }
196
197 static void
myaddr_flush_list(list)198 myaddr_flush_list(list)
199 struct _myaddr_list_ *list;
200 {
201 struct myaddr *my, *next;
202
203 for (my = LIST_FIRST(list); my; my = next) {
204 next = LIST_NEXT(my, chain);
205 myaddr_delete(my);
206 }
207 }
208
209 void
myaddr_flush()210 myaddr_flush()
211 {
212 myaddr_flush_list(&configured);
213 }
214
215 int
myaddr_listen(addr,udp_encap)216 myaddr_listen(addr, udp_encap)
217 struct sockaddr *addr;
218 int udp_encap;
219 {
220 struct myaddr *my;
221
222 if (sysdep_sa_len(addr) > sizeof(my->addr)) {
223 plog(LLV_ERROR, LOCATION, NULL,
224 "sockaddr size larger than sockaddr_storage\n");
225 return -1;
226 }
227
228 my = racoon_calloc(1, sizeof(struct myaddr));
229 if (my == NULL)
230 return -1;
231
232 memcpy(&my->addr, addr, sysdep_sa_len(addr));
233 my->udp_encap = udp_encap;
234 my->fd = -1;
235 LIST_INSERT_HEAD(&configured, my, chain);
236
237 return 0;
238 }
239
240 void
myaddr_sync()241 myaddr_sync()
242 {
243 struct myaddr *my, *next;
244
245 if (!lcconf->strict_address) {
246 kernel_sync();
247
248 /* delete all existing listeners which are not configured */
249 for (my = LIST_FIRST(&opened); my; my = next) {
250 next = LIST_NEXT(my, chain);
251
252 if (!myaddr_configured((struct sockaddr *) &my->addr))
253 myaddr_delete(my);
254 }
255 }
256 }
257
258 int
myaddr_getfd(addr)259 myaddr_getfd(addr)
260 struct sockaddr *addr;
261 {
262 struct myaddr *my;
263
264 LIST_FOREACH(my, &opened, chain) {
265 if (cmpsaddr((struct sockaddr *) &my->addr, addr) <= CMPSADDR_WILDPORT_MATCH)
266 return my->fd;
267 }
268
269 return -1;
270 }
271
272 int
myaddr_getsport(addr)273 myaddr_getsport(addr)
274 struct sockaddr *addr;
275 {
276 struct myaddr *my;
277
278 LIST_FOREACH(my, &opened, chain) {
279 if (cmpsaddr((struct sockaddr *) &my->addr, addr) <= CMPSADDR_WILDPORT_MATCH)
280 return extract_port((struct sockaddr *) &my->addr);
281 }
282
283 return PORT_ISAKMP;
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 #define ROUNDUP(a) \
683 ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
684
685 #define SAROUNDUP(X) ROUNDUP(((struct sockaddr *)(X))->sa_len)
686
687 static size_t
parse_address(start,end,dest)688 parse_address(start, end, dest)
689 caddr_t start;
690 caddr_t end;
691 struct sockaddr_storage *dest;
692 {
693 int len;
694
695 if (start >= end)
696 return 0;
697
698 len = SAROUNDUP(start);
699 if (start + len > end)
700 return end - start;
701
702 if (dest != NULL && len <= sizeof(struct sockaddr_storage))
703 memcpy(dest, start, len);
704
705 return len;
706 }
707
708 static void
parse_addresses(start,end,flags,addr)709 parse_addresses(start, end, flags, addr)
710 caddr_t start;
711 caddr_t end;
712 int flags;
713 struct sockaddr_storage *addr;
714 {
715 memset(addr, 0, sizeof(*addr));
716 if (flags & RTA_DST)
717 start += parse_address(start, end, NULL);
718 if (flags & RTA_GATEWAY)
719 start += parse_address(start, end, NULL);
720 if (flags & RTA_NETMASK)
721 start += parse_address(start, end, NULL);
722 if (flags & RTA_GENMASK)
723 start += parse_address(start, end, NULL);
724 if (flags & RTA_IFP)
725 start += parse_address(start, end, NULL);
726 if (flags & RTA_IFA)
727 start += parse_address(start, end, addr);
728 if (flags & RTA_AUTHOR)
729 start += parse_address(start, end, NULL);
730 if (flags & RTA_BRD)
731 start += parse_address(start, end, NULL);
732 }
733
734 static void
kernel_handle_message(msg)735 kernel_handle_message(msg)
736 caddr_t msg;
737 {
738 struct rt_msghdr *rtm = (struct rt_msghdr *) msg;
739 struct ifa_msghdr *ifa = (struct ifa_msghdr *) msg;
740 struct sockaddr_storage addr;
741
742 switch (rtm->rtm_type) {
743 case RTM_NEWADDR:
744 parse_addresses(ifa + 1, msg + ifa->ifam_msglen,
745 ifa->ifam_addrs, &addr);
746 myaddr_open_all_configured((struct sockaddr *) &addr);
747 break;
748 case RTM_DELADDR:
749 parse_addresses(ifa + 1, msg + ifa->ifam_msglen,
750 ifa->ifam_addrs, &addr);
751 myaddr_close_all_open((struct sockaddr *) &addr);
752 break;
753 case RTM_ADD:
754 case RTM_DELETE:
755 case RTM_CHANGE:
756 case RTM_MISS:
757 case RTM_IFINFO:
758 #ifdef RTM_OIFINFO
759 case RTM_OIFINFO:
760 #endif
761 #ifdef RTM_NEWMADDR
762 case RTM_NEWMADDR:
763 case RTM_DELMADDR:
764 #endif
765 #ifdef RTM_IFANNOUNCE
766 case RTM_IFANNOUNCE:
767 #endif
768 break;
769 default:
770 plog(LLV_WARNING, LOCATION, NULL,
771 "unrecognized route message with rtm_type: %d",
772 rtm->rtm_type);
773 break;
774 }
775 }
776
777 static int
kernel_receive(ctx,fd)778 kernel_receive(ctx, fd)
779 void *ctx;
780 int fd;
781 {
782 char buf[16*1024];
783 struct rt_msghdr *rtm = (struct rt_msghdr *) buf;
784 int len;
785
786 len = read(fd, &buf, sizeof(buf));
787 if (len <= 0) {
788 if (len < 0 && errno != EWOULDBLOCK && errno != EAGAIN)
789 plog(LLV_WARNING, LOCATION, NULL,
790 "routing socket error: %s", strerror(errno));
791 return FALSE;
792 }
793
794 if (rtm->rtm_msglen != len) {
795 plog(LLV_WARNING, LOCATION, NULL,
796 "kernel_receive: rtm->rtm_msglen %d, len %d, type %d\n",
797 rtm->rtm_msglen, len, rtm->rtm_type);
798 return FALSE;
799 }
800
801 kernel_handle_message(buf);
802 return TRUE;
803 }
804
805 static int
kernel_open_socket()806 kernel_open_socket()
807 {
808 int fd;
809
810 fd = socket(PF_ROUTE, SOCK_RAW, 0);
811 if (fd < 0) {
812 plog(LLV_ERROR, LOCATION, NULL,
813 "socket(PF_ROUTE) failed: %s",
814 strerror(errno));
815 return -1;
816 }
817 close_on_exec(fd);
818 if (fcntl(fd, F_SETFL, O_NONBLOCK) == -1)
819 plog(LLV_WARNING, LOCATION, NULL,
820 "failed to put socket in non-blocking mode\n");
821
822 return fd;
823 }
824
825 static void
kernel_sync()826 kernel_sync()
827 {
828 caddr_t ref, buf, end;
829 size_t bufsiz;
830 struct if_msghdr *ifm;
831 struct interface *ifp;
832
833 #define MIBSIZ 6
834 int mib[MIBSIZ] = {
835 CTL_NET,
836 PF_ROUTE,
837 0,
838 0, /* AF_INET & AF_INET6 */
839 NET_RT_IFLIST,
840 0
841 };
842
843 if (sysctl(mib, MIBSIZ, NULL, &bufsiz, NULL, 0) < 0) {
844 plog(LLV_WARNING, LOCATION, NULL,
845 "sysctl() error: %s", strerror(errno));
846 return;
847 }
848
849 ref = buf = racoon_malloc(bufsiz);
850
851 if (sysctl(mib, MIBSIZ, buf, &bufsiz, NULL, 0) >= 0) {
852 /* Parse both interfaces and addresses. */
853 for (end = buf + bufsiz; buf < end; buf += ifm->ifm_msglen) {
854 ifm = (struct if_msghdr *) buf;
855 kernel_handle_message(buf);
856 }
857 } else {
858 plog(LLV_WARNING, LOCATION, NULL,
859 "sysctl() error: %s", strerror(errno));
860 }
861
862 racoon_free(ref);
863 }
864
865 #else
866
867 #error No supported interface to monitor local addresses.
868
869 #endif
870