]> git.saurik.com Git - apple/ipsec.git/blob - ipsec-tools/racoon/grabmyaddr.c
ipsec-317.220.1.tar.gz
[apple/ipsec.git] / ipsec-tools / racoon / grabmyaddr.c
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>
40 #include <net/if_var.h>
41 #include <netinet/in.h>
42 #include <netinet6/in6_var.h>
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
57 #include <fcntl.h>
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
74 #ifndef HAVE_GETIFADDRS
75 static unsigned int if_maxindex (void);
76 #endif
77
78 static int suitable_ifaddr (const char *, const struct sockaddr *);
79 #ifdef INET6
80 static int suitable_ifaddr6 (const char *, const struct sockaddr *);
81 #endif
82
83 #ifndef HAVE_GETIFADDRS
84 static unsigned int
85 if_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
101 void
102 clear_myaddr()
103 {
104 struct myaddrs *p, *next;
105
106 for (p = lcconf->myaddrs; p; p = next) {
107 next = p->next;
108
109 delmyaddr(p);
110 }
111
112 lcconf->myaddrs = NULL;
113
114 }
115
116
117 struct myaddrs *
118 find_myaddr(addr, udp_encap)
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
129 for (q = lcconf->myaddrs; q; q = q->next) {
130 if (!q->addr)
131 continue;
132 if ((q->udp_encap && !udp_encap)
133 || (!q->udp_encap && udp_encap))
134 continue;
135 if (addr->sa_family != q->addr->ss_family)
136 continue;
137 if (getnameinfo((struct sockaddr *)q->addr, sysdep_sa_len((struct sockaddr *)q->addr), h2, sizeof(h2),
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.
152 void
153 grab_myaddrs()
154 {
155 struct myaddrs *p, *q;
156 struct ifaddrs *ifa0, *ifap;
157
158 char addr1[NI_MAXHOST];
159
160 if (getifaddrs(&ifa0)) {
161 plog(ASL_LEVEL_ERR,
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)) {
181 plog(ASL_LEVEL_DEBUG,
182 "unsuitable address: %s %s\n",
183 ifap->ifa_name,
184 saddrwop2str(ifap->ifa_addr));
185 continue;
186 }
187
188 p = find_myaddr(ifap->ifa_addr, 0);
189 if (p) {
190 p->in_use = 1;
191 #ifdef ENABLE_NATT
192 q = find_myaddr(ifap->ifa_addr, 1);
193 if (q)
194 q->in_use = 1;
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 }
204 #endif
205 } else {
206 p = newmyaddr();
207 if (p == NULL) {
208 plog(ASL_LEVEL_ERR,
209 "unable to allocate space for addr.\n");
210 exit(1);
211 /*NOTREACHED*/
212 }
213 p->addr = dupsaddr(ALIGNED_CAST(struct sockaddr_storage*)ifap->ifa_addr);
214 if (p->addr == NULL) {
215 plog(ASL_LEVEL_ERR,
216 "unable to duplicate addr.\n");
217 exit(1);
218 /*NOTREACHED*/
219 }
220 p->ifname = racoon_strdup(ifap->ifa_name);
221 if (p->ifname == NULL) {
222 plog(ASL_LEVEL_ERR,
223 "unable to duplicate ifname.\n");
224 exit(1);
225 /*NOTREACHED*/
226 }
227 p->in_use = 1;
228
229 if (getnameinfo((struct sockaddr *)p->addr, p->addr->ss_len,
230 addr1, sizeof(addr1),
231 NULL, 0,
232 NI_NUMERICHOST | niflags))
233 strlcpy(addr1, "(invalid)", sizeof(addr1));
234 plog(ASL_LEVEL_DEBUG,
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) {
245 plog(ASL_LEVEL_ERR,
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);
257 }
258
259
260 /*
261 * check the interface is suitable or not
262 */
263 static int
264 suitable_ifaddr(ifname, ifaddr)
265 const char *ifname;
266 const struct sockaddr *ifaddr;
267 {
268 #if 0 //we need to be able to do nested ipsec for BTMM... stub out ifdef ENABLE_HYBRID
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
287 static int
288 suitable_ifaddr6(ifname, ifaddr)
289 const char *ifname;
290 const struct sockaddr *ifaddr;
291 {
292 struct in6_ifreq ifr6;
293 int s;
294
295 if (ifaddr->sa_family != AF_INET6)
296 return 0;
297
298 s = socket(PF_INET6, SOCK_DGRAM, 0);
299 if (s == -1) {
300 plog(ASL_LEVEL_ERR,
301 "socket(SOCK_DGRAM) failed:%s\n", strerror(errno));
302 return 0;
303 }
304
305 if (fcntl(s, F_SETFL, O_NONBLOCK) == -1) {
306 plog(ASL_LEVEL_ERR, "failed to put IPv6 socket in non-blocking mode\n");
307 }
308
309 memset(&ifr6, 0, sizeof(ifr6));
310 strlcpy(ifr6.ifr_name, ifname, sizeof(ifr6.ifr_name));
311
312 memcpy(&ifr6.ifr_addr, ifaddr, sizeof(struct sockaddr_in6)); // Wcast-align fix - copy instread of assign with cast
313
314 if (ioctl(s, SIOCGIFAFLAG_IN6, &ifr6) < 0) {
315 plog(ASL_LEVEL_ERR,
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
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)
328 return 0;
329
330 /* suitable */
331 return 1;
332 }
333 #endif
334
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 */
344 int
345 autoconf_myaddrsport()
346 {
347 struct myaddrs *p;
348 int n;
349
350 plog(ASL_LEVEL_DEBUG,
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 }
356 plog(ASL_LEVEL_DEBUG,
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 */
366 u_short
367 getmyaddrsport(local)
368 struct sockaddr_storage *local;
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
383 switch (p->addr->ss_family) {
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:
401 plog(ASL_LEVEL_ERR,
402 "unsupported AF %d\n", p->addr->ss_family);
403 continue;
404 }
405 }
406 }
407
408 return htons(bestmatch_port);
409 }
410
411 struct myaddrs *
412 newmyaddr()
413 {
414 struct myaddrs *new;
415
416 new = racoon_calloc(1, sizeof(*new));
417 if (new == NULL) {
418 plog(ASL_LEVEL_ERR,
419 "failed to allocate buffer for myaddrs.\n");
420 return NULL;
421 }
422
423 new->next = NULL;
424 new->addr = NULL;
425 new->source = NULL;
426 new->sock = -1;
427 #ifdef __APPLE_
428 new->ifname = NULL;
429 #endif
430
431 return new;
432 }
433
434 struct myaddrs *
435 dupmyaddr(struct myaddrs *old)
436 {
437 struct myaddrs *new;
438
439 new = racoon_calloc(1, sizeof(*new));
440 if (new == NULL) {
441 plog(ASL_LEVEL_ERR,
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));
448 new->addr = dupsaddr (old->addr);
449 if (new->addr == NULL) {
450 plog(ASL_LEVEL_ERR,
451 "failed to allocate buffer for duplicate addr.\n");
452 racoon_free(new);
453 return NULL;
454 }
455 if (old->ifname) {
456 new->ifname = racoon_strdup(old->ifname);
457 if (new->ifname == NULL) {
458 plog(ASL_LEVEL_ERR,
459 "failed to allocate buffer for duplicate ifname.\n");
460 racoon_free(new->addr);
461 racoon_free(new);
462 return NULL;
463 }
464 }
465 new->source = NULL;
466 new->sock = -1;
467
468 new->next = old->next;
469 old->next = new;
470
471 return new;
472 }
473
474 void
475 insmyaddr(new, head)
476 struct myaddrs *new;
477 struct myaddrs **head;
478 {
479 new->next = *head;
480 *head = new;
481 }
482
483 void
484 delmyaddr(myaddr)
485 struct myaddrs *myaddr;
486 {
487 if (myaddr->addr)
488 racoon_free(myaddr->addr);
489 if (myaddr->ifname)
490 racoon_free(myaddr->ifname);
491 racoon_free(myaddr);
492 }
493
494 void
495 update_myaddrs(void *unused)
496 {
497 grab_myaddrs();
498 isakmp_close_unused();
499 autoconf_myaddrsport();
500 isakmp_open();
501 }
502
503
504 int
505 initmyaddr(void)
506 {
507
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
518
519 /* select the socket to be sent */
520 /* should implement other method. */
521 int
522 getsockmyaddr(struct sockaddr *my)
523 {
524 struct myaddrs *p, *lastresort = NULL;
525
526 for (p = lcconf->myaddrs; p; p = p->next) {
527 if (p->addr == NULL)
528 continue;
529 if (my->sa_family == p->addr->ss_family) {
530 lastresort = p;
531 } else continue;
532 if (sysdep_sa_len(my) == sysdep_sa_len((struct sockaddr *)p->addr)
533 && memcmp(my, p->addr, sysdep_sa_len(my)) == 0) {
534 break;
535 }
536 }
537 if (!p)
538 p = lastresort;
539 if (!p) {
540 plog(ASL_LEVEL_ERR,
541 "no socket matches address family %d\n",
542 my->sa_family);
543 return -1;
544 }
545
546 return p->sock;
547 }
548
549 void
550 pfroute_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
597 void
598 pfroute_close(void)
599 {
600
601 dispatch_source_cancel(lcconf->rt_source);
602 lcconf->rt_source = NULL;
603 }
604
605 int
606 pfroute_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