]> git.saurik.com Git - apple/ipsec.git/blame_incremental - ipsec-tools/racoon/grabmyaddr.c
ipsec-164.10.tar.gz
[apple/ipsec.git] / ipsec-tools / racoon / grabmyaddr.c
... / ...
CommitLineData
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
75static unsigned int if_maxindex __P((void));
76#endif
77
78static int suitable_ifaddr __P((const char *, const struct sockaddr *));
79#ifdef INET6
80static int suitable_ifaddr6 __P((const char *, const struct sockaddr *));
81#endif
82
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
109 delmyaddr(p);
110 }
111
112 lcconf->myaddrs = NULL;
113
114}
115
116
117struct myaddrs *
118find_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.
152void
153grab_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 */
262static int
263suitable_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
286static int
287suitable_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
333int
334update_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 */
394int
395autoconf_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 */
416u_short
417getmyaddrsport(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
461struct myaddrs *
462newmyaddr()
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
482struct myaddrs *
483dupmyaddr(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
520void
521insmyaddr(new, head)
522 struct myaddrs *new;
523 struct myaddrs **head;
524{
525 new->next = *head;
526 *head = new;
527}
528
529void
530delmyaddr(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
540int
541initmyaddr()
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. */
569int
570getsockmyaddr(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}