Home | History | Annotate | Download | only in ninfod
      1 /* $USAGI: ninfod_addrs.c,v 1.18 2003-07-16 09:49:01 yoshfuji Exp $ */
      2 /*
      3  * Copyright (C) 2002 USAGI/WIDE Project.
      4  * All rights reserved.
      5  *
      6  * Redistribution and use in source and binary forms, with or without
      7  * modification, are permitted provided that the following conditions
      8  * are met:
      9  * 1. Redistributions of source code must retain the above copyright
     10  *    notice, this list of conditions and the following disclaimer.
     11  * 2. Redistributions in binary form must reproduce the above copyright
     12  *    notice, this list of conditions and the following disclaimer in the
     13  *    documentation and/or other materials provided with the distribution.
     14  * 3. Neither the name of the project nor the names of its contributors
     15  *    may be used to endorse or promote products derived from this software
     16  *    without specific prior written permission.
     17  *
     18  * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
     19  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     20  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     21  * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
     22  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     23  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     24  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     25  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     26  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     27  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     28  * SUCH DAMAGE.
     29  */
     30 /*
     31  * Author:
     32  * 	YOSHIFUJI Hideaki <yoshfuji (at) linux-ipv6.org>
     33  */
     34 
     35 #if HAVE_CONFIG_H
     36 #include "config.h"
     37 #endif
     38 
     39 #if HAVE_SYS_TYPES_H
     40 # include <sys/types.h>
     41 #endif
     42 
     43 #if STDC_HEADERS
     44 # include <stdio.h>
     45 # include <stdlib.h>
     46 # include <stddef.h>
     47 #else
     48 # if HAVE_STDLIB_H
     49 #  include <stdlib.h>
     50 # endif
     51 #endif
     52 #if HAVE_STRING_H
     53 # if !STDC_HEADERS && HAVE_MEMORY_H
     54 #  include <memory.h>
     55 # endif
     56 # include <string.h>
     57 #endif
     58 #if HAVE_STRINGS_H
     59 # include <strings.h>
     60 #endif
     61 #if HAVE_INTTYPES_H
     62 # include <inttypes.h>
     63 #else
     64 # if HAVE_STDINT_H
     65 #  include <stdint.h>
     66 # endif
     67 #endif
     68 #if HAVE_UNISTD_H
     69 # include <unistd.h>
     70 #endif
     71 
     72 #if TIME_WITH_SYS_TIME
     73 # include <sys/time.h>
     74 # include <time.h>
     75 #else
     76 # if HAVE_SYS_TIME_H
     77 #  include <sys/time.h>
     78 # else
     79 #  include <time.h>
     80 # endif
     81 #endif
     82 
     83 #if HAVE_SYS_UIO_H
     84 #include <sys/uio.h>
     85 #endif
     86 
     87 #include <sys/socket.h>
     88 #if HAVE_LINUX_RTNETLINK_H
     89 #include <asm/types.h>
     90 #include <linux/rtnetlink.h>
     91 #endif
     92 
     93 #if HAVE_NETINET_IN_H
     94 # include <netinet/in.h>
     95 #endif
     96 
     97 #if HAVE_NETINET_IP6_H
     98 # include <netinet/ip6.h>
     99 #endif
    100 
    101 #if HAVE_NETINET_ICMP6_H
    102 # include <netinet/icmp6.h>
    103 #endif
    104 #ifndef HAVE_STRUCT_ICMP6_NODEINFO
    105 # include "icmp6_nodeinfo.h"
    106 #endif
    107 
    108 #if HAVE_NETDB_H
    109 # include <netdb.h>
    110 #endif
    111 #include <errno.h>
    112 
    113 #if HAVE_SYSLOG_H
    114 # include <syslog.h>
    115 #endif
    116 
    117 #include "ninfod.h"
    118 #include "ni_ifaddrs.h"
    119 
    120 #ifndef offsetof
    121 # define offsetof(aggregate,member)	((size_t)&((aggregate *)0)->member)
    122 #endif
    123 
    124 /* ---------- */
    125 /* ID */
    126 static char *RCSID __attribute__ ((unused)) = "$USAGI: ninfod_addrs.c,v 1.18 2003-07-16 09:49:01 yoshfuji Exp $";
    127 
    128 /* ---------- */
    129 /* ipv6 address */
    130 void init_nodeinfo_ipv6addr(INIT_ARGS)
    131 {
    132 	DEBUG(LOG_DEBUG, "%s()\n", __func__);
    133 	return;
    134 }
    135 
    136 int filter_ipv6addr(const struct in6_addr *ifaddr, unsigned int flags)
    137 {
    138 	if (IN6_IS_ADDR_UNSPECIFIED(ifaddr) ||
    139 	    IN6_IS_ADDR_LOOPBACK(ifaddr)) {
    140 		return 1;
    141 	} else if (IN6_IS_ADDR_V4COMPAT(ifaddr) ||
    142 		   IN6_IS_ADDR_V4MAPPED(ifaddr)) {
    143 		return !(flags & NI_NODEADDR_FLAG_COMPAT);
    144 	} else if (IN6_IS_ADDR_LINKLOCAL(ifaddr)) {
    145 		return !(flags & NI_NODEADDR_FLAG_LINKLOCAL);
    146 	} else if (IN6_IS_ADDR_SITELOCAL(ifaddr)) {
    147 		return !(flags & NI_NODEADDR_FLAG_SITELOCAL);
    148 	}
    149 	return !(flags & NI_NODEADDR_FLAG_GLOBAL);
    150 }
    151 
    152 int pr_nodeinfo_ipv6addr(CHECKANDFILL_ARGS)
    153 {
    154 	struct ni_ifaddrs *ifa0;
    155 	unsigned int ifindex = 0;
    156 
    157 	DEBUG(LOG_DEBUG, "%s()\n", __func__);
    158 
    159 	if (subject && subjlen != sizeof(struct in6_addr)) {
    160 		DEBUG(LOG_INFO,
    161 		      "%s(): invalid subject length %zu for IPv6 Address Subject\n",
    162 		      __func__, subjlen);
    163 		return 1;
    164 	}
    165 	if (ni_ifaddrs(&ifa0, AF_INET6))
    166 		return -1;	/* failed to get addresses */
    167 
    168 	/* pass 0: consider subject and determine subjected interface */
    169 	if (subject) {
    170 		struct ni_ifaddrs *ifa;
    171 
    172 		for (ifa = ifa0; ifa; ifa = ifa->ifa_next) {
    173 			if (!ifa->ifa_addr)
    174 				continue;
    175 			if (ifa->ifa_flags & (IFA_F_TENTATIVE|IFA_F_SECONDARY))
    176 				continue;
    177 			if (!ifindex &&
    178 			    IN6_ARE_ADDR_EQUAL(&p->pktinfo.ipi6_addr,
    179 					       (struct in6_addr *)subject)) {
    180 				/*
    181 				 * if subject is equal to destination
    182 				 * address, receiving interface is
    183 				 * the candidate subject interface.
    184 				 */
    185 				ifindex = p->pktinfo.ipi6_ifindex;
    186 			}
    187 			if (!IN6_IS_ADDR_LOOPBACK((struct in6_addr *)subject) &&
    188 			    IN6_ARE_ADDR_EQUAL((struct in6_addr *)ifa->ifa_addr,
    189 					       (struct in6_addr *)subject)) {
    190 				/*
    191 				 * address is assigned on some interface.
    192 				 * if multiple interfaces have the same interface,
    193 				 *  1) prefer receiving interface
    194 				 *  2) use first found one
    195 				 */
    196 				if (!ifindex ||
    197 				    (p->pktinfo.ipi6_ifindex == ifindex))
    198 					ifindex = ifa->ifa_ifindex;
    199 			}
    200 		}
    201 		if (!ifindex) {
    202 			ni_freeifaddrs(ifa0);
    203 			return 1;	/* subject not found */
    204 		}
    205 		if (subj_if)
    206 			*subj_if = ifindex;
    207 	} else {
    208 		ifindex = subj_if ? *subj_if : 0;
    209 		if (ifindex == 0)
    210 			ifindex = p->pktinfo.ipi6_ifindex;
    211 		if (ifindex == 0) {
    212 			ni_freeifaddrs(ifa0);
    213 			return 1;	/* XXX */
    214 		}
    215 	}
    216 
    217 	if (reply) {
    218 		struct ni_ifaddrs *ifa;
    219 		unsigned int addrs0 = 0, paddrs0 = 0;
    220 		unsigned int addrs, paddrs = 0, daddrs = 0;
    221 
    222 		flags &= ~NI_NODEADDR_FLAG_TRUNCATE;
    223 
    224 		/* pass 1: count addresses and preferred addresses to be returned */
    225 		for (ifa = ifa0; ifa; ifa = ifa->ifa_next) {
    226 			if (!ifa->ifa_addr)
    227 				continue;
    228 			if (ifa->ifa_flags & (IFA_F_TENTATIVE|IFA_F_SECONDARY))
    229 				continue;
    230 			if (!(flags & NI_NODEADDR_FLAG_ALL) &&
    231 			    ifa->ifa_ifindex != ifindex)
    232 				continue;
    233 			if (filter_ipv6addr((struct in6_addr *)ifa->ifa_addr, flags))
    234 				continue;
    235 
    236 			if (addrs0 + 1 >= ((MAX_REPLY_SIZE - sizeof(struct icmp6_nodeinfo)) / (sizeof(uint32_t) + sizeof(struct in6_addr)))) {
    237 				flags |= ~NI_NODEADDR_FLAG_TRUNCATE;
    238 				break;
    239 			}
    240 
    241 			addrs0++;
    242 			if (!(ifa->ifa_flags & IFA_F_DEPRECATED))
    243 				paddrs0++;
    244 		}
    245 
    246 		p->reply.ni_type = ICMP6_NI_REPLY;
    247 		p->reply.ni_code = ICMP6_NI_SUCCESS;
    248 		p->reply.ni_cksum = 0;
    249 		p->reply.ni_qtype = htons(NI_QTYPE_NODEADDR);
    250 		p->reply.ni_flags = flags&(NI_NODEADDR_FLAG_COMPAT|
    251 					   NI_NODEADDR_FLAG_LINKLOCAL|
    252 					   NI_NODEADDR_FLAG_SITELOCAL|
    253 					   NI_NODEADDR_FLAG_GLOBAL);
    254 
    255 		/* pass 2: store addresses */
    256 		p->replydatalen = (sizeof(uint32_t)+sizeof(struct in6_addr)) * addrs0;
    257 		p->replydata = p->replydatalen ? ni_malloc(p->replydatalen) : NULL;
    258 
    259 		if (p->replydatalen && !p->replydata) {
    260 			p->reply.ni_flags |= NI_NODEADDR_FLAG_TRUNCATE;
    261 			addrs0 = paddrs0 = 0;
    262 		}
    263 
    264 		for (ifa = ifa0, addrs = 0;
    265 		     ifa && addrs < addrs0;
    266 		     ifa = ifa->ifa_next) {
    267 			char *cp;
    268 			uint32_t ttl;
    269 
    270 			if (!ifa->ifa_addr)
    271 				continue;
    272 			if (ifa->ifa_flags & (IFA_F_TENTATIVE|IFA_F_SECONDARY))
    273 				continue;
    274 			if (!(flags & NI_NODEADDR_FLAG_ALL) &&
    275 			    ((subj_if && *subj_if) ? (ifa->ifa_ifindex != *subj_if) :
    276 						     (ifa->ifa_ifindex != p->pktinfo.ipi6_ifindex)))
    277 				continue;
    278 			if (filter_ipv6addr((struct in6_addr *)ifa->ifa_addr, flags))
    279 				continue;
    280 
    281 #if ENABLE_TTL
    282 			if (ifa->ifa_cacheinfo) {
    283 				ttl = ifa->ifa_cacheinfo->ifa_valid > 0x7fffffff ?
    284 				      htonl(0x7fffffff) : htonl(ifa->ifa_cacheinfo->ifa_valid);
    285 			} else {
    286 				ttl = (ifa->ifa_flags & IFA_F_PERMANENT) ? htonl(0x7fffffff) : 0;
    287 			}
    288 #else
    289 			ttl = 0;
    290 #endif
    291 
    292 			cp = p->replydata +
    293 			     (sizeof(uint32_t)+sizeof(struct in6_addr)) * (ifa->ifa_flags & IFA_F_DEPRECATED ? paddrs0+daddrs : paddrs);
    294 			memcpy(cp, &ttl, sizeof(ttl));
    295 			memcpy(cp + sizeof(ttl), ifa->ifa_addr, sizeof(struct in6_addr));
    296 
    297 			addrs++;
    298 			if (ifa->ifa_flags & IFA_F_DEPRECATED)
    299 				daddrs++;
    300 			else
    301 				paddrs++;
    302 		}
    303 	}
    304 
    305 	ni_freeifaddrs(ifa0);
    306 	return 0;
    307 }
    308 
    309 /* ipv4 address */
    310 void init_nodeinfo_ipv4addr(INIT_ARGS)
    311 {
    312 	DEBUG(LOG_DEBUG, "%s()\n", __func__);
    313 	return;
    314 }
    315 
    316 int filter_ipv4addr(const struct in_addr *ifaddr, unsigned int flags)
    317 {
    318 	return 0;
    319 }
    320 
    321 int pr_nodeinfo_ipv4addr(CHECKANDFILL_ARGS)
    322 {
    323 	struct ni_ifaddrs *ifa0;
    324 	unsigned int ifindex = 0;
    325 
    326 	DEBUG(LOG_DEBUG, "%s()\n", __func__);
    327 
    328 	if (subject && subjlen != sizeof(struct in_addr)) {
    329 		DEBUG(LOG_INFO,
    330 		      "%s(): invalid subject length %zu for IPv4 Address Subject\n",
    331 		      __func__, subjlen);
    332 		return 1;
    333 	}
    334 	if (ni_ifaddrs(&ifa0, AF_INET))
    335 		return -1;	/* failed to get addresses */
    336 
    337 	/* pass 0: consider subject and determine subjected interface */
    338 	if (subject) {
    339 		struct ni_ifaddrs *ifa;
    340 
    341 		for (ifa = ifa0; ifa; ifa = ifa->ifa_next) {
    342 			if (!ifa->ifa_addr)
    343 				continue;
    344 			if (ifa->ifa_flags & (IFA_F_TENTATIVE|IFA_F_SECONDARY))
    345 				continue;
    346 			if ((((struct in_addr *)subject)->s_addr != htonl(INADDR_LOOPBACK)) &&
    347 			    memcmp((struct in_addr *)ifa->ifa_addr,
    348 				   (struct in_addr *)subject,
    349 				   sizeof(struct in_addr)) == 0) {
    350 				/*
    351 				 * address is assigned on some interface.
    352 				 * if multiple interfaces have the same interface,
    353 				 *  1) prefer receiving interface
    354 				 *  2) use first found one
    355 				 */
    356 				if (!ifindex ||
    357 				    (p->pktinfo.ipi6_ifindex == ifindex))
    358 					ifindex = ifa->ifa_ifindex;
    359 			}
    360 		}
    361 		if (!ifindex) {
    362 			ni_freeifaddrs(ifa0);
    363 			return 1;	/* subject not found */
    364 		}
    365 		if (subj_if)
    366 			*subj_if = ifindex;
    367 	} else {
    368 		ifindex = subj_if ? *subj_if : 0;
    369 		if (ifindex == 0)
    370 			ifindex = p->pktinfo.ipi6_ifindex;
    371 		if (ifindex == 0) {
    372 			ni_freeifaddrs(ifa0);
    373 			return 1;	/* XXX */
    374 		}
    375 	}
    376 
    377 	if (reply) {
    378 		struct ni_ifaddrs *ifa;
    379 		unsigned int addrs0 = 0, paddrs0 = 0;
    380 		unsigned int addrs, paddrs = 0, daddrs = 0;
    381 
    382 		flags &= ~NI_IPV4ADDR_FLAG_TRUNCATE;
    383 
    384 		/* pass 1: count addresses and preferred addresses to be returned */
    385 		for (ifa = ifa0; ifa; ifa = ifa->ifa_next) {
    386 			if (!ifa->ifa_addr)
    387 				continue;
    388 #if 1	/* not used in kernel */
    389 			if (ifa->ifa_flags & (IFA_F_TENTATIVE))
    390 				continue;
    391 #endif
    392 			if (!(flags & NI_NODEADDR_FLAG_ALL) &&
    393 			    ((subj_if && *subj_if) ? (ifa->ifa_ifindex != *subj_if) :
    394 						     (ifa->ifa_ifindex != p->pktinfo.ipi6_ifindex)))
    395 				continue;
    396 			if (filter_ipv4addr((struct in_addr *)ifa->ifa_addr, flags))
    397 				continue;
    398 
    399 			if (addrs0 + 1 >= ((MAX_REPLY_SIZE - sizeof(struct icmp6_nodeinfo)) / (sizeof(uint32_t) + sizeof(struct in_addr)))) {
    400 				flags |= NI_IPV4ADDR_FLAG_TRUNCATE;
    401 				break;
    402 			}
    403 
    404 			addrs0++;
    405 			if (!(ifa->ifa_flags & IFA_F_DEPRECATED))
    406 				paddrs0++;
    407 		}
    408 
    409 		p->reply.ni_type = ICMP6_NI_REPLY;
    410 		p->reply.ni_code = ICMP6_NI_SUCCESS;
    411 		p->reply.ni_cksum = 0;
    412 		p->reply.ni_qtype = htons(NI_QTYPE_IPV4ADDR);
    413 		p->reply.ni_flags = flags & NI_IPV4ADDR_FLAG_ALL;
    414 
    415 		/* pass 2: store addresses */
    416 		p->replydatalen = (sizeof(uint32_t)+sizeof(struct in_addr)) * addrs0;
    417 		p->replydata = addrs0 ? ni_malloc(p->replydatalen) : NULL;
    418 
    419 		if (p->replydatalen && !p->replydata) {
    420 			p->reply.ni_flags |= NI_NODEADDR_FLAG_TRUNCATE;
    421 			addrs0 = paddrs0 = 0;
    422 		}
    423 
    424 		for (ifa = ifa0, addrs = 0;
    425 		     ifa && addrs < addrs0;
    426 		     ifa = ifa->ifa_next) {
    427 			char *cp;
    428 			uint32_t ttl;
    429 
    430 			if (!ifa->ifa_addr)
    431 				continue;
    432 #if 1	/* not used in kernel */
    433 			if (ifa->ifa_flags & (IFA_F_TENTATIVE))
    434 				continue;
    435 #endif
    436 			if (!(flags & NI_NODEADDR_FLAG_ALL) &&
    437 			    (ifa->ifa_ifindex != ifindex))
    438 				continue;
    439 			if (filter_ipv4addr((struct in_addr *)ifa->ifa_addr, flags))
    440 				continue;
    441 
    442 #if ENABLE_TTL
    443 			if (ifa->ifa_cacheinfo) {
    444 				ttl = ifa->ifa_cacheinfo->ifa_valid > 0x7fffffff ?
    445 				      htonl(0x7fffffff) : htonl(ifa->ifa_cacheinfo->ifa_valid);
    446 			} else {
    447 				ttl = 0;	/*XXX*/
    448 			}
    449 #else
    450 			ttl = 0;
    451 #endif
    452 
    453 			cp = (p->replydata +
    454 			      (sizeof(uint32_t)+sizeof(struct in_addr)) * (ifa->ifa_flags & IFA_F_DEPRECATED ? paddrs0+daddrs : paddrs));
    455 			memcpy(cp, &ttl, sizeof(ttl));
    456 			memcpy(cp + sizeof(ttl), ifa->ifa_addr, sizeof(struct in_addr));
    457 
    458 			addrs++;
    459 			if (ifa->ifa_flags & IFA_F_DEPRECATED)
    460 				daddrs++;
    461 			else
    462 				paddrs++;
    463 		}
    464 	}
    465 
    466 	ni_freeifaddrs(ifa0);
    467 	return 0;
    468 }
    469 
    470