ninfod_addrs.c revision 313379eb6b9da55f7371adef39a92153a0707d4a
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@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 */ 126static char *RCSID __attribute__ ((unused)) = "$USAGI: ninfod_addrs.c,v 1.18 2003-07-16 09:49:01 yoshfuji Exp $"; 127 128/* ---------- */ 129/* ipv6 address */ 130void init_nodeinfo_ipv6addr(INIT_ARGS) 131{ 132 DEBUG(LOG_DEBUG, "%s()\n", __func__); 133 return; 134} 135 136int 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 152int 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 */ 310void init_nodeinfo_ipv4addr(INIT_ARGS) 311{ 312 DEBUG(LOG_DEBUG, "%s()\n", __func__); 313 return; 314} 315 316int filter_ipv4addr(const struct in_addr *ifaddr, unsigned int flags) 317{ 318 return 0; 319} 320 321int 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