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