]>
Commit | Line | Data |
---|---|---|
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> | |
40 | #if defined(__FreeBSD__) && __FreeBSD__ >= 3 | |
41 | #include <net/if_var.h> | |
42 | #endif | |
43 | #if defined(__NetBSD__) || defined(__FreeBSD__) || defined(__APPLE__) | |
44 | #include <netinet/in.h> | |
45 | #include <netinet6/in6_var.h> | |
46 | #endif | |
47 | #include <net/route.h> | |
48 | ||
49 | #include <stdlib.h> | |
50 | #include <stdio.h> | |
51 | #include <string.h> | |
52 | #include <errno.h> | |
53 | #ifdef HAVE_UNISTD_H | |
54 | #include <unistd.h> | |
55 | #endif | |
56 | #include <netdb.h> | |
57 | #ifdef HAVE_GETIFADDRS | |
58 | #include <ifaddrs.h> | |
59 | #include <net/if.h> | |
60 | #endif | |
61 | ||
62 | #include "var.h" | |
63 | #include "misc.h" | |
64 | #include "vmbuf.h" | |
65 | #include "plog.h" | |
66 | #include "sockmisc.h" | |
67 | #include "debug.h" | |
68 | ||
69 | #include "localconf.h" | |
70 | #include "handler.h" | |
71 | #include "grabmyaddr.h" | |
72 | #include "sockmisc.h" | |
73 | #include "isakmp_var.h" | |
74 | #include "gcmalloc.h" | |
75 | #include "nattraversal.h" | |
76 | ||
77 | #ifdef __linux__ | |
78 | #include <linux/types.h> | |
79 | #include <linux/rtnetlink.h> | |
80 | #ifndef HAVE_GETIFADDRS | |
81 | #define HAVE_GETIFADDRS | |
82 | #define NEED_LINUX_GETIFADDRS | |
83 | #endif | |
84 | #endif | |
85 | ||
86 | #ifndef HAVE_GETIFADDRS | |
87 | static unsigned int if_maxindex __P((void)); | |
88 | #endif | |
d1e348cf | 89 | |
52b7d2ce A |
90 | static int suitable_ifaddr __P((const char *, const struct sockaddr *)); |
91 | #ifdef INET6 | |
92 | static int suitable_ifaddr6 __P((const char *, const struct sockaddr *)); | |
93 | #endif | |
94 | ||
95 | #ifdef NEED_LINUX_GETIFADDRS | |
96 | ||
97 | /* We could do this _much_ better. kame racoon in its current form | |
98 | * will esentially die at frequent changes of address configuration. | |
99 | */ | |
100 | ||
101 | struct ifaddrs | |
102 | { | |
103 | struct ifaddrs *ifa_next; | |
104 | char ifa_name[16]; | |
105 | int ifa_ifindex; | |
106 | struct sockaddr *ifa_addr; | |
107 | struct sockaddr_storage ifa_addrbuf; | |
108 | }; | |
109 | ||
110 | static int parse_rtattr(struct rtattr *tb[], int max, struct rtattr *rta, int len) | |
111 | { | |
112 | while (RTA_OK(rta, len)) { | |
113 | if (rta->rta_type <= max) | |
114 | tb[rta->rta_type] = rta; | |
115 | rta = RTA_NEXT(rta,len); | |
116 | } | |
117 | return 0; | |
118 | } | |
119 | ||
120 | static void recvaddrs(int fd, struct ifaddrs **ifa, __u32 seq) | |
121 | { | |
122 | char buf[8192]; | |
123 | struct sockaddr_nl nladdr; | |
124 | struct iovec iov = { buf, sizeof(buf) }; | |
125 | struct ifaddrmsg *m; | |
126 | struct rtattr * rta_tb[IFA_MAX+1]; | |
127 | struct ifaddrs *I; | |
128 | ||
129 | while (1) { | |
130 | int status; | |
131 | struct nlmsghdr *h; | |
132 | ||
133 | struct msghdr msg = { | |
134 | (void*)&nladdr, sizeof(nladdr), | |
135 | &iov, 1, | |
136 | NULL, 0, | |
137 | 0 | |
138 | }; | |
139 | ||
140 | status = recvmsg(fd, &msg, 0); | |
141 | ||
142 | if (status < 0) | |
143 | continue; | |
144 | ||
145 | if (status == 0) | |
146 | return; | |
147 | ||
148 | if (nladdr.nl_pid) /* Message not from kernel */ | |
149 | continue; | |
150 | ||
151 | h = (struct nlmsghdr*)buf; | |
152 | while (NLMSG_OK(h, status)) { | |
153 | if (h->nlmsg_seq != seq) | |
154 | goto skip_it; | |
155 | ||
156 | if (h->nlmsg_type == NLMSG_DONE) | |
157 | return; | |
158 | ||
159 | if (h->nlmsg_type == NLMSG_ERROR) | |
160 | return; | |
161 | ||
162 | if (h->nlmsg_type != RTM_NEWADDR) | |
163 | goto skip_it; | |
164 | ||
165 | m = NLMSG_DATA(h); | |
166 | ||
167 | if (m->ifa_family != AF_INET && | |
168 | m->ifa_family != AF_INET6) | |
169 | goto skip_it; | |
170 | ||
171 | if (m->ifa_flags&IFA_F_TENTATIVE) | |
172 | goto skip_it; | |
173 | ||
174 | memset(rta_tb, 0, sizeof(rta_tb)); | |
175 | parse_rtattr(rta_tb, IFA_MAX, IFA_RTA(m), h->nlmsg_len - NLMSG_LENGTH(sizeof(*m))); | |
176 | ||
177 | if (rta_tb[IFA_LOCAL] == NULL) | |
178 | rta_tb[IFA_LOCAL] = rta_tb[IFA_ADDRESS]; | |
179 | if (rta_tb[IFA_LOCAL] == NULL) | |
180 | goto skip_it; | |
181 | ||
182 | I = malloc(sizeof(struct ifaddrs)); | |
183 | if (!I) | |
184 | return; | |
185 | memset(I, 0, sizeof(*I)); | |
186 | ||
187 | I->ifa_ifindex = m->ifa_index; | |
188 | I->ifa_addr = (struct sockaddr*)&I->ifa_addrbuf; | |
189 | I->ifa_addr->sa_family = m->ifa_family; | |
190 | if (m->ifa_family == AF_INET) { | |
191 | struct sockaddr_in *sin = (void*)I->ifa_addr; | |
192 | memcpy(&sin->sin_addr, RTA_DATA(rta_tb[IFA_LOCAL]), 4); | |
193 | } else { | |
194 | struct sockaddr_in6 *sin = (void*)I->ifa_addr; | |
195 | memcpy(&sin->sin6_addr, RTA_DATA(rta_tb[IFA_LOCAL]), 16); | |
196 | if (IN6_IS_ADDR_LINKLOCAL(&sin->sin6_addr)) | |
197 | sin->sin6_scope_id = I->ifa_ifindex; | |
198 | } | |
199 | I->ifa_next = *ifa; | |
200 | *ifa = I; | |
201 | ||
202 | skip_it: | |
203 | h = NLMSG_NEXT(h, status); | |
204 | } | |
205 | if (msg.msg_flags & MSG_TRUNC) | |
206 | continue; | |
207 | } | |
208 | return; | |
209 | } | |
210 | ||
211 | static int getifaddrs(struct ifaddrs **ifa0) | |
212 | { | |
213 | struct { | |
214 | struct nlmsghdr nlh; | |
215 | struct rtgenmsg g; | |
216 | } req; | |
217 | struct sockaddr_nl nladdr; | |
218 | static __u32 seq; | |
219 | struct ifaddrs *i; | |
220 | int fd; | |
221 | ||
222 | fd = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE); | |
223 | if (fd < 0) | |
224 | return -1; | |
225 | ||
226 | memset(&nladdr, 0, sizeof(nladdr)); | |
227 | nladdr.nl_family = AF_NETLINK; | |
228 | ||
229 | req.nlh.nlmsg_len = sizeof(req); | |
230 | req.nlh.nlmsg_type = RTM_GETADDR; | |
231 | req.nlh.nlmsg_flags = NLM_F_ROOT|NLM_F_MATCH|NLM_F_REQUEST; | |
232 | req.nlh.nlmsg_pid = 0; | |
233 | req.nlh.nlmsg_seq = ++seq; | |
234 | req.g.rtgen_family = AF_UNSPEC; | |
235 | ||
236 | if (sendto(fd, (void*)&req, sizeof(req), 0, (struct sockaddr*)&nladdr, sizeof(nladdr)) < 0) { | |
237 | close(fd); | |
238 | return -1; | |
239 | } | |
240 | ||
241 | *ifa0 = NULL; | |
242 | ||
243 | recvaddrs(fd, ifa0, seq); | |
244 | ||
245 | close(fd); | |
246 | ||
247 | fd = socket(AF_INET, SOCK_DGRAM, 0); | |
248 | ||
249 | for (i=*ifa0; i; i = i->ifa_next) { | |
250 | struct ifreq ifr; | |
251 | ifr.ifr_ifindex = i->ifa_ifindex; | |
252 | ioctl(fd, SIOCGIFNAME, (void*)&ifr); | |
253 | memcpy(i->ifa_name, ifr.ifr_name, 16); | |
254 | } | |
255 | close(fd); | |
256 | ||
257 | return 0; | |
258 | } | |
259 | ||
260 | static void freeifaddrs(struct ifaddrs *ifa0) | |
261 | { | |
262 | struct ifaddrs *i; | |
263 | ||
264 | while (ifa0) { | |
265 | i = ifa0; | |
266 | ifa0 = i->ifa_next; | |
267 | free(i); | |
268 | } | |
269 | } | |
270 | ||
271 | #endif | |
272 | ||
273 | #ifndef HAVE_GETIFADDRS | |
274 | static unsigned int | |
275 | if_maxindex() | |
276 | { | |
277 | struct if_nameindex *p, *p0; | |
278 | unsigned int max = 0; | |
279 | ||
280 | p0 = if_nameindex(); | |
281 | for (p = p0; p && p->if_index && p->if_name; p++) { | |
282 | if (max < p->if_index) | |
283 | max = p->if_index; | |
284 | } | |
285 | if_freenameindex(p0); | |
286 | return max; | |
287 | } | |
288 | #endif | |
289 | ||
290 | ||
291 | void | |
292 | clear_myaddr() | |
293 | { | |
294 | struct myaddrs *p, *next; | |
295 | ||
296 | for (p = lcconf->myaddrs; p; p = next) { | |
297 | next = p->next; | |
298 | ||
d1e348cf | 299 | delmyaddr(p); |
52b7d2ce A |
300 | } |
301 | ||
302 | lcconf->myaddrs = NULL; | |
303 | ||
304 | } | |
305 | ||
306 | ||
d1e348cf A |
307 | struct myaddrs * |
308 | find_myaddr(addr, udp_encap) | |
52b7d2ce A |
309 | struct sockaddr *addr; |
310 | int udp_encap; | |
311 | { | |
312 | struct myaddrs *q; | |
313 | char h1[NI_MAXHOST], h2[NI_MAXHOST]; | |
314 | ||
315 | if (getnameinfo(addr, sysdep_sa_len(addr), h1, sizeof(h1), NULL, 0, | |
316 | NI_NUMERICHOST | niflags) != 0) | |
317 | return NULL; | |
318 | ||
d1e348cf | 319 | for (q = lcconf->myaddrs; q; q = q->next) { |
52b7d2ce A |
320 | if (!q->addr) |
321 | continue; | |
322 | if (q->udp_encap && !udp_encap | |
323 | || !q->udp_encap && udp_encap) | |
324 | continue; | |
325 | if (addr->sa_family != q->addr->sa_family) | |
326 | continue; | |
327 | if (getnameinfo(q->addr, sysdep_sa_len(q->addr), h2, sizeof(h2), | |
328 | NULL, 0, NI_NUMERICHOST | niflags) != 0) | |
329 | return NULL; | |
330 | if (strcmp(h1, h2) == 0) | |
331 | return q; | |
332 | } | |
333 | ||
334 | return NULL; | |
335 | } | |
336 | ||
337 | ||
338 | // modified to avoid closing and opening sockets for | |
339 | // all interfaces each time an interface change occurs. | |
340 | // on return: addrcount = zero indicates address no longer used | |
341 | // sock = -1 indicates a new address - no socket opened yet. | |
342 | void | |
343 | grab_myaddrs() | |
344 | { | |
345 | #ifdef HAVE_GETIFADDRS | |
346 | struct myaddrs *p, *q; | |
347 | struct ifaddrs *ifa0, *ifap; | |
348 | #ifdef INET6 | |
349 | struct sockaddr_in6 *sin6; | |
350 | #endif | |
351 | ||
352 | char addr1[NI_MAXHOST]; | |
353 | ||
354 | if (getifaddrs(&ifa0)) { | |
355 | plog(LLV_ERROR2, LOCATION, NULL, | |
356 | "getifaddrs failed: %s\n", strerror(errno)); | |
357 | exit(1); | |
358 | /*NOTREACHED*/ | |
359 | } | |
360 | ||
361 | // clear the in_use flag for each address in the list | |
362 | for (p = lcconf->myaddrs; p; p = p->next) | |
363 | p->in_use = 0; | |
364 | ||
365 | for (ifap = ifa0; ifap; ifap = ifap->ifa_next) { | |
366 | ||
367 | if (ifap->ifa_addr->sa_family != AF_INET | |
368 | #ifdef INET6 | |
369 | && ifap->ifa_addr->sa_family != AF_INET6 | |
370 | #endif | |
371 | ) | |
372 | continue; | |
373 | ||
374 | if (!suitable_ifaddr(ifap->ifa_name, ifap->ifa_addr)) { | |
d1e348cf | 375 | plog(LLV_DEBUG2, LOCATION, NULL, |
52b7d2ce A |
376 | "unsuitable address: %s %s\n", |
377 | ifap->ifa_name, | |
378 | saddrwop2str(ifap->ifa_addr)); | |
379 | continue; | |
380 | } | |
381 | ||
d1e348cf | 382 | p = find_myaddr(ifap->ifa_addr, 0); |
52b7d2ce A |
383 | if (p) { |
384 | p->in_use = 1; | |
385 | #ifdef ENABLE_NATT | |
d1e348cf | 386 | q = find_myaddr(ifap->ifa_addr, 1); |
52b7d2ce A |
387 | if (q) |
388 | q->in_use = 1; | |
389 | #endif | |
390 | } else { | |
391 | p = newmyaddr(); | |
392 | if (p == NULL) { | |
393 | plog(LLV_ERROR2, LOCATION, NULL, | |
394 | "unable to allocate space for addr.\n"); | |
395 | exit(1); | |
396 | /*NOTREACHED*/ | |
397 | } | |
398 | p->addr = dupsaddr(ifap->ifa_addr); | |
399 | if (p->addr == NULL) { | |
400 | plog(LLV_ERROR2, LOCATION, NULL, | |
401 | "unable to duplicate addr.\n"); | |
402 | exit(1); | |
403 | /*NOTREACHED*/ | |
404 | } | |
d1e348cf A |
405 | p->ifname = racoon_strdup(ifap->ifa_name); |
406 | if (p->ifname == NULL) { | |
407 | plog(LLV_ERROR2, LOCATION, NULL, | |
408 | "unable to duplicate ifname.\n"); | |
409 | exit(1); | |
410 | /*NOTREACHED*/ | |
411 | } | |
412 | ||
52b7d2ce A |
413 | p->sock = -1; |
414 | p->in_use = 1; | |
415 | ||
416 | if (getnameinfo(p->addr, p->addr->sa_len, | |
417 | addr1, sizeof(addr1), | |
418 | NULL, 0, | |
419 | NI_NUMERICHOST | niflags)) | |
420 | strlcpy(addr1, "(invalid)", sizeof(addr1)); | |
421 | plog(LLV_DEBUG, LOCATION, NULL, | |
422 | "my interface: %s (%s)\n", | |
423 | addr1, ifap->ifa_name); | |
424 | ||
425 | p->next = lcconf->myaddrs; | |
426 | lcconf->myaddrs = p; | |
427 | ||
428 | #ifdef ENABLE_NATT | |
429 | if (natt_enabled_in_rmconf ()) { | |
430 | q = dupmyaddr(p); | |
431 | if (q == NULL) { | |
432 | plog(LLV_ERROR2, LOCATION, NULL, | |
433 | "unable to allocate space for natt addr.\n"); | |
434 | exit(1); | |
435 | } | |
436 | q->udp_encap = 1; | |
437 | } | |
438 | #endif | |
439 | ||
440 | } | |
441 | } | |
442 | ||
443 | freeifaddrs(ifa0); | |
444 | ||
445 | ||
446 | #else /*!HAVE_GETIFADDRS*/ | |
447 | #error "NOT SUPPORTED" | |
448 | #endif /*HAVE_GETIFADDRS*/ | |
449 | } | |
450 | ||
451 | ||
452 | /* | |
453 | * check the interface is suitable or not | |
454 | */ | |
455 | static int | |
456 | suitable_ifaddr(ifname, ifaddr) | |
457 | const char *ifname; | |
458 | const struct sockaddr *ifaddr; | |
459 | { | |
460 | #ifdef ENABLE_HYBRID | |
461 | /* Exclude any address we got through ISAKMP mode config */ | |
462 | if (exclude_cfg_addr(ifaddr) == 0) | |
463 | return 0; | |
464 | #endif | |
465 | switch(ifaddr->sa_family) { | |
466 | case AF_INET: | |
467 | return 1; | |
468 | #ifdef INET6 | |
469 | case AF_INET6: | |
470 | return suitable_ifaddr6(ifname, ifaddr); | |
471 | #endif | |
472 | default: | |
473 | return 0; | |
474 | } | |
475 | /*NOTREACHED*/ | |
476 | } | |
477 | ||
478 | #ifdef INET6 | |
479 | static int | |
480 | suitable_ifaddr6(ifname, ifaddr) | |
481 | const char *ifname; | |
482 | const struct sockaddr *ifaddr; | |
483 | { | |
484 | #ifndef __linux__ | |
485 | struct in6_ifreq ifr6; | |
486 | int s; | |
487 | #endif | |
488 | ||
489 | if (ifaddr->sa_family != AF_INET6) | |
490 | return 0; | |
491 | ||
492 | #ifndef __linux__ | |
493 | s = socket(PF_INET6, SOCK_DGRAM, 0); | |
494 | if (s == -1) { | |
495 | plog(LLV_ERROR, LOCATION, NULL, | |
496 | "socket(SOCK_DGRAM) failed:%s\n", strerror(errno)); | |
497 | return 0; | |
498 | } | |
499 | ||
500 | memset(&ifr6, 0, sizeof(ifr6)); | |
d1e348cf | 501 | strlcpy(ifr6.ifr_name, ifname, sizeof(ifr6.ifr_name)); |
52b7d2ce A |
502 | |
503 | ifr6.ifr_addr = *(const struct sockaddr_in6 *)ifaddr; | |
504 | ||
505 | if (ioctl(s, SIOCGIFAFLAG_IN6, &ifr6) < 0) { | |
506 | plog(LLV_ERROR, LOCATION, NULL, | |
507 | "ioctl(SIOCGIFAFLAG_IN6) failed:%s\n", strerror(errno)); | |
508 | close(s); | |
509 | return 0; | |
510 | } | |
511 | ||
512 | close(s); | |
513 | ||
514 | if (ifr6.ifr_ifru.ifru_flags6 & IN6_IFF_DUPLICATED | |
515 | || ifr6.ifr_ifru.ifru_flags6 & IN6_IFF_DETACHED | |
516 | || ifr6.ifr_ifru.ifru_flags6 & IN6_IFF_ANYCAST) | |
517 | return 0; | |
518 | #endif | |
519 | ||
520 | /* suitable */ | |
521 | return 1; | |
522 | } | |
523 | #endif | |
524 | ||
525 | int | |
526 | update_myaddrs() | |
527 | { | |
528 | #ifdef __linux__ | |
529 | char msg[BUFSIZ]; | |
530 | int len; | |
531 | struct nlmsghdr *h = (void*)msg; | |
532 | len = read(lcconf->rtsock, msg, sizeof(msg)); | |
533 | if (len < 0) | |
534 | return errno == ENOBUFS; | |
535 | if (len < sizeof(*h)) | |
536 | return 0; | |
537 | if (h->nlmsg_pid) /* not from kernel! */ | |
538 | return 0; | |
539 | if (h->nlmsg_type == RTM_NEWLINK) | |
540 | return 0; | |
541 | plog(LLV_DEBUG, LOCATION, NULL, | |
542 | "netlink signals update interface address list\n"); | |
543 | return 1; | |
544 | #else | |
545 | char msg[BUFSIZ]; | |
546 | int len; | |
547 | struct rt_msghdr *rtm; | |
548 | ||
549 | len = read(lcconf->rtsock, msg, sizeof(msg)); | |
550 | if (len < 0) { | |
551 | plog(LLV_ERROR, LOCATION, NULL, | |
552 | "read(PF_ROUTE) failed: %s\n", | |
553 | strerror(errno)); | |
554 | return 0; | |
555 | } | |
556 | rtm = (struct rt_msghdr *)msg; | |
557 | if (len < rtm->rtm_msglen) { | |
558 | plog(LLV_ERROR, LOCATION, NULL, | |
559 | "read(PF_ROUTE) short read\n"); | |
560 | return 0; | |
561 | } | |
562 | if (rtm->rtm_version != RTM_VERSION) { | |
563 | plog(LLV_ERROR, LOCATION, NULL, | |
564 | "routing socket version mismatch\n"); | |
565 | close(lcconf->rtsock); | |
566 | lcconf->rtsock = -1; | |
567 | return 0; | |
568 | } | |
569 | switch (rtm->rtm_type) { | |
570 | case RTM_NEWADDR: | |
571 | case RTM_DELADDR: | |
572 | case RTM_DELETE: | |
573 | case RTM_IFINFO: | |
574 | break; | |
575 | case RTM_MISS: | |
576 | /* ignore this message silently */ | |
577 | return 0; | |
578 | default: | |
579 | plog(LLV_DEBUG, LOCATION, NULL, | |
580 | "msg %d not interesting\n", rtm->rtm_type); | |
581 | return 0; | |
582 | } | |
583 | /* XXX more filters here? */ | |
584 | ||
585 | plog(LLV_DEBUG, LOCATION, NULL, | |
586 | "caught rtm:%d, need update interface address list\n", | |
587 | rtm->rtm_type); | |
588 | ||
589 | return 1; | |
590 | #endif /* __linux__ */ | |
591 | } | |
592 | ||
593 | /* | |
594 | * initialize default port for ISAKMP to send, if no "listen" | |
595 | * directive is specified in config file. | |
596 | * | |
597 | * DO NOT listen to wildcard addresses. if you receive packets to | |
598 | * wildcard address, you'll be in trouble (DoS attack possible by | |
599 | * broadcast storm). | |
600 | */ | |
601 | int | |
602 | autoconf_myaddrsport() | |
603 | { | |
604 | struct myaddrs *p; | |
605 | int n; | |
606 | ||
607 | plog(LLV_DEBUG, LOCATION, NULL, | |
608 | "configuring default isakmp port.\n"); | |
609 | ||
610 | for (p = lcconf->myaddrs, n = 0; p; p = p->next, n++) { | |
611 | set_port (p->addr, p->udp_encap ? lcconf->port_isakmp_natt : lcconf->port_isakmp); | |
612 | } | |
613 | plog(LLV_DEBUG, LOCATION, NULL, | |
614 | "%d addrs are configured successfully\n", n); | |
615 | ||
616 | return 0; | |
617 | } | |
618 | ||
619 | /* | |
620 | * get a port number to which racoon binded. | |
621 | * NOTE: network byte order returned. | |
622 | */ | |
623 | u_short | |
624 | getmyaddrsport(local) | |
625 | struct sockaddr *local; | |
626 | { | |
627 | struct myaddrs *p, *bestmatch = NULL; | |
628 | u_short bestmatch_port = PORT_ISAKMP; | |
629 | ||
630 | /* get a relative port */ | |
631 | for (p = lcconf->myaddrs; p; p = p->next) { | |
632 | if (!p->addr) | |
633 | continue; | |
634 | if (!cmpsaddrwop(local, p->addr)) { | |
635 | if (! bestmatch) { | |
636 | bestmatch = p; | |
637 | continue; | |
638 | } | |
639 | ||
640 | switch (p->addr->sa_family) { | |
641 | case AF_INET: | |
642 | if (((struct sockaddr_in *)p->addr)->sin_port == PORT_ISAKMP) { | |
643 | bestmatch = p; | |
644 | bestmatch_port = ((struct sockaddr_in *)p->addr)->sin_port; | |
645 | break; | |
646 | } | |
647 | break; | |
648 | #ifdef INET6 | |
649 | case AF_INET6: | |
650 | if (((struct sockaddr_in6 *)p->addr)->sin6_port == PORT_ISAKMP) { | |
651 | bestmatch = p; | |
652 | bestmatch_port = ((struct sockaddr_in6 *)p->addr)->sin6_port; | |
653 | break; | |
654 | } | |
655 | break; | |
656 | #endif | |
657 | default: | |
658 | plog(LLV_ERROR, LOCATION, NULL, | |
659 | "unsupported AF %d\n", p->addr->sa_family); | |
660 | continue; | |
661 | } | |
662 | } | |
663 | } | |
664 | ||
665 | return htons(bestmatch_port); | |
666 | } | |
667 | ||
668 | struct myaddrs * | |
669 | newmyaddr() | |
670 | { | |
671 | struct myaddrs *new; | |
672 | ||
673 | new = racoon_calloc(1, sizeof(*new)); | |
674 | if (new == NULL) { | |
675 | plog(LLV_ERROR, LOCATION, NULL, | |
676 | "failed to allocate buffer for myaddrs.\n"); | |
677 | return NULL; | |
678 | } | |
679 | ||
680 | new->next = NULL; | |
681 | new->addr = NULL; | |
d1e348cf A |
682 | #ifdef __APPLE_ |
683 | new->ifname = NULL; | |
684 | #endif | |
52b7d2ce A |
685 | |
686 | return new; | |
687 | } | |
688 | ||
689 | struct myaddrs * | |
690 | dupmyaddr(struct myaddrs *old) | |
691 | { | |
692 | struct myaddrs *new; | |
693 | ||
694 | new = racoon_calloc(1, sizeof(*new)); | |
695 | if (new == NULL) { | |
696 | plog(LLV_ERROR, LOCATION, NULL, | |
697 | "failed to allocate buffer for myaddrs.\n"); | |
698 | return NULL; | |
699 | } | |
700 | ||
701 | /* Copy the whole structure and set the differences. */ | |
702 | memcpy (new, old, sizeof (*new)); | |
703 | new->addr = dupsaddr (old->addr); | |
704 | if (new->addr == NULL) { | |
705 | plog(LLV_ERROR, LOCATION, NULL, | |
706 | "failed to allocate buffer for duplicate addr.\n"); | |
707 | racoon_free(new); | |
708 | return NULL; | |
709 | } | |
d1e348cf A |
710 | if (old->ifname) { |
711 | new->ifname = racoon_strdup(old->ifname); | |
712 | if (new->ifname == NULL) { | |
713 | plog(LLV_ERROR, LOCATION, NULL, | |
714 | "failed to allocate buffer for duplicate ifname.\n"); | |
715 | racoon_free(new->addr); | |
716 | racoon_free(new); | |
717 | return NULL; | |
718 | } | |
719 | } | |
720 | ||
52b7d2ce A |
721 | new->next = old->next; |
722 | old->next = new; | |
723 | ||
724 | return new; | |
725 | } | |
726 | ||
727 | void | |
728 | insmyaddr(new, head) | |
729 | struct myaddrs *new; | |
730 | struct myaddrs **head; | |
731 | { | |
732 | new->next = *head; | |
733 | *head = new; | |
734 | } | |
735 | ||
736 | void | |
737 | delmyaddr(myaddr) | |
738 | struct myaddrs *myaddr; | |
739 | { | |
740 | if (myaddr->addr) | |
741 | racoon_free(myaddr->addr); | |
d1e348cf A |
742 | #ifdef __APPLE__ |
743 | if (myaddr->ifname) | |
744 | racoon_free(myaddr->ifname); | |
745 | #endif | |
52b7d2ce A |
746 | racoon_free(myaddr); |
747 | } | |
748 | ||
749 | int | |
750 | initmyaddr() | |
751 | { | |
752 | /* initialize routing socket */ | |
753 | lcconf->rtsock = socket(PF_ROUTE, SOCK_RAW, PF_UNSPEC); | |
754 | if (lcconf->rtsock < 0) { | |
755 | plog(LLV_ERROR, LOCATION, NULL, | |
756 | "socket(PF_ROUTE) failed: %s", | |
757 | strerror(errno)); | |
758 | return -1; | |
759 | } | |
760 | ||
761 | #ifdef __linux__ | |
762 | { | |
763 | struct sockaddr_nl nl; | |
764 | u_int addr_len; | |
765 | ||
766 | memset(&nl, 0, sizeof(nl)); | |
767 | nl.nl_family = AF_NETLINK; | |
768 | nl.nl_groups = RTMGRP_IPV4_IFADDR|RTMGRP_LINK; | |
769 | ||
770 | if (bind(lcconf->rtsock, (struct sockaddr*)&nl, sizeof(nl)) < 0) { | |
771 | plog(LLV_ERROR, LOCATION, NULL, | |
772 | "bind(PF_NETLINK) failed: %s\n", | |
773 | strerror(errno)); | |
774 | return -1; | |
775 | } | |
776 | addr_len = sizeof(nl); | |
777 | if (getsockname(lcconf->rtsock, (struct sockaddr*)&nl, &addr_len) < 0) { | |
778 | plog(LLV_ERROR, LOCATION, NULL, | |
779 | "getsockname(PF_NETLINK) failed: %s\n", | |
780 | strerror(errno)); | |
781 | return -1; | |
782 | } | |
783 | } | |
784 | #endif | |
785 | ||
786 | if (lcconf->myaddrs == NULL && lcconf->autograbaddr == 1) { | |
787 | grab_myaddrs(); | |
788 | ||
789 | if (autoconf_myaddrsport() < 0) | |
790 | return -1; | |
791 | } | |
792 | ||
793 | return 0; | |
794 | } | |
795 | ||
796 | /* select the socket to be sent */ | |
797 | /* should implement other method. */ | |
798 | int | |
799 | getsockmyaddr(my) | |
800 | struct sockaddr *my; | |
801 | { | |
802 | struct myaddrs *p, *lastresort = NULL; | |
803 | #if defined(INET6) && defined(__linux__) | |
804 | struct myaddrs *match_wo_scope_id = NULL; | |
805 | int check_wo_scope_id = (my->sa_family == AF_INET6) && | |
806 | IN6_IS_ADDR_LINKLOCAL(&((struct sockaddr_in6 *)my)->sin6_addr); | |
807 | #endif | |
808 | ||
809 | for (p = lcconf->myaddrs; p; p = p->next) { | |
810 | if (p->addr == NULL) | |
811 | continue; | |
812 | if (my->sa_family == p->addr->sa_family) { | |
813 | lastresort = p; | |
814 | } else continue; | |
815 | if (sysdep_sa_len(my) == sysdep_sa_len(p->addr) | |
816 | && memcmp(my, p->addr, sysdep_sa_len(my)) == 0) { | |
817 | break; | |
818 | } | |
819 | #if defined(INET6) && defined(__linux__) | |
820 | if (check_wo_scope_id && IN6_IS_ADDR_LINKLOCAL(&((struct sockaddr_in6 *)p->addr)->sin6_addr) && | |
821 | /* XXX: this depends on sin6_scope_id to be last | |
822 | * item in struct sockaddr_in6 */ | |
823 | memcmp(my, p->addr, | |
824 | sysdep_sa_len(my) - sizeof(uint32_t)) == 0) { | |
825 | match_wo_scope_id = p; | |
826 | } | |
827 | #endif | |
828 | } | |
829 | #if defined(INET6) && defined(__linux__) | |
830 | if (!p) | |
831 | p = match_wo_scope_id; | |
832 | #endif | |
833 | if (!p) | |
834 | p = lastresort; | |
835 | if (!p) { | |
836 | plog(LLV_ERROR, LOCATION, NULL, | |
837 | "no socket matches address family %d\n", | |
838 | my->sa_family); | |
839 | return -1; | |
840 | } | |
841 | ||
842 | return p->sock; | |
843 | } |