]> git.saurik.com Git - apple/ipsec.git/blob - ipsec-tools/racoon/grabmyaddr.c
ipsec-164.10.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 __P((void));
76 #endif
77
78 static int suitable_ifaddr __P((const char *, const struct sockaddr *));
79 #ifdef INET6
80 static int suitable_ifaddr6 __P((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 #ifdef HAVE_GETIFADDRS
156 struct myaddrs *p, *q;
157 struct ifaddrs *ifa0, *ifap;
158
159 char addr1[NI_MAXHOST];
160
161 if (getifaddrs(&ifa0)) {
162 plog(LLV_ERROR2, LOCATION, NULL,
163 "getifaddrs failed: %s\n", strerror(errno));
164 exit(1);
165 /*NOTREACHED*/
166 }
167
168 // clear the in_use flag for each address in the list
169 for (p = lcconf->myaddrs; p; p = p->next)
170 p->in_use = 0;
171
172 for (ifap = ifa0; ifap; ifap = ifap->ifa_next) {
173
174 if (ifap->ifa_addr->sa_family != AF_INET
175 #ifdef INET6
176 && ifap->ifa_addr->sa_family != AF_INET6
177 #endif
178 )
179 continue;
180
181 if (!suitable_ifaddr(ifap->ifa_name, ifap->ifa_addr)) {
182 plog(LLV_DEBUG2, LOCATION, NULL,
183 "unsuitable address: %s %s\n",
184 ifap->ifa_name,
185 saddrwop2str(ifap->ifa_addr));
186 continue;
187 }
188
189 p = find_myaddr(ifap->ifa_addr, 0);
190 if (p) {
191 p->in_use = 1;
192 #ifdef ENABLE_NATT
193 q = find_myaddr(ifap->ifa_addr, 1);
194 if (q)
195 q->in_use = 1;
196 #endif
197 } else {
198 p = newmyaddr();
199 if (p == NULL) {
200 plog(LLV_ERROR2, LOCATION, NULL,
201 "unable to allocate space for addr.\n");
202 exit(1);
203 /*NOTREACHED*/
204 }
205 p->addr = dupsaddr(ifap->ifa_addr);
206 if (p->addr == NULL) {
207 plog(LLV_ERROR2, LOCATION, NULL,
208 "unable to duplicate addr.\n");
209 exit(1);
210 /*NOTREACHED*/
211 }
212 p->ifname = racoon_strdup(ifap->ifa_name);
213 if (p->ifname == NULL) {
214 plog(LLV_ERROR2, LOCATION, NULL,
215 "unable to duplicate ifname.\n");
216 exit(1);
217 /*NOTREACHED*/
218 }
219
220 p->sock = -1;
221 p->in_use = 1;
222
223 if (getnameinfo((struct sockaddr *)p->addr, p->addr->ss_len,
224 addr1, sizeof(addr1),
225 NULL, 0,
226 NI_NUMERICHOST | niflags))
227 strlcpy(addr1, "(invalid)", sizeof(addr1));
228 plog(LLV_DEBUG, LOCATION, NULL,
229 "my interface: %s (%s)\n",
230 addr1, ifap->ifa_name);
231
232 p->next = lcconf->myaddrs;
233 lcconf->myaddrs = p;
234
235 #ifdef ENABLE_NATT
236 if (natt_enabled_in_rmconf ()) {
237 q = dupmyaddr(p);
238 if (q == NULL) {
239 plog(LLV_ERROR2, LOCATION, NULL,
240 "unable to allocate space for natt addr.\n");
241 exit(1);
242 }
243 q->udp_encap = 1;
244 }
245 #endif
246
247 }
248 }
249
250 freeifaddrs(ifa0);
251
252
253 #else /*!HAVE_GETIFADDRS*/
254 #error "NOT SUPPORTED"
255 #endif /*HAVE_GETIFADDRS*/
256 }
257
258
259 /*
260 * check the interface is suitable or not
261 */
262 static int
263 suitable_ifaddr(ifname, ifaddr)
264 const char *ifname;
265 const struct sockaddr *ifaddr;
266 {
267 #if 0 //we need to be able to do nested ipsec for BTMM... stub out ifdef ENABLE_HYBRID
268 /* Exclude any address we got through ISAKMP mode config */
269 if (exclude_cfg_addr(ifaddr) == 0)
270 return 0;
271 #endif
272 switch(ifaddr->sa_family) {
273 case AF_INET:
274 return 1;
275 #ifdef INET6
276 case AF_INET6:
277 return suitable_ifaddr6(ifname, ifaddr);
278 #endif
279 default:
280 return 0;
281 }
282 /*NOTREACHED*/
283 }
284
285 #ifdef INET6
286 static int
287 suitable_ifaddr6(ifname, ifaddr)
288 const char *ifname;
289 const struct sockaddr *ifaddr;
290 {
291 struct in6_ifreq ifr6;
292 int s;
293
294 if (ifaddr->sa_family != AF_INET6)
295 return 0;
296
297 s = socket(PF_INET6, SOCK_DGRAM, 0);
298 if (s == -1) {
299 plog(LLV_ERROR, LOCATION, NULL,
300 "socket(SOCK_DGRAM) failed:%s\n", strerror(errno));
301 return 0;
302 }
303
304 if (fcntl(s, F_SETFL, O_NONBLOCK) == -1) {
305 plog(LLV_ERROR, LOCATION, NULL,
306 "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(LLV_ERROR, LOCATION, NULL,
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 return 0;
327
328 /* suitable */
329 return 1;
330 }
331 #endif
332
333 int
334 update_myaddrs()
335 {
336 struct rtmessage { // Wcast-align fix - force alignment
337 struct rt_msghdr rtm;
338 char discard[BUFSIZ];
339 } msg;
340
341 int len;
342
343 while((len = read(lcconf->rtsock, &msg, sizeof(msg))) < 0) {
344 if (errno == EINTR)
345 continue;
346 plog(LLV_ERROR, LOCATION, NULL,
347 "read(PF_ROUTE) failed: %s\n",
348 strerror(errno));
349 return 0;
350 }
351 if (len < msg.rtm.rtm_msglen) {
352 plog(LLV_ERROR, LOCATION, NULL,
353 "read(PF_ROUTE) short read\n");
354 return 0;
355 }
356 if (msg.rtm.rtm_version != RTM_VERSION) {
357 plog(LLV_ERROR, LOCATION, NULL,
358 "routing socket version mismatch\n");
359 close(lcconf->rtsock);
360 lcconf->rtsock = -1;
361 return 0;
362 }
363 switch (msg.rtm.rtm_type) {
364 case RTM_NEWADDR:
365 case RTM_DELADDR:
366 case RTM_DELETE:
367 case RTM_IFINFO:
368 break;
369 case RTM_MISS:
370 /* ignore this message silently */
371 return 0;
372 default:
373 //plog(LLV_DEBUG, LOCATION, NULL,
374 // "msg %d not interesting\n", msg.rtm.rtm_type);
375 return 0;
376 }
377 /* XXX more filters here? */
378
379 //plog(LLV_DEBUG, LOCATION, NULL,
380 // "caught rtm:%d, need update interface address list\n",
381 // msg.rtm.rtm_type);
382
383 return 1;
384 }
385
386 /*
387 * initialize default port for ISAKMP to send, if no "listen"
388 * directive is specified in config file.
389 *
390 * DO NOT listen to wildcard addresses. if you receive packets to
391 * wildcard address, you'll be in trouble (DoS attack possible by
392 * broadcast storm).
393 */
394 int
395 autoconf_myaddrsport()
396 {
397 struct myaddrs *p;
398 int n;
399
400 plog(LLV_DEBUG, LOCATION, NULL,
401 "configuring default isakmp port.\n");
402
403 for (p = lcconf->myaddrs, n = 0; p; p = p->next, n++) {
404 set_port (p->addr, p->udp_encap ? lcconf->port_isakmp_natt : lcconf->port_isakmp);
405 }
406 plog(LLV_DEBUG, LOCATION, NULL,
407 "%d addrs are configured successfully\n", n);
408
409 return 0;
410 }
411
412 /*
413 * get a port number to which racoon binded.
414 * NOTE: network byte order returned.
415 */
416 u_short
417 getmyaddrsport(local)
418 struct sockaddr_storage *local;
419 {
420 struct myaddrs *p, *bestmatch = NULL;
421 u_short bestmatch_port = PORT_ISAKMP;
422
423 /* get a relative port */
424 for (p = lcconf->myaddrs; p; p = p->next) {
425 if (!p->addr)
426 continue;
427 if (!cmpsaddrwop(local, p->addr)) {
428 if (! bestmatch) {
429 bestmatch = p;
430 continue;
431 }
432
433 switch (p->addr->ss_family) {
434 case AF_INET:
435 if (((struct sockaddr_in *)p->addr)->sin_port == PORT_ISAKMP) {
436 bestmatch = p;
437 bestmatch_port = ((struct sockaddr_in *)p->addr)->sin_port;
438 break;
439 }
440 break;
441 #ifdef INET6
442 case AF_INET6:
443 if (((struct sockaddr_in6 *)p->addr)->sin6_port == PORT_ISAKMP) {
444 bestmatch = p;
445 bestmatch_port = ((struct sockaddr_in6 *)p->addr)->sin6_port;
446 break;
447 }
448 break;
449 #endif
450 default:
451 plog(LLV_ERROR, LOCATION, NULL,
452 "unsupported AF %d\n", p->addr->ss_family);
453 continue;
454 }
455 }
456 }
457
458 return htons(bestmatch_port);
459 }
460
461 struct myaddrs *
462 newmyaddr()
463 {
464 struct myaddrs *new;
465
466 new = racoon_calloc(1, sizeof(*new));
467 if (new == NULL) {
468 plog(LLV_ERROR, LOCATION, NULL,
469 "failed to allocate buffer for myaddrs.\n");
470 return NULL;
471 }
472
473 new->next = NULL;
474 new->addr = NULL;
475 #ifdef __APPLE_
476 new->ifname = NULL;
477 #endif
478
479 return new;
480 }
481
482 struct myaddrs *
483 dupmyaddr(struct myaddrs *old)
484 {
485 struct myaddrs *new;
486
487 new = racoon_calloc(1, sizeof(*new));
488 if (new == NULL) {
489 plog(LLV_ERROR, LOCATION, NULL,
490 "failed to allocate buffer for myaddrs.\n");
491 return NULL;
492 }
493
494 /* Copy the whole structure and set the differences. */
495 memcpy (new, old, sizeof (*new));
496 new->addr = dupsaddr ((struct sockaddr *)old->addr);
497 if (new->addr == NULL) {
498 plog(LLV_ERROR, LOCATION, NULL,
499 "failed to allocate buffer for duplicate addr.\n");
500 racoon_free(new);
501 return NULL;
502 }
503 if (old->ifname) {
504 new->ifname = racoon_strdup(old->ifname);
505 if (new->ifname == NULL) {
506 plog(LLV_ERROR, LOCATION, NULL,
507 "failed to allocate buffer for duplicate ifname.\n");
508 racoon_free(new->addr);
509 racoon_free(new);
510 return NULL;
511 }
512 }
513
514 new->next = old->next;
515 old->next = new;
516
517 return new;
518 }
519
520 void
521 insmyaddr(new, head)
522 struct myaddrs *new;
523 struct myaddrs **head;
524 {
525 new->next = *head;
526 *head = new;
527 }
528
529 void
530 delmyaddr(myaddr)
531 struct myaddrs *myaddr;
532 {
533 if (myaddr->addr)
534 racoon_free(myaddr->addr);
535 if (myaddr->ifname)
536 racoon_free(myaddr->ifname);
537 racoon_free(myaddr);
538 }
539
540 int
541 initmyaddr()
542 {
543 /* initialize routing socket */
544 lcconf->rtsock = socket(PF_ROUTE, SOCK_RAW, PF_UNSPEC);
545 if (lcconf->rtsock < 0) {
546 plog(LLV_ERROR, LOCATION, NULL,
547 "socket(PF_ROUTE) failed: %s",
548 strerror(errno));
549 return -1;
550 }
551
552 if (fcntl(lcconf->rtsock, F_SETFL, O_NONBLOCK) == -1) {
553 plog(LLV_ERROR, LOCATION, NULL,
554 "failed to put PF_ROUTE socket in non-blocking mode\n");
555 }
556
557 if (lcconf->myaddrs == NULL && lcconf->autograbaddr == 1) {
558 grab_myaddrs();
559
560 if (autoconf_myaddrsport() < 0)
561 return -1;
562 }
563
564 return 0;
565 }
566
567 /* select the socket to be sent */
568 /* should implement other method. */
569 int
570 getsockmyaddr(my)
571 struct sockaddr *my;
572 {
573 struct myaddrs *p, *lastresort = NULL;
574
575 for (p = lcconf->myaddrs; p; p = p->next) {
576 if (p->addr == NULL)
577 continue;
578 if (my->sa_family == p->addr->ss_family) {
579 lastresort = p;
580 } else continue;
581 if (sysdep_sa_len(my) == sysdep_sa_len((struct sockaddr *)p->addr)
582 && memcmp(my, p->addr, sysdep_sa_len(my)) == 0) {
583 break;
584 }
585 }
586 if (!p)
587 p = lastresort;
588 if (!p) {
589 plog(LLV_ERROR, LOCATION, NULL,
590 "no socket matches address family %d\n",
591 my->sa_family);
592 return -1;
593 }
594
595 return p->sock;
596 }