1 /* $USAGI: ninfod_core.c,v 1.29 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 #if STDC_HEADERS 43 # include <stdio.h> 44 # include <stdlib.h> 45 # include <stddef.h> 46 #else 47 # if HAVE_STDLIB_H 48 # include <stdlib.h> 49 # endif 50 #endif 51 #if ENABLE_THREADS && HAVE_PTHREAD_H 52 # include <pthread.h> 53 #endif 54 #if HAVE_STRING_H 55 # if !STDC_HEADERS && HAVE_MEMORY_H 56 # include <memory.h> 57 # endif 58 # include <string.h> 59 #endif 60 #if HAVE_STRINGS_H 61 # include <strings.h> 62 #endif 63 #if HAVE_INTTYPES_H 64 # include <inttypes.h> 65 #else 66 # if HAVE_STDINT_H 67 # include <stdint.h> 68 # endif 69 #endif 70 #if HAVE_UNISTD_H 71 # include <unistd.h> 72 #endif 73 74 #if TIME_WITH_SYS_TIME 75 # include <sys/time.h> 76 # include <time.h> 77 #else 78 # if HAVE_SYS_TIME_H 79 # include <sys/time.h> 80 # else 81 # include <time.h> 82 # endif 83 #endif 84 85 #if HAVE_SYS_UIO_H 86 #include <sys/uio.h> 87 #endif 88 89 #if HAVE_NETINET_IN_H 90 # include <netinet/in.h> 91 #endif 92 93 #if HAVE_NETINET_ICMP6_H 94 # include <netinet/icmp6.h> 95 #endif 96 #ifndef HAVE_STRUCT_ICMP6_NODEINFO 97 # include "icmp6_nodeinfo.h" 98 #endif 99 100 #if HAVE_NETDB_H 101 # include <netdb.h> 102 #endif 103 #include <errno.h> 104 105 #if HAVE_SYSLOG_H 106 # include <syslog.h> 107 #endif 108 109 #include "ninfod.h" 110 111 #ifndef offsetof 112 # define offsetof(aggregate,member) ((size_t)&((aggregate *)0)->member) 113 #endif 114 115 #define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0])) 116 117 /* ---------- */ 118 /* ID */ 119 static char *RCSID __attribute__ ((unused)) = "$USAGI: ninfod_core.c,v 1.29 2003-07-16 09:49:01 yoshfuji Exp $"; 120 121 /* Variables */ 122 int initialized = 0; 123 124 #if ENABLE_THREADS && HAVE_LIBPTHREAD 125 pthread_attr_t pattr; 126 #endif 127 128 static uint32_t suptypes[(MAX_SUPTYPES+31)>>5]; 129 static size_t suptypes_len; 130 131 /* ---------- */ 132 struct subjinfo { 133 uint8_t code; 134 char *name; 135 int (*checksubj)(CHECKANDFILL_ARGS); 136 int (*init)(INIT_ARGS); 137 }; 138 139 static struct subjinfo subjinfo_table [] = { 140 [ICMP6_NI_SUBJ_IPV6] = { 141 .code = ICMP6_NI_SUBJ_IPV6, 142 .name = "IPv6", 143 //.init = init_nodeinfo_ipv6addr, 144 .checksubj = pr_nodeinfo_ipv6addr, 145 }, 146 [ICMP6_NI_SUBJ_FQDN] = { 147 .code = ICMP6_NI_SUBJ_FQDN, 148 .name = "FQDN", 149 //.init = init_nodeinfo_nodename, 150 .checksubj = pr_nodeinfo_nodename, 151 }, 152 [ICMP6_NI_SUBJ_IPV4] = { 153 .code = ICMP6_NI_SUBJ_IPV4, 154 .name = "IPv4", 155 //.init = init_nodeinfo_ipv4addr, 156 .checksubj = pr_nodeinfo_ipv4addr, 157 }, 158 }; 159 160 static struct subjinfo subjinfo_null = { 161 .name = "null", 162 .checksubj = pr_nodeinfo_noop, 163 }; 164 165 static __inline__ struct subjinfo *subjinfo_lookup(int code) 166 { 167 if (code >= ARRAY_SIZE(subjinfo_table)) 168 return NULL; 169 if (subjinfo_table[code].name == NULL) 170 return NULL; 171 return &subjinfo_table[code]; 172 } 173 174 /* ---------- */ 175 #define QTYPEINFO_F_RATELIMIT 0x1 176 177 struct qtypeinfo { 178 uint16_t qtype; 179 char *name; 180 int (*getreply)(CHECKANDFILL_ARGS); 181 void (*init)(INIT_ARGS); 182 int flags; 183 }; 184 185 static struct qtypeinfo qtypeinfo_table[] = { 186 [NI_QTYPE_NOOP] = { 187 .qtype = NI_QTYPE_NOOP, 188 .name = "NOOP", 189 .getreply = pr_nodeinfo_noop, 190 }, 191 #if ENABLE_SUPTYPES 192 [NI_QTYPE_SUPTYPES] = { 193 .qtype = NI_QTYPE_SUPTYPES, 194 .name = "SupTypes", 195 .getreply = pr_nodeinfo_suptypes, 196 .init = init_nodeinfo_suptypes, 197 }, 198 #endif 199 [NI_QTYPE_DNSNAME] = { 200 .qtype = NI_QTYPE_DNSNAME, 201 .name = "DnsName", 202 .getreply = pr_nodeinfo_nodename, 203 .init = init_nodeinfo_nodename, 204 }, 205 [NI_QTYPE_NODEADDR] = { 206 .qtype = NI_QTYPE_NODEADDR, 207 .name = "NodeAddr", 208 .getreply = pr_nodeinfo_ipv6addr, 209 .init = init_nodeinfo_ipv6addr, 210 }, 211 [NI_QTYPE_IPV4ADDR] = { 212 .qtype = NI_QTYPE_IPV4ADDR, 213 .name = "IPv4Addr", 214 .getreply = pr_nodeinfo_ipv4addr, 215 .init = init_nodeinfo_ipv4addr, 216 }, 217 }; 218 219 static struct qtypeinfo qtypeinfo_unknown = { 220 .name = "unknown", 221 .getreply = pr_nodeinfo_unknown, 222 .flags = QTYPEINFO_F_RATELIMIT, 223 }; 224 225 static struct qtypeinfo qtypeinfo_refused = { 226 .name = "refused", 227 .getreply = pr_nodeinfo_refused, 228 .flags = QTYPEINFO_F_RATELIMIT, 229 }; 230 231 static __inline__ struct qtypeinfo *qtypeinfo_lookup(int qtype) 232 { 233 if (qtype >= ARRAY_SIZE(qtypeinfo_table)) 234 return &qtypeinfo_unknown; 235 if (qtypeinfo_table[qtype].name == NULL) 236 return &qtypeinfo_unknown; 237 return &qtypeinfo_table[qtype]; 238 } 239 240 /* ---------- */ 241 /* noop */ 242 int pr_nodeinfo_noop(CHECKANDFILL_ARGS) 243 { 244 DEBUG(LOG_DEBUG, "%s()\n", __func__); 245 246 if (subjlen) { 247 DEBUG(LOG_WARNING, 248 "%s(): invalid subject length(%zu)\n", 249 __func__, subjlen); 250 return 1; 251 } 252 253 if (reply) { 254 p->reply.ni_type = ICMP6_NI_REPLY; 255 p->reply.ni_code = ICMP6_NI_SUCCESS; 256 p->reply.ni_cksum = 0; 257 p->reply.ni_qtype = htons(NI_QTYPE_NOOP); 258 p->reply.ni_flags = flags; 259 } 260 261 if (subj_if) 262 *subj_if = 0; 263 264 return 0; 265 } 266 267 #if ENABLE_SUPTYPES 268 /* suptypes */ 269 int pr_nodeinfo_suptypes(CHECKANDFILL_ARGS) 270 { 271 DEBUG(LOG_DEBUG, "%s()\n", __func__); 272 273 if (subjlen) { 274 DEBUG(LOG_WARNING, "%s(): invalid subject length(%zu)\n", 275 __func__, subjlen); 276 return 1; 277 } 278 279 if (reply) { 280 p->reply.ni_type = ICMP6_NI_REPLY; 281 p->reply.ni_code = ICMP6_NI_SUCCESS; 282 p->reply.ni_cksum = 0; 283 p->reply.ni_qtype = htons(NI_QTYPE_SUPTYPES); 284 p->reply.ni_flags = flags&~NI_SUPTYPE_FLAG_COMPRESS; 285 286 p->replydatalen = suptypes_len<<2; 287 p->replydata = ni_malloc(p->replydatalen); 288 if (p->replydata == NULL) { 289 p->replydatalen = -1; 290 return -1; /*XXX*/ 291 } 292 293 memcpy(p->replydata, suptypes, p->replydatalen); 294 } 295 return 0; 296 } 297 298 void init_nodeinfo_suptypes(INIT_ARGS) 299 { 300 size_t w, b; 301 int i; 302 303 if (!forced && initialized) 304 return; 305 306 memset(suptypes, 0, sizeof(suptypes)); 307 suptypes_len = 0; 308 309 for (i=0; i < ARRAY_SIZE(qtypeinfo_table); i++) { 310 unsigned short qtype; 311 312 if (qtypeinfo_table[i].name == NULL) 313 continue; 314 qtype = qtypeinfo_table[i].qtype; 315 w = qtype>>5; 316 b = qtype&0x1f; 317 if (w >= ARRAY_SIZE(suptypes)) { 318 /* This is programming error. */ 319 DEBUG(LOG_ERR, "Warning: Too Large Supported Types\n"); 320 exit(1); 321 } 322 suptypes[w] |= htonl(1<<b); 323 324 if (suptypes_len < w) 325 suptypes_len = w; 326 } 327 suptypes_len++; 328 } 329 #endif 330 331 /* ---------- */ 332 /* unknown qtype response */ 333 int pr_nodeinfo_unknown(CHECKANDFILL_ARGS) 334 { 335 if (!reply) 336 return -1; /*???*/ 337 338 p->reply.ni_type = ICMP6_NI_REPLY; 339 p->reply.ni_code = ICMP6_NI_UNKNOWN; 340 p->reply.ni_cksum = 0; 341 //p->reply.ni_qtype = 0; 342 p->reply.ni_flags = flags; 343 344 p->replydata = NULL; 345 p->replydatalen = 0; 346 347 return 0; 348 } 349 350 /* refused response */ 351 int pr_nodeinfo_refused(CHECKANDFILL_ARGS) 352 { 353 if (!reply) 354 return -1; /*???*/ 355 356 p->reply.ni_type = ICMP6_NI_REPLY; 357 p->reply.ni_code = ICMP6_NI_REFUSED; 358 p->reply.ni_cksum = 0; 359 //p->reply.ni_qtype = 0; 360 p->reply.ni_flags = flags; 361 362 p->replydata = NULL; 363 p->replydatalen = 0; 364 365 return 0; 366 } 367 368 /* ---------- */ 369 /* Policy */ 370 static int ni_policy(struct packetcontext *p) 371 { 372 const struct in6_addr *saddr = &((const struct sockaddr_in6 *)&p->addr)->sin6_addr; 373 374 /* 375 * >0: reply 376 * 0: refused 377 * <0: discard 378 */ 379 380 /* Default policy is to refuse queries from 381 * non-local addresses; loopback, link-local or 382 * site-local are okay 383 */ 384 if (!(IN6_IS_ADDR_LINKLOCAL(saddr) || 385 IN6_IS_ADDR_SITELOCAL(saddr) || 386 IN6_IS_ADDR_LOOPBACK(saddr))) 387 return 0; 388 return 1; 389 } 390 391 /* ---------- */ 392 void init_core(int forced) 393 { 394 int i; 395 396 DEBUG(LOG_DEBUG, "%s()\n", __func__); 397 398 if (!initialized || forced) { 399 struct timeval tv; 400 unsigned int seed = 0; 401 pid_t pid; 402 403 if (gettimeofday(&tv, NULL) < 0) { 404 DEBUG(LOG_WARNING, "%s(): failed to gettimeofday()\n", __func__); 405 } else { 406 seed = (tv.tv_usec & 0xffffffff); 407 } 408 409 pid = getpid(); 410 seed ^= (((unsigned long)pid) & 0xffffffff); 411 412 srand(seed); 413 414 #if ENABLE_THREADS && HAVE_LIBPTHREAD 415 if (initialized) 416 pthread_attr_destroy(&pattr); 417 418 pthread_attr_init(&pattr); 419 pthread_attr_setdetachstate(&pattr, PTHREAD_CREATE_DETACHED); 420 #endif 421 } 422 423 for (i=0; i < ARRAY_SIZE(subjinfo_table); i++) { 424 if (subjinfo_table[i].name == NULL) 425 continue; 426 if (subjinfo_table[i].init) 427 subjinfo_table[i].init(forced); 428 } 429 430 for (i=0; i < ARRAY_SIZE(qtypeinfo_table); i++) { 431 if (qtypeinfo_table[i].name == NULL) 432 continue; 433 if (qtypeinfo_table[i].init) 434 qtypeinfo_table[i].init(forced); 435 } 436 437 initialized = 1; 438 439 return; 440 } 441 442 #if ENABLE_THREADS && HAVE_LIBPTHREAD 443 static void *ni_send_thread(void *data) 444 { 445 int ret; 446 DEBUG(LOG_DEBUG, "%s(): thread=%ld\n", __func__, pthread_self()); 447 ret = ni_send(data); 448 DEBUG(LOG_DEBUG, "%s(): thread=%ld => %d\n", __func__, pthread_self(), ret); 449 return NULL; 450 } 451 #else 452 static int ni_send_fork(struct packetcontext *p) 453 { 454 pid_t child = fork(); 455 if (child < 0) 456 return -1; 457 if (child == 0) { 458 pid_t grandchild = fork(); 459 if (grandchild < 0) 460 exit(1); 461 if (grandchild == 0) { 462 int ret; 463 DEBUG(LOG_DEBUG, "%s(): worker=%d\n", 464 __func__, getpid()); 465 ret = ni_send(p); 466 DEBUG(LOG_DEBUG, "%s(): worker=%d => %d\n", 467 __func__, getpid(), ret); 468 exit(ret > 0 ? 1 : 0); 469 } 470 ni_free(p->replydata); 471 ni_free(p); 472 exit(0); 473 } else { 474 waitpid(child, NULL, 0); 475 ni_free(p->replydata); 476 ni_free(p); 477 } 478 return 0; 479 } 480 #endif 481 482 static int ni_ratelimit(void) 483 { 484 static struct timeval last; 485 struct timeval tv, sub; 486 487 if (gettimeofday(&tv, NULL) < 0) { 488 DEBUG(LOG_WARNING, "%s(): gettimeofday(): %s\n", 489 __func__, strerror(errno)); 490 return -1; 491 } 492 493 if (!timerisset(&last)) { 494 last = tv; 495 return 0; 496 } 497 498 timersub(&tv, &last, &sub); 499 500 if (sub.tv_sec < 1) 501 return 1; 502 503 last = tv; 504 return 0; 505 } 506 507 int pr_nodeinfo(struct packetcontext *p) 508 { 509 struct icmp6_nodeinfo *query = (struct icmp6_nodeinfo *)p->query; 510 511 char *subject = (char *)(query + 1); 512 size_t subjlen; 513 struct subjinfo *subjinfo; 514 struct qtypeinfo *qtypeinfo; 515 int replyonsubjcheck = 0; 516 unsigned int subj_if; 517 #if ENABLE_DEBUG 518 char printbuf[128]; 519 int i; 520 char *cp; 521 #endif 522 #if ENABLE_THREADS && HAVE_PTHREAD_H 523 pthread_t thread; 524 #endif 525 int rc; 526 527 /* Step 0: Check destination address 528 * discard non-linklocal multicast 529 * discard non-nigroup multicast address(?) 530 */ 531 if (IN6_IS_ADDR_MULTICAST(&p->pktinfo.ipi6_addr)) { 532 if (!IN6_IS_ADDR_MC_LINKLOCAL(&p->pktinfo.ipi6_addr)) { 533 DEBUG(LOG_WARNING, 534 "Destination is non-link-local multicast address.\n"); 535 ni_free(p); 536 return -1; 537 } 538 #if 0 539 /* Do not discard NI Queries to multicast address 540 * other than its own NI Group Address(es) by default. 541 */ 542 if (!check_nigroup(&p->pktinfo.ipi6_addr)) { 543 DEBUG(LOG_WARNING, 544 "Destination is link-local multicast address other than " 545 "NI Group address.\n"); 546 ni_free(p); 547 return -1; 548 } 549 #endif 550 } 551 552 /* Step 1: Check length */ 553 if (p->querylen < sizeof(struct icmp6_nodeinfo)) { 554 DEBUG(LOG_WARNING, "Query too short\n"); 555 ni_free(p); 556 return -1; 557 } 558 559 #if ENABLE_DEBUG 560 cp = printbuf; 561 for (i = 0; i < sizeof(query->icmp6_ni_nonce); i++) { 562 cp += sprintf(cp, " %02x", query->icmp6_ni_nonce[i]); 563 } 564 DEBUG(LOG_DEBUG, "%s(): qtype=%d, flags=0x%04x, nonce[] = {%s }\n", 565 __func__, 566 ntohs(query->ni_qtype), ntohs(query->ni_flags), printbuf); 567 #endif 568 569 subjlen = p->querylen - sizeof(struct icmp6_nodeinfo); 570 571 /* Step 2: Check Subject Code */ 572 switch(htons(query->ni_qtype)) { 573 case NI_QTYPE_NOOP: 574 case NI_QTYPE_SUPTYPES: 575 if (query->ni_code != ICMP6_NI_SUBJ_FQDN) { 576 DEBUG(LOG_WARNING, 577 "%s(): invalid/unknown code %u\n", 578 __func__, query->ni_code); 579 subjlen = 0; 580 } 581 subjinfo = &subjinfo_null; 582 break; 583 default: 584 subjinfo = subjinfo_lookup(query->ni_code); 585 if (!subjinfo) { 586 DEBUG(LOG_WARNING, 587 "%s(): unknown code %u\n", 588 __func__, query->ni_code); 589 ni_free(p); 590 return -1; 591 } 592 } 593 594 /* Step 3: Lookup Qtype */ 595 qtypeinfo = qtypeinfo_lookup(ntohs(query->ni_qtype)); 596 597 /* Step 4: Check Subject 598 * (And fill reply if it is available now) 599 */ 600 if (qtypeinfo->getreply == subjinfo->checksubj) 601 replyonsubjcheck = 1; 602 603 if (subjinfo->checksubj(p, 604 subject, subjlen, 605 query->ni_flags, 606 replyonsubjcheck ? NULL : &subj_if, 607 replyonsubjcheck)) { 608 if (p->replydatalen < 0) { 609 DEBUG(LOG_WARNING, 610 "failed to make reply: %s\n", 611 strerror(errno)); 612 } 613 ni_free(p); 614 return -1; 615 } 616 617 /* XXX: Step 5: Check the policy */ 618 rc = ni_policy(p); 619 if (rc <= 0) { 620 ni_free(p->replydata); 621 p->replydata = NULL; 622 p->replydatalen = 0; 623 if (rc < 0) { 624 DEBUG(LOG_WARNING, "Ignored by policy.\n"); 625 ni_free(p); 626 return -1; 627 } 628 DEBUG(LOG_WARNING, "Refused by policy.\n"); 629 replyonsubjcheck = 0; 630 qtypeinfo = &qtypeinfo_refused; 631 } 632 633 /* Step 6: Fill the reply if not yet done */ 634 if (!replyonsubjcheck) { 635 if (qtypeinfo->getreply(p, 636 NULL, 0, 637 query->ni_flags, 638 &subj_if, 639 1)) { 640 if (p->replydatalen) { 641 DEBUG(LOG_WARNING, 642 "failed to make reply: %s\n", 643 strerror(errno)); 644 } 645 ni_free(p); 646 return -1; 647 } 648 } 649 650 /* Step 7: Rate Limit */ 651 if (qtypeinfo->flags&QTYPEINFO_F_RATELIMIT && 652 ni_ratelimit()) { 653 ni_free(p->replydata); 654 ni_free(p); 655 return -1; 656 } 657 658 /* Step 8: Fill Qtype / Nonce */ 659 p->reply.ni_qtype = query->ni_qtype; 660 memcpy(p->reply.icmp6_ni_nonce, query->icmp6_ni_nonce, sizeof(p->reply.icmp6_ni_nonce)); 661 662 /* Step 9: Source address selection */ 663 if (IN6_IS_ADDR_MULTICAST(&p->pktinfo.ipi6_addr)) { 664 /* if query was sent to multicast address, 665 * use source address selection in kernel. 666 * XXX: anycast? 667 */ 668 memset(&p->pktinfo.ipi6_addr, 0, sizeof(p->pktinfo.ipi6_addr)); 669 670 /* Random Delay between zero and MAX_ANYCAST_DELAY_TIME is 671 * required if query was sent to anycast or multicast address. 672 */ 673 p->delay = (int) (MAX_ANYCAST_DELAY_TIME*rand()/(RAND_MAX+1.0)); 674 } else { 675 p->delay = 0; 676 } 677 678 /* Step 10: Send the reply 679 * XXX: with possible random delay */ 680 #if ENABLE_THREADS && HAVE_LIBPTHREAD 681 /* ni_send_thread() frees p */ 682 if (pthread_create(&thread, &pattr, ni_send_thread, p)) { 683 ni_free(p->replydata); 684 ni_free(p); 685 return -1; 686 } 687 #else 688 /* ni_send_fork() frees p */ 689 if (ni_send_fork(p)) { 690 ni_free(p->replydata); 691 ni_free(p); 692 return -1; 693 } 694 #endif 695 696 return 0; 697 } 698 699