]> git.saurik.com Git - apple/network_cmds.git/blob - racoon.tproj/grabmyaddr.c
5abd87f2c54066758f4bc16a994f14b2793792a3
[apple/network_cmds.git] / racoon.tproj / grabmyaddr.c
1 /* $KAME: grabmyaddr.c,v 1.35 2003/01/14 07:07:36 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 sockaddr *));
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, addr)
112 struct myaddrs *db;
113 struct sockaddr *addr;
114 {
115 struct myaddrs *q;
116 char h1[NI_MAXHOST], h2[NI_MAXHOST];
117
118 if (getnameinfo(addr, 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 (!q->addr)
124 continue;
125 if (addr->sa_len != q->addr->sa_len)
126 continue;
127 if (getnameinfo(q->addr, q->addr->sa_len, h2, sizeof(h2),
128 NULL, 0, NI_NUMERICHOST | niflags) != 0)
129 return NULL;
130 if (strcmp(h1, h2) == 0)
131 return q;
132 }
133
134 return NULL;
135 }
136
137 // 1/19/04 - modified to avoid closing and opening sockets for
138 // all interfaces each time an interface change occurs.
139 // on return: addrcount = zero indicates address no longer used
140 // sock = -1 indicates a new address - no socket opened yet.
141 void
142 grab_myaddrs()
143 {
144 #ifdef HAVE_GETIFADDRS
145 struct myaddrs *p;
146 struct ifaddrs *ifa0, *ifap;
147 #ifdef INET6
148 #ifdef __KAME__
149 struct sockaddr_in6 *sin6;
150 #endif
151 #endif
152
153 char addr1[NI_MAXHOST];
154
155 if (getifaddrs(&ifa0)) {
156 plog(LLV_ERROR, LOCATION, NULL,
157 "getifaddrs failed: %s\n", strerror(errno));
158 exit(1);
159 /*NOTREACHED*/
160 }
161
162 // zero the count for each address in our list
163 for (p = lcconf->myaddrs; p; p = p->next)
164 p->addrcount = 0;
165
166 for (ifap = ifa0; ifap; ifap = ifap->ifa_next) {
167
168 if (ifap->ifa_addr->sa_family != AF_INET
169 #ifdef INET6
170 && ifap->ifa_addr->sa_family != AF_INET6
171 #endif
172 )
173 continue;
174
175 if (!suitable_ifaddr(ifap->ifa_name, ifap->ifa_addr)) {
176 plog(LLV_ERROR, LOCATION, NULL,
177 "unsuitable address: %s %s\n",
178 ifap->ifa_name,
179 saddrwop2str(ifap->ifa_addr));
180 continue;
181 }
182
183 #ifdef INET6
184 #ifdef __KAME__
185 if (ifap->ifa_addr->sa_family == AF_INET6) {
186 sin6 = (struct sockaddr_in6 *)ifap->ifa_addr;
187 if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)
188 || IN6_IS_ADDR_SITELOCAL(&sin6->sin6_addr)) {
189 sin6->sin6_scope_id =
190 ntohs(*(u_int16_t *)&sin6->sin6_addr.s6_addr[2]);
191 sin6->sin6_addr.s6_addr[2] = 0;
192 sin6->sin6_addr.s6_addr[3] = 0;
193 }
194 }
195 #endif
196 #endif
197
198 p = find_myaddr(lcconf->myaddrs, ifap->ifa_addr);
199 if (p)
200 p->addrcount++;
201 else {
202 p = newmyaddr();
203 if (p == NULL) {
204 exit(1);
205 /*NOTREACHED*/
206 }
207 p->addr = dupsaddr(ifap->ifa_addr);
208 if (p->addr == NULL) {
209 exit(1);
210 /*NOTREACHED*/
211 }
212 p->sock = -1;
213 #ifdef IKE_NAT_T
214 p->nattsock = -1;
215 #endif
216 p->addrcount = 1;
217
218 if (getnameinfo(p->addr, p->addr->sa_len,
219 addr1, sizeof(addr1),
220 NULL, 0,
221 NI_NUMERICHOST | niflags))
222 strlcpy(addr1, "(invalid)", sizeof(addr1));
223 plog(LLV_DEBUG, LOCATION, NULL,
224 "my interface: %s (%s)\n",
225 addr1, ifap->ifa_name);
226
227 p->next = lcconf->myaddrs;
228 lcconf->myaddrs = p;
229 }
230 }
231
232 freeifaddrs(ifa0);
233
234
235 #else /*!HAVE_GETIFADDRS*/
236 #error "NOT SUPPORTED"
237 #endif /*HAVE_GETIFADDRS*/
238 }
239
240 /*
241 * check the interface is suitable or not
242 */
243 static int
244 suitable_ifaddr(ifname, ifaddr)
245 const char *ifname;
246 const struct sockaddr *ifaddr;
247 {
248 switch(ifaddr->sa_family) {
249 case AF_INET:
250 return 1;
251 #ifdef INET6
252 case AF_INET6:
253 return suitable_ifaddr6(ifname, ifaddr);
254 #endif
255 default:
256 return 0;
257 }
258 /*NOTREACHED*/
259 }
260
261 #ifdef INET6
262 static int
263 suitable_ifaddr6(ifname, ifaddr)
264 const char *ifname;
265 const struct sockaddr *ifaddr;
266 {
267 struct in6_ifreq ifr6;
268 int s;
269
270 if (ifaddr->sa_family != AF_INET6)
271 return 0;
272
273 s = socket(PF_INET6, SOCK_DGRAM, 0);
274 if (s == -1) {
275 plog(LLV_ERROR, LOCATION, NULL,
276 "socket(SOCK_DGRAM) failed:%s\n", strerror(errno));
277 return 0;
278 }
279
280 memset(&ifr6, 0, sizeof(ifr6));
281 strncpy(ifr6.ifr_name, ifname, strlen(ifname));
282
283 ifr6.ifr_addr = *(const struct sockaddr_in6 *)ifaddr;
284
285 if (ioctl(s, SIOCGIFAFLAG_IN6, &ifr6) < 0) {
286 plog(LLV_ERROR, LOCATION, NULL,
287 "ioctl(SIOCGIFAFLAG_IN6) failed:%s\n", strerror(errno));
288 close(s);
289 return 0;
290 }
291
292 close(s);
293
294 if (ifr6.ifr_ifru.ifru_flags6 & IN6_IFF_DUPLICATED
295 || ifr6.ifr_ifru.ifru_flags6 & IN6_IFF_DETACHED)
296 return 0;
297
298 /* suitable */
299 return 1;
300 }
301 #endif
302
303 int
304 update_myaddrs()
305 {
306 char msg[BUFSIZ];
307 int len;
308 struct rt_msghdr *rtm;
309
310 len = read(lcconf->rtsock, msg, sizeof(msg));
311 if (len < 0) {
312 plog(LLV_ERROR, LOCATION, NULL,
313 "read(PF_ROUTE) failed: %s\n",
314 strerror(errno));
315 return 0;
316 }
317 rtm = (struct rt_msghdr *)msg;
318 if (len < rtm->rtm_msglen) {
319 plog(LLV_ERROR, LOCATION, NULL,
320 "read(PF_ROUTE) short read\n");
321 return 0;
322 }
323 if (rtm->rtm_version != RTM_VERSION) {
324 plog(LLV_ERROR, LOCATION, NULL,
325 "routing socket version mismatch\n");
326 close(lcconf->rtsock);
327 lcconf->rtsock = -1;
328 return 0;
329 }
330 switch (rtm->rtm_type) {
331 case RTM_NEWADDR:
332 case RTM_DELADDR:
333 case RTM_DELETE:
334 case RTM_IFINFO:
335 break;
336 case RTM_MISS:
337 /* ignore this message silently */
338 return 0;
339 default:
340 plog(LLV_DEBUG, LOCATION, NULL,
341 "msg %d not interesting\n", rtm->rtm_type);
342 return 0;
343 }
344 /* XXX more filters here? */
345
346 plog(LLV_DEBUG, LOCATION, NULL,
347 "caught rtm:%d, need update interface address list\n",
348 rtm->rtm_type);
349 return 1;
350 }
351
352 /*
353 * initialize default port for ISAKMP to send, if no "listen"
354 * directive is specified in config file.
355 *
356 * DO NOT listen to wildcard addresses. if you receive packets to
357 * wildcard address, you'll be in trouble (DoS attack possible by
358 * broadcast storm).
359 */
360 int
361 autoconf_myaddrsport()
362 {
363 struct myaddrs *p;
364 struct sockaddr_in *sin4;
365 #ifdef INET6
366 struct sockaddr_in6 *sin6;
367 #endif
368 int n;
369
370 plog(LLV_DEBUG, LOCATION, NULL,
371 "configuring default isakmp port.\n");
372 n = 0;
373 for (p = lcconf->myaddrs; p; p = p->next) {
374 if (!p->addr)
375 continue;
376 switch (p->addr->sa_family) {
377 case AF_INET:
378 sin4 = (struct sockaddr_in *)p->addr;
379 sin4->sin_port = htons(lcconf->port_isakmp);
380 break;
381 #ifdef INET6
382 case AF_INET6:
383 sin6 = (struct sockaddr_in6 *)p->addr;
384 sin6->sin6_port = htons(lcconf->port_isakmp);
385 break;
386 #endif
387 default:
388 plog(LLV_ERROR, LOCATION, NULL,
389 "unsupported AF %d\n", p->addr->sa_family);
390 goto err;
391 }
392 n++;
393 }
394 plog(LLV_DEBUG, LOCATION, NULL,
395 "%d addrs are configured successfully\n", n);
396
397 return 0;
398 err:
399 plog(LLV_ERROR, LOCATION, NULL, "address autoconfiguration failed\n");
400 return -1;
401 }
402
403 /*
404 * get a port number to which racoon binded.
405 * NOTE: network byte order returned.
406 */
407 u_short
408 getmyaddrsport(local)
409 struct sockaddr *local;
410 {
411 struct myaddrs *p;
412
413 /* get a relative port */
414 for (p = lcconf->myaddrs; p; p = p->next) {
415 if (!p->addr)
416 continue;
417 if (!cmpsaddrwop(local, p->addr)) {
418 switch (p->addr->sa_family) {
419 case AF_INET:
420 return ((struct sockaddr_in *)p->addr)->sin_port;
421 #ifdef INET6
422 case AF_INET6:
423 return ((struct sockaddr_in6 *)p->addr)->sin6_port;
424 #endif
425 default:
426 plog(LLV_ERROR, LOCATION, NULL,
427 "invalid family: %d\n",
428 p->addr->sa_family);
429 return -1;
430 }
431 }
432 continue;
433 }
434
435 return htons(PORT_ISAKMP);
436 }
437
438 struct myaddrs *
439 newmyaddr()
440 {
441 struct myaddrs *new;
442
443 new = racoon_calloc(1, sizeof(*new));
444 if (new == NULL) {
445 plog(LLV_ERROR, LOCATION, NULL,
446 "failed to allocate buffer for myaddrs.\n");
447 return NULL;
448 }
449
450 new->next = NULL;
451 new->addr = NULL;
452
453 return new;
454 }
455
456 void
457 insmyaddr(new, head)
458 struct myaddrs *new;
459 struct myaddrs **head;
460 {
461 new->next = *head;
462 *head = new;
463 }
464
465 void
466 delmyaddr(myaddr)
467 struct myaddrs *myaddr;
468 {
469 if (myaddr->addr)
470 racoon_free(myaddr->addr);
471 racoon_free(myaddr);
472 }
473
474 int
475 initmyaddr()
476 {
477 /* initialize routing socket */
478 lcconf->rtsock = socket(PF_ROUTE, SOCK_RAW, PF_UNSPEC);
479 if (lcconf->rtsock < 0) {
480 plog(LLV_ERROR, LOCATION, NULL,
481 "socket(PF_ROUTE) failed: %s",
482 strerror(errno));
483 return -1;
484 }
485
486 if (lcconf->myaddrs == NULL && lcconf->autograbaddr == 1) {
487 grab_myaddrs();
488
489 if (autoconf_myaddrsport() < 0)
490 return -1;
491 }
492
493 return 0;
494 }
495
496 /* select the socket to be sent */
497 /* should implement other method. */
498 int
499 getsockmyaddr(my)
500 struct sockaddr *my;
501 {
502 struct myaddrs *p, *lastresort = NULL;
503
504 for (p = lcconf->myaddrs; p; p = p->next) {
505 if (p->addr == NULL)
506 continue;
507 if (my->sa_family == p->addr->sa_family)
508 lastresort = p;
509 if (my->sa_len == p->addr->sa_len
510 && memcmp(my, p->addr, my->sa_len) == 0) {
511 break;
512 }
513 #ifdef IKE_NAT_T
514 if (my->sa_family == p->addr->sa_family &&
515 my->sa_family == AF_INET &&
516 ((struct sockaddr_in*)my)->sin_addr.s_addr ==
517 ((struct sockaddr_in*)p->addr)->sin_addr.s_addr &&
518 ((struct sockaddr_in*)my)->sin_port == htons(PORT_ISAKMP_NATT))
519 {
520 plog(LLV_DEBUG, LOCATION, NULL,
521 "picked natt socket (%d - %s) for sending\n",
522 p->nattsock, saddr2str(my));
523 return p->nattsock;
524 }
525 #endif
526 }
527 if (!p)
528 p = lastresort;
529 if (!p) {
530 plog(LLV_ERROR, LOCATION, NULL,
531 "no socket matches address family %d\n",
532 my->sa_family);
533 return -1;
534 }
535
536 return p->sock;
537 }