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