]> git.saurik.com Git - apple/ipsec.git/blame - ipsec-tools/racoon/grabmyaddr.c
ipsec-146.3.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
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
52b7d2ce
A
73#ifndef HAVE_GETIFADDRS
74static unsigned int if_maxindex __P((void));
75#endif
d1e348cf 76
52b7d2ce
A
77static int suitable_ifaddr __P((const char *, const struct sockaddr *));
78#ifdef INET6
79static int suitable_ifaddr6 __P((const char *, const struct sockaddr *));
80#endif
81
52b7d2ce
A
82#ifndef HAVE_GETIFADDRS
83static unsigned int
84if_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
100void
101clear_myaddr()
102{
103 struct myaddrs *p, *next;
104
105 for (p = lcconf->myaddrs; p; p = next) {
106 next = p->next;
107
d1e348cf 108 delmyaddr(p);
52b7d2ce
A
109 }
110
111 lcconf->myaddrs = NULL;
112
113}
114
115
d1e348cf
A
116struct myaddrs *
117find_myaddr(addr, udp_encap)
52b7d2ce
A
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
d1e348cf 128 for (q = lcconf->myaddrs; q; q = q->next) {
52b7d2ce
A
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.
151void
152grab_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)) {
d1e348cf 184 plog(LLV_DEBUG2, LOCATION, NULL,
52b7d2ce
A
185 "unsuitable address: %s %s\n",
186 ifap->ifa_name,
187 saddrwop2str(ifap->ifa_addr));
188 continue;
189 }
190
d1e348cf 191 p = find_myaddr(ifap->ifa_addr, 0);
52b7d2ce
A
192 if (p) {
193 p->in_use = 1;
194#ifdef ENABLE_NATT
d1e348cf 195 q = find_myaddr(ifap->ifa_addr, 1);
52b7d2ce
A
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 }
d1e348cf
A
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
52b7d2ce
A
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 */
264static int
265suitable_ifaddr(ifname, ifaddr)
266 const char *ifname;
267 const struct sockaddr *ifaddr;
268{
e8d9021d 269#if 0 //we need to be able to do nested ipsec for BTMM... stub out ifdef ENABLE_HYBRID
52b7d2ce
A
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
288static int
289suitable_ifaddr6(ifname, ifaddr)
290 const char *ifname;
291 const struct sockaddr *ifaddr;
292{
52b7d2ce
A
293 struct in6_ifreq ifr6;
294 int s;
52b7d2ce
A
295
296 if (ifaddr->sa_family != AF_INET6)
297 return 0;
298
52b7d2ce
A
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));
d1e348cf 307 strlcpy(ifr6.ifr_name, ifname, sizeof(ifr6.ifr_name));
52b7d2ce
A
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;
52b7d2ce
A
324
325 /* suitable */
326 return 1;
327}
328#endif
329
330int
331update_myaddrs()
332{
52b7d2ce
A
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;
52b7d2ce
A
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 */
388int
389autoconf_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 */
410u_short
411getmyaddrsport(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
455struct myaddrs *
456newmyaddr()
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;
d1e348cf
A
469#ifdef __APPLE_
470 new->ifname = NULL;
471#endif
52b7d2ce
A
472
473 return new;
474}
475
476struct myaddrs *
477dupmyaddr(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 }
d1e348cf
A
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
52b7d2ce
A
508 new->next = old->next;
509 old->next = new;
510
511 return new;
512}
513
514void
515insmyaddr(new, head)
516 struct myaddrs *new;
517 struct myaddrs **head;
518{
519 new->next = *head;
520 *head = new;
521}
522
523void
524delmyaddr(myaddr)
525 struct myaddrs *myaddr;
526{
527 if (myaddr->addr)
528 racoon_free(myaddr->addr);
d1e348cf
A
529 if (myaddr->ifname)
530 racoon_free(myaddr->ifname);
52b7d2ce
A
531 racoon_free(myaddr);
532}
533
534int
535initmyaddr()
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
52b7d2ce
A
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. */
558int
559getsockmyaddr(my)
560 struct sockaddr *my;
561{
562 struct myaddrs *p, *lastresort = NULL;
52b7d2ce
A
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 }
52b7d2ce 574 }
52b7d2ce
A
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}