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