]> git.saurik.com Git - apple/ipsec.git/blame - ipsec-tools/racoon/grabmyaddr.c
ipsec-93.8.tar.gz
[apple/ipsec.git] / ipsec-tools / racoon / grabmyaddr.c
CommitLineData
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
87static unsigned int if_maxindex __P((void));
88#endif
d1e348cf 89
52b7d2ce
A
90static int suitable_ifaddr __P((const char *, const struct sockaddr *));
91#ifdef INET6
92static 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
101struct 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
110static 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
120static 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
202skip_it:
203 h = NLMSG_NEXT(h, status);
204 }
205 if (msg.msg_flags & MSG_TRUNC)
206 continue;
207 }
208 return;
209}
210
211static 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
260static 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
274static unsigned int
275if_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
291void
292clear_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
307struct myaddrs *
308find_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.
342void
343grab_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 */
455static int
456suitable_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
479static int
480suitable_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
525int
526update_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 */
601int
602autoconf_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 */
623u_short
624getmyaddrsport(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
668struct myaddrs *
669newmyaddr()
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
689struct myaddrs *
690dupmyaddr(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
727void
728insmyaddr(new, head)
729 struct myaddrs *new;
730 struct myaddrs **head;
731{
732 new->next = *head;
733 *head = new;
734}
735
736void
737delmyaddr(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
749int
750initmyaddr()
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. */
798int
799getsockmyaddr(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}