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