]> git.saurik.com Git - apple/network_cmds.git/blame - racoon.tproj/grabmyaddr.c
network_cmds-176.2.1.tar.gz
[apple/network_cmds.git] / racoon.tproj / grabmyaddr.c
CommitLineData
ac2f15b3 1/* $KAME: grabmyaddr.c,v 1.35 2003/01/14 07:07:36 sakane Exp $ */
7ba0088d
A
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 <sys/types.h>
33#include <sys/param.h>
34#include <sys/socket.h>
35#include <sys/ioctl.h>
36
37#include <net/if.h>
38#if defined(__FreeBSD__) && __FreeBSD__ >= 3
39#include <net/if_var.h>
40#endif
41#include <net/route.h>
42#include <netkey/key_var.h>
43#include <netinet/in.h>
44#include <netinet6/in6_var.h>
45
46#include <stdlib.h>
47#include <stdio.h>
48#include <string.h>
49#include <errno.h>
50#ifdef HAVE_UNISTD_H
51#include <unistd.h>
52#endif
53#include <netdb.h>
54#ifdef HAVE_GETIFADDRS
55#include <ifaddrs.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 "grabmyaddr.h"
67#include "sockmisc.h"
68#include "isakmp_var.h"
69#include "gcmalloc.h"
70
71#ifndef HAVE_GETIFADDRS
72static unsigned int if_maxindex __P((void));
73#endif
74static struct myaddrs *find_myaddr __P((struct myaddrs *, struct myaddrs *));
75static int suitable_ifaddr __P((const char *, const struct sockaddr *));
76#ifdef INET6
77static int suitable_ifaddr6 __P((const char *, const struct sockaddr *));
78#endif
79
80#ifndef HAVE_GETIFADDRS
81static unsigned int
82if_maxindex()
83{
84 struct if_nameindex *p, *p0;
85 unsigned int max = 0;
86
87 p0 = if_nameindex();
88 for (p = p0; p && p->if_index && p->if_name; p++) {
89 if (max < p->if_index)
90 max = p->if_index;
91 }
92 if_freenameindex(p0);
93 return max;
94}
95#endif
96
97void
98clear_myaddr(db)
99 struct myaddrs **db;
100{
101 struct myaddrs *p;
102
103 while (*db) {
104 p = (*db)->next;
105 delmyaddr(*db);
106 *db = p;
107 }
108}
109
110static struct myaddrs *
111find_myaddr(db, p)
112 struct myaddrs *db;
113 struct myaddrs *p;
114{
115 struct myaddrs *q;
116 char h1[NI_MAXHOST], h2[NI_MAXHOST];
117
118 if (getnameinfo(p->addr, p->addr->sa_len, h1, sizeof(h1), NULL, 0,
119 NI_NUMERICHOST | niflags) != 0)
120 return NULL;
121
122 for (q = db; q; q = q->next) {
123 if (p->addr->sa_len != q->addr->sa_len)
124 continue;
125 if (getnameinfo(q->addr, q->addr->sa_len, h2, sizeof(h2),
126 NULL, 0, NI_NUMERICHOST | niflags) != 0)
127 return NULL;
128 if (strcmp(h1, h2) == 0)
129 return q;
130 }
131
132 return NULL;
133}
134
135void
136grab_myaddrs()
137{
138#ifdef HAVE_GETIFADDRS
139 struct myaddrs *p, *q, *old;
140 struct ifaddrs *ifa0, *ifap;
141#ifdef INET6
142#ifdef __KAME__
143 struct sockaddr_in6 *sin6;
144#endif
145#endif
146
ac2f15b3 147 char addr1[NI_MAXHOST];
7ba0088d
A
148
149 if (getifaddrs(&ifa0)) {
150 plog(LLV_ERROR, LOCATION, NULL,
151 "getifaddrs failed: %s\n", strerror(errno));
152 exit(1);
153 /*NOTREACHED*/
154 }
155
156 old = lcconf->myaddrs;
157
158 for (ifap = ifa0; ifap; ifap = ifap->ifa_next) {
159
160 if (ifap->ifa_addr->sa_family != AF_INET
161#ifdef INET6
162 && ifap->ifa_addr->sa_family != AF_INET6
163#endif
164 )
165 continue;
166
167 if (!suitable_ifaddr(ifap->ifa_name, ifap->ifa_addr)) {
168 plog(LLV_ERROR, LOCATION, NULL,
ac2f15b3
A
169 "unsuitable address: %s %s\n",
170 ifap->ifa_name,
171 saddrwop2str(ifap->ifa_addr));
7ba0088d
A
172 continue;
173 }
174
175 p = newmyaddr();
176 if (p == NULL) {
177 exit(1);
178 /*NOTREACHED*/
179 }
180 p->addr = dupsaddr(ifap->ifa_addr);
181 if (p->addr == NULL) {
182 exit(1);
183 /*NOTREACHED*/
184 }
185#ifdef INET6
186#ifdef __KAME__
187 if (ifap->ifa_addr->sa_family == AF_INET6) {
188 sin6 = (struct sockaddr_in6 *)p->addr;
189 if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)
190 || IN6_IS_ADDR_SITELOCAL(&sin6->sin6_addr)) {
191 sin6->sin6_scope_id =
192 ntohs(*(u_int16_t *)&sin6->sin6_addr.s6_addr[2]);
193 sin6->sin6_addr.s6_addr[2] = 0;
194 sin6->sin6_addr.s6_addr[3] = 0;
195 }
196 }
197#endif
198#endif
199 if (getnameinfo(p->addr, p->addr->sa_len,
ac2f15b3 200 addr1, sizeof(addr1),
7ba0088d
A
201 NULL, 0,
202 NI_NUMERICHOST | niflags))
ac2f15b3 203 strlcpy(addr1, "(invalid)", sizeof(addr1));
7ba0088d
A
204 plog(LLV_DEBUG, LOCATION, NULL,
205 "my interface: %s (%s)\n",
ac2f15b3 206 addr1, ifap->ifa_name);
7ba0088d 207 q = find_myaddr(old, p);
ac2f15b3 208 if (q) {
7ba0088d 209 p->sock = q->sock;
ac2f15b3
A
210#ifdef IKE_NAT_T
211 p->nattsock = q->nattsock;
212#endif
213 } else {
7ba0088d 214 p->sock = -1;
ac2f15b3
A
215#ifdef IKE_NAT_T
216 p->nattsock = -1;
217#endif
218 }
7ba0088d
A
219 p->next = lcconf->myaddrs;
220 lcconf->myaddrs = p;
221 }
222
223 freeifaddrs(ifa0);
224
225 clear_myaddr(&old);
226
227#else /*!HAVE_GETIFADDRS*/
228 int s;
229 unsigned int maxif;
230 int len;
231 struct ifreq *iflist;
232 struct ifconf ifconf;
233 struct ifreq *ifr, *ifr_end;
234 struct myaddrs *p, *q, *old;
235#ifdef INET6
236#ifdef __KAME__
237 struct sockaddr_in6 *sin6;
238#endif
239#endif
240
ac2f15b3 241 char addr1[NI_MAXHOST];
7ba0088d
A
242
243 maxif = if_maxindex() + 1;
244 len = maxif * sizeof(struct sockaddr_storage) * 4; /* guess guess */
245
246 iflist = (struct ifreq *)racoon_malloc(len);
247 if (!iflist) {
248 plog(LLV_ERROR, LOCATION, NULL,
249 "failed to allocate buffer\n");
250 exit(1);
251 /*NOTREACHED*/
252 }
253
254 if ((s = socket(PF_INET, SOCK_DGRAM, 0)) < 0) {
255 plog(LLV_ERROR, LOCATION, NULL,
256 "socket(SOCK_DGRAM) failed: %s\n",
257 strerror(errno));
258 exit(1);
259 /*NOTREACHED*/
260 }
261 memset(&ifconf, 0, sizeof(ifconf));
262 ifconf.ifc_req = iflist;
263 ifconf.ifc_len = len;
264 if (ioctl(s, SIOCGIFCONF, &ifconf) < 0) {
265 plog(LLV_ERROR, LOCATION, NULL,
266 "ioctl(SIOCGIFCONF) failed: %s\n",
267 strerror(errno));
268 exit(1);
269 /*NOTREACHED*/
270 }
271 close(s);
272
273 old = lcconf->myaddrs;
274
275 /* Look for this interface in the list */
276 ifr_end = (struct ifreq *) (ifconf.ifc_buf + ifconf.ifc_len);
277
278#define _IFREQ_LEN(p) \
279 (sizeof((p)->ifr_name) + (p)->ifr_addr.sa_len > sizeof(struct ifreq) \
280 ? sizeof((p)->ifr_name) + (p)->ifr_addr.sa_len : sizeof(struct ifreq))
281
282 for (ifr = ifconf.ifc_req;
283 ifr < ifr_end;
284 ifr = (struct ifreq *)((caddr_t)ifr + _IFREQ_LEN(ifr))) {
285
286 switch (ifr->ifr_addr.sa_family) {
287 case AF_INET:
288#ifdef INET6
289 case AF_INET6:
290#endif
291 if (!suitable_ifaddr(ifr->ifr_name, &ifr->ifr_addr)) {
ac2f15b3
A
292 plog(LLV_ERROR, LOCATION, NULL,
293 "unsuitable address: %s %s\n",
294 ifr->ifr_name,
295 saddrwop2str(&ifr->ifr_addr));
7ba0088d
A
296 continue;
297 }
298
299 p = newmyaddr();
300 if (p == NULL) {
301 exit(1);
302 /*NOTREACHED*/
303 }
304 p->addr = dupsaddr(&ifr->ifr_addr);
305 if (p->addr == NULL) {
306 exit(1);
307 /*NOTREACHED*/
308 }
309#ifdef INET6
310#ifdef __KAME__
311 sin6 = (struct sockaddr_in6 *)p->addr;
312 if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)
313 || IN6_IS_ADDR_SITELOCAL(&sin6->sin6_addr)) {
314 sin6->sin6_scope_id =
315 ntohs(*(u_int16_t *)&sin6->sin6_addr.s6_addr[2]);
316 sin6->sin6_addr.s6_addr[2] = 0;
317 sin6->sin6_addr.s6_addr[3] = 0;
318 }
319#endif
320#endif
321 if (getnameinfo(p->addr, p->addr->sa_len,
ac2f15b3 322 addr1, sizeof(addr1),
7ba0088d
A
323 NULL, 0,
324 NI_NUMERICHOST | niflags))
ac2f15b3 325 strlcpy(addr1, "(invalid)", sizeof(addr1));
7ba0088d
A
326 plog(LLV_DEBUG, LOCATION, NULL,
327 "my interface: %s (%s)\n",
ac2f15b3 328 addr1, ifr->ifr_name);
7ba0088d
A
329 q = find_myaddr(old, p);
330 if (q)
331 p->sock = q->sock;
332 else
333 p->sock = -1;
334 p->next = lcconf->myaddrs;
335 lcconf->myaddrs = p;
336 break;
337 default:
338 break;
339 }
340 }
341
342 clear_myaddr(&old);
343
344 racoon_free(iflist);
345#endif /*HAVE_GETIFADDRS*/
346}
347
348/*
349 * check the interface is suitable or not
350 */
351static int
352suitable_ifaddr(ifname, ifaddr)
353 const char *ifname;
354 const struct sockaddr *ifaddr;
355{
356 switch(ifaddr->sa_family) {
357 case AF_INET:
358 return 1;
359#ifdef INET6
360 case AF_INET6:
361 return suitable_ifaddr6(ifname, ifaddr);
362#endif
363 default:
364 return 0;
365 }
366 /*NOTREACHED*/
367}
368
369#ifdef INET6
370static int
371suitable_ifaddr6(ifname, ifaddr)
372 const char *ifname;
373 const struct sockaddr *ifaddr;
374{
375 struct in6_ifreq ifr6;
376 int s;
377
378 if (ifaddr->sa_family != AF_INET6)
379 return 0;
380
381 s = socket(PF_INET6, SOCK_DGRAM, 0);
382 if (s == -1) {
383 plog(LLV_ERROR, LOCATION, NULL,
384 "socket(SOCK_DGRAM) failed:%s\n", strerror(errno));
385 return 0;
386 }
387
388 memset(&ifr6, 0, sizeof(ifr6));
389 strncpy(ifr6.ifr_name, ifname, strlen(ifname));
390
391 ifr6.ifr_addr = *(const struct sockaddr_in6 *)ifaddr;
392
393 if (ioctl(s, SIOCGIFAFLAG_IN6, &ifr6) < 0) {
394 plog(LLV_ERROR, LOCATION, NULL,
395 "ioctl(SIOCGIFAFLAG_IN6) failed:%s\n", strerror(errno));
396 close(s);
397 return 0;
398 }
399
400 close(s);
401
402 if (ifr6.ifr_ifru.ifru_flags6 & IN6_IFF_DUPLICATED
403 || ifr6.ifr_ifru.ifru_flags6 & IN6_IFF_DETACHED)
404 return 0;
405
406 /* suitable */
407 return 1;
408}
409#endif
410
411int
412update_myaddrs()
413{
414 char msg[BUFSIZ];
415 int len;
416 struct rt_msghdr *rtm;
417
418 len = read(lcconf->rtsock, msg, sizeof(msg));
419 if (len < 0) {
420 plog(LLV_ERROR, LOCATION, NULL,
421 "read(PF_ROUTE) failed: %s\n",
422 strerror(errno));
423 return 0;
424 }
425 rtm = (struct rt_msghdr *)msg;
426 if (len < rtm->rtm_msglen) {
427 plog(LLV_ERROR, LOCATION, NULL,
428 "read(PF_ROUTE) short read\n");
429 return 0;
430 }
431 if (rtm->rtm_version != RTM_VERSION) {
432 plog(LLV_ERROR, LOCATION, NULL,
433 "routing socket version mismatch\n");
434 close(lcconf->rtsock);
ac2f15b3 435 lcconf->rtsock = -1;
7ba0088d
A
436 return 0;
437 }
438 switch (rtm->rtm_type) {
439 case RTM_NEWADDR:
440 case RTM_DELADDR:
441 case RTM_DELETE:
442 case RTM_IFINFO:
443 break;
444 case RTM_MISS:
445 /* ignore this message silently */
446 return 0;
447 default:
448 plog(LLV_DEBUG, LOCATION, NULL,
449 "msg %d not interesting\n", rtm->rtm_type);
450 return 0;
451 }
452 /* XXX more filters here? */
453
454 plog(LLV_DEBUG, LOCATION, NULL,
455 "caught rtm:%d, need update interface address list\n",
456 rtm->rtm_type);
457 return 1;
458}
459
460/*
461 * initialize default port for ISAKMP to send, if no "listen"
462 * directive is specified in config file.
463 *
464 * DO NOT listen to wildcard addresses. if you receive packets to
465 * wildcard address, you'll be in trouble (DoS attack possible by
466 * broadcast storm).
467 */
468int
469autoconf_myaddrsport()
470{
471 struct myaddrs *p;
472 struct sockaddr_in *sin4;
473#ifdef INET6
474 struct sockaddr_in6 *sin6;
475#endif
476 int n;
477
478 plog(LLV_DEBUG, LOCATION, NULL,
479 "configuring default isakmp port.\n");
480 n = 0;
481 for (p = lcconf->myaddrs; p; p = p->next) {
482 switch (p->addr->sa_family) {
483 case AF_INET:
484 sin4 = (struct sockaddr_in *)p->addr;
485 sin4->sin_port = htons(lcconf->port_isakmp);
486 break;
487#ifdef INET6
488 case AF_INET6:
489 sin6 = (struct sockaddr_in6 *)p->addr;
490 sin6->sin6_port = htons(lcconf->port_isakmp);
491 break;
492#endif
493 default:
494 plog(LLV_ERROR, LOCATION, NULL,
495 "unsupported AF %d\n", p->addr->sa_family);
496 goto err;
497 }
498 n++;
499 }
500 plog(LLV_DEBUG, LOCATION, NULL,
501 "%d addrs are configured successfully\n", n);
502
503 return 0;
504err:
505 plog(LLV_ERROR, LOCATION, NULL, "address autoconfiguration failed\n");
506 return -1;
507}
508
509/*
510 * get a port number to which racoon binded.
511 * NOTE: network byte order returned.
512 */
513u_short
514getmyaddrsport(local)
515 struct sockaddr *local;
516{
517 struct myaddrs *p;
518
519 /* get a relative port */
520 for (p = lcconf->myaddrs; p; p = p->next) {
521 if (!p->addr)
522 continue;
523 if (!cmpsaddrwop(local, p->addr)) {
524 switch (p->addr->sa_family) {
525 case AF_INET:
526 return ((struct sockaddr_in *)p->addr)->sin_port;
527#ifdef INET6
528 case AF_INET6:
529 return ((struct sockaddr_in6 *)p->addr)->sin6_port;
530#endif
531 default:
532 plog(LLV_ERROR, LOCATION, NULL,
533 "invalid family: %d\n",
534 p->addr->sa_family);
535 return -1;
536 }
537 }
538 continue;
539 }
540
541 return htons(PORT_ISAKMP);
542}
543
544struct myaddrs *
545newmyaddr()
546{
547 struct myaddrs *new;
548
549 new = racoon_calloc(1, sizeof(*new));
550 if (new == NULL) {
551 plog(LLV_ERROR, LOCATION, NULL,
552 "failed to allocate buffer for myaddrs.\n");
553 return NULL;
554 }
555
556 new->next = NULL;
557 new->addr = NULL;
558
559 return new;
560}
561
562void
563insmyaddr(new, head)
564 struct myaddrs *new;
565 struct myaddrs **head;
566{
567 new->next = *head;
568 *head = new;
569}
570
571void
572delmyaddr(myaddr)
573 struct myaddrs *myaddr;
574{
575 if (myaddr->addr)
576 racoon_free(myaddr->addr);
577 racoon_free(myaddr);
578}
579
580int
581initmyaddr()
582{
583 /* initialize routing socket */
584 lcconf->rtsock = socket(PF_ROUTE, SOCK_RAW, PF_UNSPEC);
585 if (lcconf->rtsock < 0) {
586 plog(LLV_ERROR, LOCATION, NULL,
587 "socket(PF_ROUTE) failed: %s",
588 strerror(errno));
589 return -1;
590 }
591
592 if (lcconf->myaddrs == NULL && lcconf->autograbaddr == 1) {
593 grab_myaddrs();
594
595 if (autoconf_myaddrsport() < 0)
596 return -1;
597 }
598
599 return 0;
600}
601
602/* select the socket to be sent */
603/* should implement other method. */
604int
605getsockmyaddr(my)
606 struct sockaddr *my;
607{
608 struct myaddrs *p, *lastresort = NULL;
609
610 for (p = lcconf->myaddrs; p; p = p->next) {
611 if (p->addr == NULL)
612 continue;
613 if (my->sa_family == p->addr->sa_family)
614 lastresort = p;
615 if (my->sa_len == p->addr->sa_len
616 && memcmp(my, p->addr, my->sa_len) == 0) {
617 break;
618 }
ac2f15b3
A
619#ifdef IKE_NAT_T
620 if (my->sa_family == p->addr->sa_family &&
621 my->sa_family == AF_INET &&
622 ((struct sockaddr_in*)my)->sin_addr.s_addr ==
623 ((struct sockaddr_in*)p->addr)->sin_addr.s_addr &&
624 ((struct sockaddr_in*)my)->sin_port == htons(PORT_ISAKMP_NATT))
625 {
626 plog(LLV_DEBUG, LOCATION, NULL,
627 "picked natt socket (%d - %s) for sending\n",
628 p->nattsock, saddr2str(my));
629 return p->nattsock;
630 }
631#endif
7ba0088d
A
632 }
633 if (!p)
634 p = lastresort;
635 if (!p) {
636 plog(LLV_ERROR, LOCATION, NULL,
637 "no socket matches address family %d\n",
638 my->sa_family);
639 return -1;
640 }
641
642 return p->sock;
643}