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#include <net/if_var.h>
41#include <netinet/in.h>
42#include <netinet6/in6_var.h>
43#include <net/route.h>
44
45#include <stdlib.h>
46#include <stdio.h>
47#include <string.h>
48#include <errno.h>
49#ifdef HAVE_UNISTD_H
50#include <unistd.h>
51#endif
52#include <netdb.h>
53#ifdef HAVE_GETIFADDRS
54#include <ifaddrs.h>
55#include <net/if.h>
56#endif
57#include <fcntl.h>
58
59#include "var.h"
60#include "misc.h"
61#include "vmbuf.h"
62#include "plog.h"
63#include "sockmisc.h"
64#include "debug.h"
65
66#include "localconf.h"
67#include "handler.h"
68#include "grabmyaddr.h"
69#include "sockmisc.h"
70#include "isakmp_var.h"
71#include "gcmalloc.h"
72#include "nattraversal.h"
73
74#ifndef HAVE_GETIFADDRS
75static unsigned int if_maxindex (void);
76#endif
77
78static int suitable_ifaddr (const char *, const struct sockaddr *);
79#ifdef INET6
80static int suitable_ifaddr6 (const char *, const struct sockaddr *);
81#endif
82
83#ifndef HAVE_GETIFADDRS
84static unsigned int
85if_maxindex()
86{
87	struct if_nameindex *p, *p0;
88	unsigned int max = 0;
89
90	p0 = if_nameindex();
91	for (p = p0; p && p->if_index && p->if_name; p++) {
92		if (max < p->if_index)
93			max = p->if_index;
94	}
95	if_freenameindex(p0);
96	return max;
97}
98#endif
99
100
101void
102clear_myaddr()
103{
104	struct myaddrs *p, *next;
105
106	for (p = lcconf->myaddrs; p; p = next) {
107		next = p->next;
108
109		delmyaddr(p);
110	}
111
112	lcconf->myaddrs = NULL;
113
114}
115
116
117struct myaddrs *
118find_myaddr(addr, udp_encap)
119	struct sockaddr *addr;
120	int udp_encap;
121{
122	struct myaddrs *q;
123	char h1[NI_MAXHOST], h2[NI_MAXHOST];
124
125	if (getnameinfo(addr, sysdep_sa_len(addr), h1, sizeof(h1), NULL, 0,
126	    NI_NUMERICHOST | niflags) != 0)
127		return NULL;
128
129	for (q = lcconf->myaddrs; q; q = q->next) {
130		if (!q->addr)
131			continue;
132		if ((q->udp_encap && !udp_encap)
133			|| (!q->udp_encap && udp_encap))
134			continue;
135		if (addr->sa_family != q->addr->ss_family)
136			continue;
137		if (getnameinfo((struct sockaddr *)q->addr, sysdep_sa_len((struct sockaddr *)q->addr), h2, sizeof(h2),
138		    NULL, 0, NI_NUMERICHOST | niflags) != 0)
139			return NULL;
140		if (strcmp(h1, h2) == 0)
141			return q;
142	}
143
144	return NULL;
145}
146
147
148// modified to avoid closing and opening sockets for
149// all interfaces each time an interface change occurs.
150// on return: 	addrcount = zero indicates address no longer used
151//				sock = -1 indicates a new address - no socket opened yet.
152void
153grab_myaddrs()
154{
155	struct myaddrs *p, *q;
156	struct ifaddrs *ifa0, *ifap;
157
158	char addr1[NI_MAXHOST];
159
160	if (getifaddrs(&ifa0)) {
161		plog(ASL_LEVEL_ERR,
162			"getifaddrs failed: %s\n", strerror(errno));
163		exit(1);
164		/*NOTREACHED*/
165	}
166
167	// clear the in_use flag for each address in the list
168	for (p = lcconf->myaddrs; p; p = p->next)
169		p->in_use = 0;
170
171	for (ifap = ifa0; ifap; ifap = ifap->ifa_next) {
172
173		if (ifap->ifa_addr->sa_family != AF_INET
174#ifdef INET6
175		 && ifap->ifa_addr->sa_family != AF_INET6
176#endif
177		)
178			continue;
179
180		if (!suitable_ifaddr(ifap->ifa_name, ifap->ifa_addr)) {
181			plog(ASL_LEVEL_DEBUG,
182				"unsuitable address: %s %s\n",
183				ifap->ifa_name,
184				saddrwop2str(ifap->ifa_addr));
185			continue;
186		}
187
188		p = find_myaddr(ifap->ifa_addr, 0);
189		if (p) {
190			p->in_use = 1;
191#ifdef ENABLE_NATT
192			q = find_myaddr(ifap->ifa_addr, 1);
193			if (q)
194				q->in_use = 1;
195            else if (natt_enabled_in_rmconf ()) {
196				q = dupmyaddr(p);
197				if (q == NULL) {
198					plog(ASL_LEVEL_ERR,
199                         "unable to allocate space for natt addr.\n");
200					exit(1);
201				}
202				q->udp_encap = 1;
203			}
204#endif
205		} else {
206			p = newmyaddr();
207			if (p == NULL) {
208				plog(ASL_LEVEL_ERR,
209					"unable to allocate space for addr.\n");
210				exit(1);
211				/*NOTREACHED*/
212			}
213			p->addr = dupsaddr(ALIGNED_CAST(struct sockaddr_storage*)ifap->ifa_addr);
214			if (p->addr == NULL) {
215				plog(ASL_LEVEL_ERR,
216					"unable to duplicate addr.\n");
217				exit(1);
218				/*NOTREACHED*/
219			}
220			p->ifname = racoon_strdup(ifap->ifa_name);
221			if (p->ifname == NULL) {
222				plog(ASL_LEVEL_ERR,
223					"unable to duplicate ifname.\n");
224				exit(1);
225				/*NOTREACHED*/
226			}
227			p->in_use = 1;
228
229			if (getnameinfo((struct sockaddr *)p->addr, p->addr->ss_len,
230					addr1, sizeof(addr1),
231					NULL, 0,
232					NI_NUMERICHOST | niflags))
233				strlcpy(addr1, "(invalid)", sizeof(addr1));
234			plog(ASL_LEVEL_DEBUG,
235				"my interface: %s (%s)\n",
236				addr1, ifap->ifa_name);
237
238			p->next = lcconf->myaddrs;
239			lcconf->myaddrs = p;
240
241#ifdef ENABLE_NATT
242			if (natt_enabled_in_rmconf ()) {
243				q = dupmyaddr(p);
244				if (q == NULL) {
245					plog(ASL_LEVEL_ERR,
246						"unable to allocate space for natt addr.\n");
247					exit(1);
248				}
249				q->udp_encap = 1;
250			}
251#endif
252
253		}
254	}
255
256	freeifaddrs(ifa0);
257}
258
259
260/*
261 * check the interface is suitable or not
262 */
263static int
264suitable_ifaddr(ifname, ifaddr)
265	const char *ifname;
266	const struct sockaddr *ifaddr;
267{
268#if 0 //we need to be able to do nested ipsec for BTMM... stub out ifdef ENABLE_HYBRID
269	/* Exclude any address we got through ISAKMP mode config */
270	if (exclude_cfg_addr(ifaddr) == 0)
271		return 0;
272#endif
273	switch(ifaddr->sa_family) {
274	case AF_INET:
275		return 1;
276#ifdef INET6
277	case AF_INET6:
278		return suitable_ifaddr6(ifname, ifaddr);
279#endif
280	default:
281		return 0;
282	}
283	/*NOTREACHED*/
284}
285
286#ifdef INET6
287static int
288suitable_ifaddr6(ifname, ifaddr)
289	const char *ifname;
290	const struct sockaddr *ifaddr;
291{
292	struct in6_ifreq ifr6;
293	int s;
294
295	if (ifaddr->sa_family != AF_INET6)
296		return 0;
297
298	s = socket(PF_INET6, SOCK_DGRAM, 0);
299	if (s == -1) {
300		plog(ASL_LEVEL_ERR,
301			"socket(SOCK_DGRAM) failed:%s\n", strerror(errno));
302		return 0;
303	}
304
305    if (fcntl(s, F_SETFL, O_NONBLOCK) == -1) {
306		plog(ASL_LEVEL_ERR, "failed to put IPv6 socket in non-blocking mode\n");
307	}
308
309	memset(&ifr6, 0, sizeof(ifr6));
310	strlcpy(ifr6.ifr_name, ifname, sizeof(ifr6.ifr_name));
311
312	memcpy(&ifr6.ifr_addr, ifaddr, sizeof(struct sockaddr_in6));    // Wcast-align fix - copy instread of assign with cast
313
314	if (ioctl(s, SIOCGIFAFLAG_IN6, &ifr6) < 0) {
315		plog(ASL_LEVEL_ERR,
316			"ioctl(SIOCGIFAFLAG_IN6) failed:%s\n", strerror(errno));
317		close(s);
318		return 0;
319	}
320
321	close(s);
322
323	if (ifr6.ifr_ifru.ifru_flags6 & IN6_IFF_DUPLICATED
324	 || ifr6.ifr_ifru.ifru_flags6 & IN6_IFF_DETACHED
325	 || ifr6.ifr_ifru.ifru_flags6 & IN6_IFF_ANYCAST
326	 /* Deprecated addresses will now be dropped by isakmp_close_unused */
327	 || ifr6.ifr_ifru.ifru_flags6 & IN6_IFF_DEPRECATED)
328		return 0;
329
330	/* suitable */
331	return 1;
332}
333#endif
334
335
336/*
337 * initialize default port for ISAKMP to send, if no "listen"
338 * directive is specified in config file.
339 *
340 * DO NOT listen to wildcard addresses.  if you receive packets to
341 * wildcard address, you'll be in trouble (DoS attack possible by
342 * broadcast storm).
343 */
344int
345autoconf_myaddrsport()
346{
347	struct myaddrs *p;
348	int n;
349
350	plog(ASL_LEVEL_DEBUG,
351		"configuring default isakmp port.\n");
352
353	for (p = lcconf->myaddrs, n = 0; p; p = p->next, n++) {
354		set_port (p->addr, p->udp_encap ? lcconf->port_isakmp_natt : lcconf->port_isakmp);
355	}
356	plog(ASL_LEVEL_DEBUG,
357		"%d addrs are configured successfully\n", n);
358
359	return 0;
360}
361
362/*
363 * get a port number to which racoon binded.
364 * NOTE: network byte order returned.
365 */
366u_short
367getmyaddrsport(local)
368	struct sockaddr_storage *local;
369{
370	struct myaddrs *p, *bestmatch = NULL;
371	u_short bestmatch_port = PORT_ISAKMP;
372
373	/* get a relative port */
374	for (p = lcconf->myaddrs; p; p = p->next) {
375		if (!p->addr)
376			continue;
377		if (!cmpsaddrwop(local, p->addr)) {
378			if (! bestmatch) {
379				bestmatch = p;
380				continue;
381			}
382
383			switch (p->addr->ss_family) {
384			case AF_INET:
385				if (((struct sockaddr_in *)p->addr)->sin_port == PORT_ISAKMP) {
386					bestmatch = p;
387					bestmatch_port = ((struct sockaddr_in *)p->addr)->sin_port;
388					break;
389				}
390				break;
391#ifdef INET6
392			case AF_INET6:
393				if (((struct sockaddr_in6 *)p->addr)->sin6_port == PORT_ISAKMP) {
394					bestmatch = p;
395					bestmatch_port = ((struct sockaddr_in6 *)p->addr)->sin6_port;
396					break;
397				}
398				break;
399#endif
400			default:
401				plog(ASL_LEVEL_ERR,
402				     "unsupported AF %d\n", p->addr->ss_family);
403				continue;
404			}
405		}
406	}
407
408	return htons(bestmatch_port);
409}
410
411struct myaddrs *
412newmyaddr()
413{
414	struct myaddrs *new;
415
416	new = racoon_calloc(1, sizeof(*new));
417	if (new == NULL) {
418		plog(ASL_LEVEL_ERR,
419			"failed to allocate buffer for myaddrs.\n");
420		return NULL;
421	}
422
423	new->next = NULL;
424	new->addr = NULL;
425    new->source = NULL;
426    new->sock = -1;
427#ifdef __APPLE_
428	new->ifname = NULL;
429#endif
430
431	return new;
432}
433
434struct myaddrs *
435dupmyaddr(struct myaddrs *old)
436{
437	struct myaddrs *new;
438
439	new = racoon_calloc(1, sizeof(*new));
440	if (new == NULL) {
441		plog(ASL_LEVEL_ERR,
442			"failed to allocate buffer for myaddrs.\n");
443		return NULL;
444	}
445
446	/* Copy the whole structure and set the differences.  */
447	memcpy (new, old, sizeof (*new));
448	new->addr = dupsaddr (old->addr);
449	if (new->addr == NULL) {
450		plog(ASL_LEVEL_ERR,
451			"failed to allocate buffer for duplicate addr.\n");
452		racoon_free(new);
453		return NULL;
454	}
455	if (old->ifname) {
456		new->ifname = racoon_strdup(old->ifname);
457		if (new->ifname == NULL) {
458			plog(ASL_LEVEL_ERR,
459				"failed to allocate buffer for duplicate ifname.\n");
460			racoon_free(new->addr);
461			racoon_free(new);
462			return NULL;
463		}
464	}
465    new->source = NULL;
466    new->sock = -1;
467
468	new->next = old->next;
469	old->next = new;
470
471	return new;
472}
473
474void
475insmyaddr(new, head)
476	struct myaddrs *new;
477	struct myaddrs **head;
478{
479	new->next = *head;
480	*head = new;
481}
482
483void
484delmyaddr(myaddr)
485	struct myaddrs *myaddr;
486{
487	if (myaddr->addr)
488		racoon_free(myaddr->addr);
489	if (myaddr->ifname)
490		racoon_free(myaddr->ifname);
491	racoon_free(myaddr);
492}
493
494void
495update_myaddrs(void *unused)
496{
497    grab_myaddrs();
498    isakmp_close_unused();
499    autoconf_myaddrsport();
500    isakmp_open();
501}
502
503
504int
505initmyaddr(void)
506{
507
508	if (lcconf->myaddrs == NULL && lcconf->autograbaddr == 1) {
509		grab_myaddrs();
510
511		if (autoconf_myaddrsport() < 0)
512			return -1;
513	}
514
515	return 0;
516}
517
518
519/* select the socket to be sent */
520/* should implement other method. */
521int
522getsockmyaddr(struct sockaddr *my)
523{
524	struct myaddrs *p, *lastresort = NULL;
525
526	for (p = lcconf->myaddrs; p; p = p->next) {
527		if (p->addr == NULL)
528			continue;
529		if (my->sa_family == p->addr->ss_family) {
530			lastresort = p;
531		} else continue;
532		if (sysdep_sa_len(my) == sysdep_sa_len((struct sockaddr *)p->addr)
533		 && memcmp(my, p->addr, sysdep_sa_len(my)) == 0) {
534			break;
535		}
536	}
537	if (!p)
538		p = lastresort;
539	if (!p) {
540		plog(ASL_LEVEL_ERR,
541			"no socket matches address family %d\n",
542			my->sa_family);
543		return -1;
544	}
545
546	return p->sock;
547}
548
549void
550pfroute_handler(void *unused)
551{
552
553    struct rtmessage {          // Wcast-align fix - force alignment
554        struct rt_msghdr rtm;
555        char discard[BUFSIZ];
556    } msg;
557
558	int len;
559
560	while((len = read(lcconf->rtsock, &msg, sizeof(msg))) < 0) {
561		if (errno == EINTR)
562			continue;
563		plog(ASL_LEVEL_DEBUG,
564             "read(PF_ROUTE) failed: %s\n",
565             strerror(errno));
566		return;
567	}
568	if (len < msg.rtm.rtm_msglen) {
569		plog(ASL_LEVEL_DEBUG,
570             "read(PF_ROUTE) short read\n");
571		return;
572	}
573	switch (msg.rtm.rtm_type) {
574        case RTM_NEWADDR:
575        case RTM_DELADDR:
576        case RTM_DELETE:
577        case RTM_IFINFO:
578            break;
579        case RTM_MISS:
580            /* ignore this message silently */
581            return;
582        default:
583            //plog(ASL_LEVEL_DEBUG,
584            //     "msg %d not interesting\n", msg.rtm.rtm_type);
585            return;
586	}
587	/* XXX more filters here? */
588
589	plog(ASL_LEVEL_DEBUG,
590         "caught rtm:%d, need update interface address list\n",
591         msg.rtm.rtm_type);
592
593    // Interface changes occurred - update addrs
594    update_myaddrs(NULL);
595}
596
597void
598pfroute_close(void)
599{
600
601    dispatch_source_cancel(lcconf->rt_source);
602    lcconf->rt_source = NULL;
603}
604
605int
606pfroute_init(void)
607{
608    int sock;
609
610    /* initialize routing socket */
611    lcconf->rtsock = socket(PF_ROUTE, SOCK_RAW, PF_UNSPEC);
612    if (lcconf->rtsock < 0) {
613        plog(ASL_LEVEL_DEBUG,
614             "socket(PF_ROUTE) failed: %s",
615             strerror(errno));
616        return -1;
617    }
618    if (fcntl(lcconf->rtsock, F_SETFL, O_NONBLOCK) == -1) {
619		plog(ASL_LEVEL_DEBUG, "failed to put PF_ROUTE socket in non-blocking mode\n");
620	}
621
622    lcconf->rt_source = dispatch_source_create(DISPATCH_SOURCE_TYPE_READ, lcconf->rtsock, 0, dispatch_get_main_queue());
623    if (lcconf->rt_source == NULL) {
624        plog(ASL_LEVEL_DEBUG, "could not create pfroute socket source.");
625        return -1;
626    }
627    dispatch_source_set_event_handler_f(lcconf->rt_source, pfroute_handler);
628    sock = lcconf->rtsock;
629    dispatch_source_set_cancel_handler(lcconf->rt_source,
630                                         ^{
631                                             close(sock);
632                                         });
633    dispatch_resume(lcconf->rt_source);
634    return 0;
635}
636
637
638
639