Annotation of embedaddon/ipsec-tools/src/racoon/grabmyaddr.c, revision 1.1.1.1
1.1 misho 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:
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
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
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
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
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
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
210: myaddr_flush()
211: {
212: myaddr_flush_list(&configured);
213: }
214:
215: int
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
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
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
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
287: myaddr_init_lists()
288: {
289: LIST_INIT(&configured);
290: LIST_INIT(&opened);
291: }
292:
293: int
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>