]> git.saurik.com Git - apple/ipsec.git/blame - ipsec-tools/racoon/grabmyaddr.c
ipsec-317.220.1.tar.gz
[apple/ipsec.git] / ipsec-tools / racoon / grabmyaddr.c
CommitLineData
52b7d2ce
A
1/* $Id: grabmyaddr.c,v 1.23.4.2 2005/07/16 04:41:01 monas Exp $ */
2
3/*
4 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
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 <sys/types.h>
35#include <sys/param.h>
36#include <sys/socket.h>
37#include <sys/ioctl.h>
38
39#include <net/if.h>
52b7d2ce 40#include <net/if_var.h>
52b7d2ce
A
41#include <netinet/in.h>
42#include <netinet6/in6_var.h>
52b7d2ce
A
43#include <net/route.h>
44
45#include <stdlib.h>
46#include <stdio.h>
47#include <string.h>
48#include <errno.h>
49#ifdef HAVE_UNISTD_H
50#include <unistd.h>
51#endif
52#include <netdb.h>
53#ifdef HAVE_GETIFADDRS
54#include <ifaddrs.h>
55#include <net/if.h>
56#endif
85f41bec 57#include <fcntl.h>
52b7d2ce
A
58
59#include "var.h"
60#include "misc.h"
61#include "vmbuf.h"
62#include "plog.h"
63#include "sockmisc.h"
64#include "debug.h"
65
66#include "localconf.h"
67#include "handler.h"
68#include "grabmyaddr.h"
69#include "sockmisc.h"
70#include "isakmp_var.h"
71#include "gcmalloc.h"
72#include "nattraversal.h"
73
52b7d2ce 74#ifndef HAVE_GETIFADDRS
65c25746 75static unsigned int if_maxindex (void);
52b7d2ce 76#endif
d1e348cf 77
65c25746 78static int suitable_ifaddr (const char *, const struct sockaddr *);
52b7d2ce 79#ifdef INET6
65c25746 80static int suitable_ifaddr6 (const char *, const struct sockaddr *);
52b7d2ce
A
81#endif
82
52b7d2ce
A
83#ifndef HAVE_GETIFADDRS
84static unsigned int
85if_maxindex()
86{
87 struct if_nameindex *p, *p0;
88 unsigned int max = 0;
89
90 p0 = if_nameindex();
91 for (p = p0; p && p->if_index && p->if_name; p++) {
92 if (max < p->if_index)
93 max = p->if_index;
94 }
95 if_freenameindex(p0);
96 return max;
97}
98#endif
99
100
101void
102clear_myaddr()
103{
104 struct myaddrs *p, *next;
105
106 for (p = lcconf->myaddrs; p; p = next) {
107 next = p->next;
108
d1e348cf 109 delmyaddr(p);
52b7d2ce
A
110 }
111
112 lcconf->myaddrs = NULL;
113
114}
115
116
d1e348cf
A
117struct myaddrs *
118find_myaddr(addr, udp_encap)
52b7d2ce
A
119 struct sockaddr *addr;
120 int udp_encap;
121{
122 struct myaddrs *q;
123 char h1[NI_MAXHOST], h2[NI_MAXHOST];
124
125 if (getnameinfo(addr, sysdep_sa_len(addr), h1, sizeof(h1), NULL, 0,
126 NI_NUMERICHOST | niflags) != 0)
127 return NULL;
128
d1e348cf 129 for (q = lcconf->myaddrs; q; q = q->next) {
52b7d2ce
A
130 if (!q->addr)
131 continue;
65c25746
A
132 if ((q->udp_encap && !udp_encap)
133 || (!q->udp_encap && udp_encap))
52b7d2ce 134 continue;
85f41bec 135 if (addr->sa_family != q->addr->ss_family)
52b7d2ce 136 continue;
85f41bec 137 if (getnameinfo((struct sockaddr *)q->addr, sysdep_sa_len((struct sockaddr *)q->addr), h2, sizeof(h2),
52b7d2ce
A
138 NULL, 0, NI_NUMERICHOST | niflags) != 0)
139 return NULL;
140 if (strcmp(h1, h2) == 0)
141 return q;
142 }
143
144 return NULL;
145}
146
147
148// modified to avoid closing and opening sockets for
149// all interfaces each time an interface change occurs.
150// on return: addrcount = zero indicates address no longer used
151// sock = -1 indicates a new address - no socket opened yet.
152void
153grab_myaddrs()
154{
52b7d2ce
A
155 struct myaddrs *p, *q;
156 struct ifaddrs *ifa0, *ifap;
52b7d2ce
A
157
158 char addr1[NI_MAXHOST];
159
160 if (getifaddrs(&ifa0)) {
65c25746 161 plog(ASL_LEVEL_ERR,
52b7d2ce
A
162 "getifaddrs failed: %s\n", strerror(errno));
163 exit(1);
164 /*NOTREACHED*/
165 }
166
167 // clear the in_use flag for each address in the list
168 for (p = lcconf->myaddrs; p; p = p->next)
169 p->in_use = 0;
170
171 for (ifap = ifa0; ifap; ifap = ifap->ifa_next) {
172
173 if (ifap->ifa_addr->sa_family != AF_INET
174#ifdef INET6
175 && ifap->ifa_addr->sa_family != AF_INET6
176#endif
177 )
178 continue;
179
180 if (!suitable_ifaddr(ifap->ifa_name, ifap->ifa_addr)) {
65c25746 181 plog(ASL_LEVEL_DEBUG,
52b7d2ce
A
182 "unsuitable address: %s %s\n",
183 ifap->ifa_name,
184 saddrwop2str(ifap->ifa_addr));
185 continue;
186 }
187
d1e348cf 188 p = find_myaddr(ifap->ifa_addr, 0);
52b7d2ce
A
189 if (p) {
190 p->in_use = 1;
191#ifdef ENABLE_NATT
d1e348cf 192 q = find_myaddr(ifap->ifa_addr, 1);
52b7d2ce
A
193 if (q)
194 q->in_use = 1;
65c25746
A
195 else if (natt_enabled_in_rmconf ()) {
196 q = dupmyaddr(p);
197 if (q == NULL) {
198 plog(ASL_LEVEL_ERR,
199 "unable to allocate space for natt addr.\n");
200 exit(1);
201 }
202 q->udp_encap = 1;
203 }
52b7d2ce
A
204#endif
205 } else {
206 p = newmyaddr();
207 if (p == NULL) {
65c25746 208 plog(ASL_LEVEL_ERR,
52b7d2ce
A
209 "unable to allocate space for addr.\n");
210 exit(1);
211 /*NOTREACHED*/
212 }
65c25746 213 p->addr = dupsaddr(ALIGNED_CAST(struct sockaddr_storage*)ifap->ifa_addr);
52b7d2ce 214 if (p->addr == NULL) {
65c25746 215 plog(ASL_LEVEL_ERR,
52b7d2ce
A
216 "unable to duplicate addr.\n");
217 exit(1);
218 /*NOTREACHED*/
219 }
d1e348cf
A
220 p->ifname = racoon_strdup(ifap->ifa_name);
221 if (p->ifname == NULL) {
65c25746 222 plog(ASL_LEVEL_ERR,
d1e348cf
A
223 "unable to duplicate ifname.\n");
224 exit(1);
225 /*NOTREACHED*/
65c25746 226 }
52b7d2ce
A
227 p->in_use = 1;
228
85f41bec 229 if (getnameinfo((struct sockaddr *)p->addr, p->addr->ss_len,
52b7d2ce
A
230 addr1, sizeof(addr1),
231 NULL, 0,
232 NI_NUMERICHOST | niflags))
233 strlcpy(addr1, "(invalid)", sizeof(addr1));
65c25746 234 plog(ASL_LEVEL_DEBUG,
52b7d2ce
A
235 "my interface: %s (%s)\n",
236 addr1, ifap->ifa_name);
237
238 p->next = lcconf->myaddrs;
239 lcconf->myaddrs = p;
240
241#ifdef ENABLE_NATT
242 if (natt_enabled_in_rmconf ()) {
243 q = dupmyaddr(p);
244 if (q == NULL) {
65c25746 245 plog(ASL_LEVEL_ERR,
52b7d2ce
A
246 "unable to allocate space for natt addr.\n");
247 exit(1);
248 }
249 q->udp_encap = 1;
250 }
251#endif
252
253 }
254 }
255
256 freeifaddrs(ifa0);
52b7d2ce
A
257}
258
259
260/*
261 * check the interface is suitable or not
262 */
263static int
264suitable_ifaddr(ifname, ifaddr)
265 const char *ifname;
266 const struct sockaddr *ifaddr;
267{
e8d9021d 268#if 0 //we need to be able to do nested ipsec for BTMM... stub out ifdef ENABLE_HYBRID
52b7d2ce
A
269 /* Exclude any address we got through ISAKMP mode config */
270 if (exclude_cfg_addr(ifaddr) == 0)
271 return 0;
272#endif
273 switch(ifaddr->sa_family) {
274 case AF_INET:
275 return 1;
276#ifdef INET6
277 case AF_INET6:
278 return suitable_ifaddr6(ifname, ifaddr);
279#endif
280 default:
281 return 0;
282 }
283 /*NOTREACHED*/
284}
285
286#ifdef INET6
287static int
288suitable_ifaddr6(ifname, ifaddr)
289 const char *ifname;
290 const struct sockaddr *ifaddr;
291{
52b7d2ce
A
292 struct in6_ifreq ifr6;
293 int s;
52b7d2ce
A
294
295 if (ifaddr->sa_family != AF_INET6)
296 return 0;
297
52b7d2ce
A
298 s = socket(PF_INET6, SOCK_DGRAM, 0);
299 if (s == -1) {
65c25746 300 plog(ASL_LEVEL_ERR,
52b7d2ce
A
301 "socket(SOCK_DGRAM) failed:%s\n", strerror(errno));
302 return 0;
303 }
304
65c25746
A
305 if (fcntl(s, F_SETFL, O_NONBLOCK) == -1) {
306 plog(ASL_LEVEL_ERR, "failed to put IPv6 socket in non-blocking mode\n");
85f41bec
A
307 }
308
52b7d2ce 309 memset(&ifr6, 0, sizeof(ifr6));
d1e348cf 310 strlcpy(ifr6.ifr_name, ifname, sizeof(ifr6.ifr_name));
52b7d2ce 311
85f41bec 312 memcpy(&ifr6.ifr_addr, ifaddr, sizeof(struct sockaddr_in6)); // Wcast-align fix - copy instread of assign with cast
52b7d2ce
A
313
314 if (ioctl(s, SIOCGIFAFLAG_IN6, &ifr6) < 0) {
65c25746 315 plog(ASL_LEVEL_ERR,
52b7d2ce
A
316 "ioctl(SIOCGIFAFLAG_IN6) failed:%s\n", strerror(errno));
317 close(s);
318 return 0;
319 }
320
321 close(s);
322
323 if (ifr6.ifr_ifru.ifru_flags6 & IN6_IFF_DUPLICATED
324 || ifr6.ifr_ifru.ifru_flags6 & IN6_IFF_DETACHED
65c25746
A
325 || ifr6.ifr_ifru.ifru_flags6 & IN6_IFF_ANYCAST
326 /* Deprecated addresses will now be dropped by isakmp_close_unused */
327 || ifr6.ifr_ifru.ifru_flags6 & IN6_IFF_DEPRECATED)
52b7d2ce 328 return 0;
52b7d2ce
A
329
330 /* suitable */
331 return 1;
332}
333#endif
334
52b7d2ce
A
335
336/*
337 * initialize default port for ISAKMP to send, if no "listen"
338 * directive is specified in config file.
339 *
340 * DO NOT listen to wildcard addresses. if you receive packets to
341 * wildcard address, you'll be in trouble (DoS attack possible by
342 * broadcast storm).
343 */
344int
345autoconf_myaddrsport()
346{
347 struct myaddrs *p;
348 int n;
349
65c25746 350 plog(ASL_LEVEL_DEBUG,
52b7d2ce
A
351 "configuring default isakmp port.\n");
352
353 for (p = lcconf->myaddrs, n = 0; p; p = p->next, n++) {
354 set_port (p->addr, p->udp_encap ? lcconf->port_isakmp_natt : lcconf->port_isakmp);
355 }
65c25746 356 plog(ASL_LEVEL_DEBUG,
52b7d2ce
A
357 "%d addrs are configured successfully\n", n);
358
359 return 0;
360}
361
362/*
363 * get a port number to which racoon binded.
364 * NOTE: network byte order returned.
365 */
366u_short
367getmyaddrsport(local)
85f41bec 368 struct sockaddr_storage *local;
52b7d2ce
A
369{
370 struct myaddrs *p, *bestmatch = NULL;
371 u_short bestmatch_port = PORT_ISAKMP;
372
373 /* get a relative port */
374 for (p = lcconf->myaddrs; p; p = p->next) {
375 if (!p->addr)
376 continue;
377 if (!cmpsaddrwop(local, p->addr)) {
378 if (! bestmatch) {
379 bestmatch = p;
380 continue;
381 }
382
85f41bec 383 switch (p->addr->ss_family) {
52b7d2ce
A
384 case AF_INET:
385 if (((struct sockaddr_in *)p->addr)->sin_port == PORT_ISAKMP) {
386 bestmatch = p;
387 bestmatch_port = ((struct sockaddr_in *)p->addr)->sin_port;
388 break;
389 }
390 break;
391#ifdef INET6
392 case AF_INET6:
393 if (((struct sockaddr_in6 *)p->addr)->sin6_port == PORT_ISAKMP) {
394 bestmatch = p;
395 bestmatch_port = ((struct sockaddr_in6 *)p->addr)->sin6_port;
396 break;
397 }
398 break;
399#endif
400 default:
65c25746 401 plog(ASL_LEVEL_ERR,
85f41bec 402 "unsupported AF %d\n", p->addr->ss_family);
52b7d2ce
A
403 continue;
404 }
405 }
406 }
407
408 return htons(bestmatch_port);
409}
410
411struct myaddrs *
412newmyaddr()
413{
414 struct myaddrs *new;
415
416 new = racoon_calloc(1, sizeof(*new));
417 if (new == NULL) {
65c25746 418 plog(ASL_LEVEL_ERR,
52b7d2ce
A
419 "failed to allocate buffer for myaddrs.\n");
420 return NULL;
421 }
422
423 new->next = NULL;
424 new->addr = NULL;
65c25746
A
425 new->source = NULL;
426 new->sock = -1;
d1e348cf
A
427#ifdef __APPLE_
428 new->ifname = NULL;
429#endif
52b7d2ce
A
430
431 return new;
432}
433
434struct myaddrs *
435dupmyaddr(struct myaddrs *old)
436{
437 struct myaddrs *new;
438
439 new = racoon_calloc(1, sizeof(*new));
440 if (new == NULL) {
65c25746 441 plog(ASL_LEVEL_ERR,
52b7d2ce
A
442 "failed to allocate buffer for myaddrs.\n");
443 return NULL;
444 }
445
446 /* Copy the whole structure and set the differences. */
447 memcpy (new, old, sizeof (*new));
65c25746 448 new->addr = dupsaddr (old->addr);
52b7d2ce 449 if (new->addr == NULL) {
65c25746 450 plog(ASL_LEVEL_ERR,
52b7d2ce
A
451 "failed to allocate buffer for duplicate addr.\n");
452 racoon_free(new);
453 return NULL;
454 }
d1e348cf
A
455 if (old->ifname) {
456 new->ifname = racoon_strdup(old->ifname);
457 if (new->ifname == NULL) {
65c25746 458 plog(ASL_LEVEL_ERR,
d1e348cf
A
459 "failed to allocate buffer for duplicate ifname.\n");
460 racoon_free(new->addr);
461 racoon_free(new);
462 return NULL;
463 }
464 }
65c25746
A
465 new->source = NULL;
466 new->sock = -1;
467
52b7d2ce
A
468 new->next = old->next;
469 old->next = new;
470
471 return new;
472}
473
474void
475insmyaddr(new, head)
476 struct myaddrs *new;
477 struct myaddrs **head;
478{
479 new->next = *head;
480 *head = new;
481}
482
483void
484delmyaddr(myaddr)
485 struct myaddrs *myaddr;
486{
487 if (myaddr->addr)
488 racoon_free(myaddr->addr);
d1e348cf
A
489 if (myaddr->ifname)
490 racoon_free(myaddr->ifname);
52b7d2ce
A
491 racoon_free(myaddr);
492}
493
65c25746
A
494void
495update_myaddrs(void *unused)
496{
497 grab_myaddrs();
498 isakmp_close_unused();
499 autoconf_myaddrsport();
500 isakmp_open();
65c25746
A
501}
502
503
52b7d2ce 504int
65c25746 505initmyaddr(void)
52b7d2ce 506{
52b7d2ce 507
52b7d2ce
A
508 if (lcconf->myaddrs == NULL && lcconf->autograbaddr == 1) {
509 grab_myaddrs();
510
511 if (autoconf_myaddrsport() < 0)
512 return -1;
513 }
514
515 return 0;
516}
517
65c25746 518
52b7d2ce
A
519/* select the socket to be sent */
520/* should implement other method. */
521int
65c25746 522getsockmyaddr(struct sockaddr *my)
52b7d2ce
A
523{
524 struct myaddrs *p, *lastresort = NULL;
52b7d2ce
A
525
526 for (p = lcconf->myaddrs; p; p = p->next) {
527 if (p->addr == NULL)
528 continue;
85f41bec 529 if (my->sa_family == p->addr->ss_family) {
52b7d2ce
A
530 lastresort = p;
531 } else continue;
85f41bec 532 if (sysdep_sa_len(my) == sysdep_sa_len((struct sockaddr *)p->addr)
52b7d2ce
A
533 && memcmp(my, p->addr, sysdep_sa_len(my)) == 0) {
534 break;
535 }
52b7d2ce 536 }
52b7d2ce
A
537 if (!p)
538 p = lastresort;
539 if (!p) {
65c25746 540 plog(ASL_LEVEL_ERR,
52b7d2ce
A
541 "no socket matches address family %d\n",
542 my->sa_family);
543 return -1;
544 }
545
546 return p->sock;
547}
65c25746
A
548
549void
550pfroute_handler(void *unused)
551{
552
553 struct rtmessage { // Wcast-align fix - force alignment
554 struct rt_msghdr rtm;
555 char discard[BUFSIZ];
556 } msg;
557
558 int len;
559
560 while((len = read(lcconf->rtsock, &msg, sizeof(msg))) < 0) {
561 if (errno == EINTR)
562 continue;
563 plog(ASL_LEVEL_DEBUG,
564 "read(PF_ROUTE) failed: %s\n",
565 strerror(errno));
566 return;
567 }
568 if (len < msg.rtm.rtm_msglen) {
569 plog(ASL_LEVEL_DEBUG,
570 "read(PF_ROUTE) short read\n");
571 return;
572 }
573 switch (msg.rtm.rtm_type) {
574 case RTM_NEWADDR:
575 case RTM_DELADDR:
576 case RTM_DELETE:
577 case RTM_IFINFO:
578 break;
579 case RTM_MISS:
580 /* ignore this message silently */
581 return;
582 default:
583 //plog(ASL_LEVEL_DEBUG,
584 // "msg %d not interesting\n", msg.rtm.rtm_type);
585 return;
586 }
587 /* XXX more filters here? */
588
589 plog(ASL_LEVEL_DEBUG,
590 "caught rtm:%d, need update interface address list\n",
591 msg.rtm.rtm_type);
592
593 // Interface changes occurred - update addrs
594 update_myaddrs(NULL);
595}
596
597void
598pfroute_close(void)
599{
600
601 dispatch_source_cancel(lcconf->rt_source);
602 lcconf->rt_source = NULL;
603}
604
605int
606pfroute_init(void)
607{
608 int sock;
609
610 /* initialize routing socket */
611 lcconf->rtsock = socket(PF_ROUTE, SOCK_RAW, PF_UNSPEC);
612 if (lcconf->rtsock < 0) {
613 plog(ASL_LEVEL_DEBUG,
614 "socket(PF_ROUTE) failed: %s",
615 strerror(errno));
616 return -1;
617 }
618 if (fcntl(lcconf->rtsock, F_SETFL, O_NONBLOCK) == -1) {
619 plog(ASL_LEVEL_DEBUG, "failed to put PF_ROUTE socket in non-blocking mode\n");
620 }
621
622 lcconf->rt_source = dispatch_source_create(DISPATCH_SOURCE_TYPE_READ, lcconf->rtsock, 0, dispatch_get_main_queue());
623 if (lcconf->rt_source == NULL) {
624 plog(ASL_LEVEL_DEBUG, "could not create pfroute socket source.");
625 return -1;
626 }
627 dispatch_source_set_event_handler_f(lcconf->rt_source, pfroute_handler);
628 sock = lcconf->rtsock;
629 dispatch_source_set_cancel_handler(lcconf->rt_source,
630 ^{
631 close(sock);
632 });
633 dispatch_resume(lcconf->rt_source);
634 return 0;
635}
636
637
638