1 /* $KAME: rrenumd.c,v 1.20 2000/11/08 02:40:53 itojun 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 * $FreeBSD: src/usr.sbin/rrenumd/rrenumd.c,v 1.1.2.4 2001/07/09 09:49:49 ume Exp $ 32 * $DragonFly: src/usr.sbin/rrenumd/rrenumd.c,v 1.3 2003/11/03 19:31:42 eirikn Exp $ 33 */ 34 35 #include <sys/param.h> 36 #include <sys/socket.h> 37 #include <sys/uio.h> 38 #include <sys/time.h> 39 40 #include <string.h> 41 42 #include <net/route.h> 43 44 #include <netinet/in_systm.h> 45 #include <netinet/in.h> 46 #include <netinet/ip.h> 47 #include <netinet/ip6.h> 48 #include <netinet/icmp6.h> 49 50 #include <arpa/inet.h> 51 52 #ifdef IPSEC 53 #include <netinet6/ipsec.h> 54 #endif 55 56 #include <stdio.h> 57 #include <err.h> 58 #include <errno.h> 59 #include <stdlib.h> 60 #include <unistd.h> 61 #include <syslog.h> 62 63 #include "rrenumd.h" 64 65 #define LL_ALLROUTERS "ff02::2" 66 #define SL_ALLROUTERS "ff05::2" 67 68 #define RR_MCHLIM_DEFAULT 64 69 70 #ifndef IN6_IS_SCOPE_LINKLOCAL 71 #define IN6_IS_SCOPE_LINKLOCAL(a) \ 72 ((IN6_IS_ADDR_LINKLOCAL(a)) || \ 73 (IN6_IS_ADDR_MC_LINKLOCAL(a))) 74 #endif /* IN6_IS_SCOPE_LINKLOCAL */ 75 76 struct flags { 77 u_long debug : 1; 78 u_long fg : 1; 79 #ifdef IPSEC 80 #ifdef IPSEC_POLICY_IPSEC 81 u_long policy : 1; 82 #else /* IPSEC_POLICY_IPSEC */ 83 u_long auth : 1; 84 u_long encrypt : 1; 85 #endif /* IPSEC_POLICY_IPSEC */ 86 #endif /*IPSEC*/ 87 }; 88 89 struct msghdr sndmhdr; 90 struct msghdr rcvmhdr; 91 struct sockaddr_in6 from; 92 struct sockaddr_in6 sin6_ll_allrouters; 93 94 int s4, s6; 95 int with_v4dest, with_v6dest; 96 struct in6_addr prefix; /* ADHOC */ 97 int prefixlen = 64; /* ADHOC */ 98 99 extern int parse(FILE **); 100 101 static void show_usage(void); 102 static void init_sin6(struct sockaddr_in6 *, const char *); 103 #if 0 104 static void join_multi(const char *); 105 #endif 106 static void init_globals(void); 107 static void config(FILE **); 108 #ifdef IPSEC_POLICY_IPSEC 109 static void sock6_open(struct flags *, char *); 110 static void sock4_open(struct flags *, char *); 111 #else 112 static void sock6_open(struct flags *); 113 static void sock4_open(struct flags *); 114 #endif 115 static void rrenum_output(struct payload_list *, struct dst_list *); 116 static void rrenum_snd_eachdst(struct payload_list *); 117 #if 0 118 static void rrenum_snd_fullsequence(void); 119 #endif 120 static void rrenum_input(int); 121 int main(int, char *[]); 122 123 124 /* Print usage. Don't call this after daemonized. */ 125 static void 126 show_usage() 127 { 128 fprintf(stderr, "usage: rrenumd [-c conf_file|-s] [-df" 129 #ifdef IPSEC 130 #ifdef IPSEC_POLICY_IPSEC 131 "] [-P policy" 132 #else /* IPSEC_POLICY_IPSEC */ 133 "AE" 134 #endif /* IPSEC_POLICY_IPSEC */ 135 #endif /* IPSEC */ 136 "]\n"); 137 exit(1); 138 } 139 140 static void 141 init_sin6(struct sockaddr_in6 *sin6, const char *addr_ascii) 142 { 143 memset(sin6, 0, sizeof(*sin6)); 144 sin6->sin6_len = sizeof(*sin6); 145 sin6->sin6_family = AF_INET6; 146 if (inet_pton(AF_INET6, addr_ascii, &sin6->sin6_addr) != 1) 147 ; /* XXX do something */ 148 } 149 150 #if 0 /* XXX: not necessary ?? */ 151 static void 152 join_multi(const char *addrname) 153 { 154 struct ipv6_mreq mreq; 155 156 if (inet_pton(AF_INET6, addrname, &mreq.ipv6mr_multiaddr.s6_addr) 157 != 1) { 158 syslog(LOG_ERR, "<%s> inet_pton failed(library bug?)", 159 __FUNCTION__); 160 exit(1); 161 } 162 /* ADHOC: currently join only one */ 163 { 164 if ((mreq.ipv6mr_interface = if_nametoindex(ifname)) == 0) { 165 syslog(LOG_ERR, "<%s> ifname %s should be invalid: %s", 166 __FUNCTION__, ifname, strerror(errno)); 167 exit(1); 168 } 169 if (setsockopt(s, IPPROTO_IPV6, IPV6_JOIN_GROUP, 170 &mreq, 171 sizeof(mreq)) < 0) { 172 syslog(LOG_ERR, "<%s> IPV6_JOIN_GROUP on %s: %s", 173 __FUNCTION__, ifname, strerror(errno)); 174 exit(1); 175 } 176 } 177 } 178 #endif 179 180 static void 181 init_globals() 182 { 183 static struct iovec rcviov; 184 static u_char rprdata[4500]; /* maximal MTU of connected links */ 185 static u_char *rcvcmsgbuf = NULL; 186 static u_char *sndcmsgbuf = NULL; 187 int sndcmsglen, rcvcmsglen; 188 189 /* init ll_allrouters */ 190 init_sin6(&sin6_ll_allrouters, LL_ALLROUTERS); 191 192 /* initialize msghdr for receiving packets */ 193 rcviov.iov_base = (caddr_t)rprdata; 194 rcviov.iov_len = sizeof(rprdata); 195 rcvmhdr.msg_namelen = sizeof(struct sockaddr_in6); 196 rcvmhdr.msg_iov = &rcviov; 197 rcvmhdr.msg_iovlen = 1; 198 rcvcmsglen = CMSG_SPACE(sizeof(struct in6_pktinfo)) + 199 CMSG_SPACE(sizeof(int)); 200 if (rcvcmsgbuf == NULL && 201 (rcvcmsgbuf = (u_char *)malloc(rcvcmsglen)) == NULL) { 202 syslog(LOG_ERR, "<%s>: malloc failed", __FUNCTION__); 203 exit(1); 204 } 205 rcvmhdr.msg_control = (caddr_t)rcvcmsgbuf; 206 rcvmhdr.msg_controllen = rcvcmsglen; 207 208 /* initialize msghdr for sending packets */ 209 sndmhdr.msg_namelen = sizeof(struct sockaddr_in6); 210 sndmhdr.msg_iovlen = 1; 211 sndcmsglen = CMSG_SPACE(sizeof(struct in6_pktinfo)) + 212 CMSG_SPACE(sizeof(int)); 213 if (sndcmsgbuf == NULL && 214 (sndcmsgbuf = (u_char *)malloc(sndcmsglen)) == NULL) { 215 syslog(LOG_ERR, "<%s>: malloc failed", __FUNCTION__); 216 exit(1); 217 } 218 sndmhdr.msg_control = (caddr_t)sndcmsgbuf; 219 sndmhdr.msg_controllen = sndcmsglen; 220 } 221 222 static void 223 config(FILE **fpp) 224 { 225 struct payload_list *pl; 226 struct iovec *iov; 227 struct icmp6_router_renum *irr; 228 struct rr_pco_match *rpm; 229 230 if (parse(fpp) < 0) { 231 syslog(LOG_ERR, "<%s> parse failed", __FUNCTION__); 232 exit(1); 233 } 234 235 /* initialize fields not configured by parser */ 236 for (pl = pl_head; pl; pl = pl->pl_next) { 237 iov = (struct iovec *)&pl->pl_sndiov; 238 irr = (struct icmp6_router_renum *)&pl->pl_irr; 239 rpm = (struct rr_pco_match *)&pl->pl_rpm; 240 241 irr->rr_type = ICMP6_ROUTER_RENUMBERING; 242 irr->rr_code = 0; 243 /* 244 * now we don't support multiple PCOs in a rr message. 245 * so segment number is not supported. 246 */ 247 /* TODO: rr flags config in parser */ 248 irr->rr_flags |= ICMP6_RR_FLAGS_SPECSITE; 249 /* TODO: max delay config in parser */ 250 251 /* 252 * means only 1 use_prefix is contained as router-renum-05.txt. 253 * now we don't support multiple PCOs in a rr message, 254 * nor multiple use_prefix in one PCO. 255 */ 256 rpm->rpm_len = 4*1 +3; 257 rpm->rpm_ordinal = 0; 258 iov->iov_base = (caddr_t)irr; 259 iov->iov_len = sizeof(struct icmp6_router_renum) 260 + sizeof(struct rr_pco_match) 261 + sizeof(struct rr_pco_use); 262 } 263 } 264 265 static void 266 sock6_open(struct flags *flags 267 #ifdef IPSEC_POLICY_IPSEC 268 , char *policy 269 #endif /* IPSEC_POLICY_IPSEC */ 270 ) 271 { 272 struct icmp6_filter filt; 273 int on; 274 #ifdef IPSEC 275 #ifndef IPSEC_POLICY_IPSEC 276 int optval; 277 #endif 278 #endif 279 280 if (with_v6dest == 0) 281 return; 282 if (with_v6dest && 283 (s6 = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6)) < 0) { 284 syslog(LOG_ERR, "<%s> socket(v6): %s", __FUNCTION__, 285 strerror(errno)); 286 exit(1); 287 } 288 289 /* 290 * join all routers multicast addresses. 291 */ 292 #if 0 /* XXX: not necessary ?? */ 293 join_multi(LL_ALLROUTERS); 294 join_multi(SL_ALLROUTERS); 295 #endif 296 297 /* set icmpv6 filter */ 298 ICMP6_FILTER_SETBLOCKALL(&filt); 299 ICMP6_FILTER_SETPASS(ICMP6_ROUTER_RENUMBERING, &filt); 300 if (setsockopt(s6, IPPROTO_ICMPV6, ICMP6_FILTER, &filt, 301 sizeof(filt)) < 0) { 302 syslog(LOG_ERR, "<%s> IICMP6_FILTER: %s", 303 __FUNCTION__, strerror(errno)); 304 exit(1); 305 } 306 307 /* specify to tell receiving interface */ 308 on = 1; 309 if (setsockopt(s6, IPPROTO_IPV6, IPV6_PKTINFO, &on, 310 sizeof(on)) < 0) { 311 syslog(LOG_ERR, "<%s> IPV6_PKTINFO: %s", 312 __FUNCTION__, strerror(errno)); 313 exit(1); 314 } 315 316 #ifdef IPSEC 317 #ifdef IPSEC_POLICY_IPSEC 318 if (flags->policy) { 319 char *buf; 320 buf = ipsec_set_policy(policy, strlen(policy)); 321 if (buf == NULL) 322 errx(1, "%s", ipsec_strerror()); 323 /* XXX should handle in/out bound policy. */ 324 if (setsockopt(s6, IPPROTO_IPV6, IPV6_IPSEC_POLICY, 325 buf, ipsec_get_policylen(buf)) < 0) 326 err(1, "setsockopt(IPV6_IPSEC_POLICY)"); 327 free(buf); 328 } 329 #else /* IPSEC_POLICY_IPSEC */ 330 if (flags->auth) { 331 optval = IPSEC_LEVEL_REQUIRE; 332 if (setsockopt(s6, IPPROTO_IPV6, IPV6_AUTH_TRANS_LEVEL, 333 &optval, sizeof(optval)) == -1) { 334 syslog(LOG_ERR, "<%s> IPV6_AUTH_TRANS_LEVEL: %s", 335 __FUNCTION__, strerror(errno)); 336 exit(1); 337 } 338 } 339 if (flags->encrypt) { 340 optval = IPSEC_LEVEL_REQUIRE; 341 if (setsockopt(s6, IPPROTO_IPV6, IPV6_ESP_TRANS_LEVEL, 342 &optval, sizeof(optval)) == -1) { 343 syslog(LOG_ERR, "<%s> IPV6_ESP_TRANS_LEVEL: %s", 344 __FUNCTION__, strerror(errno)); 345 exit(1); 346 } 347 } 348 #endif /* IPSEC_POLICY_IPSEC */ 349 #endif /* IPSEC */ 350 351 return; 352 } 353 354 static void 355 sock4_open(struct flags *flags 356 #ifdef IPSEC_POLICY_IPSEC 357 , char *policy 358 #endif /* IPSEC_POLICY_IPSEC */ 359 ) 360 { 361 #ifdef IPSEC 362 #ifndef IPSEC_POLICY_IPSEC 363 int optval; 364 #endif 365 #endif 366 367 if (with_v4dest == 0) 368 return; 369 if ((s4 = socket(AF_INET, SOCK_RAW, IPPROTO_ICMPV6)) < 0) { 370 syslog(LOG_ERR, "<%s> socket(v4): %s", __FUNCTION__, 371 strerror(errno)); 372 exit(1); 373 } 374 375 #if 0 /* XXX: not necessary ?? */ 376 /* 377 * join all routers multicast addresses. 378 */ 379 some_join_function(); 380 #endif 381 382 #ifdef IPSEC 383 #ifdef IPSEC_POLICY_IPSEC 384 if (flags->policy) { 385 char *buf; 386 buf = ipsec_set_policy(policy, strlen(policy)); 387 if (buf == NULL) 388 errx(1, "%s", ipsec_strerror()); 389 /* XXX should handle in/out bound policy. */ 390 if (setsockopt(s4, IPPROTO_IP, IP_IPSEC_POLICY, 391 buf, ipsec_get_policylen(buf)) < 0) 392 err(1, "setsockopt(IP_IPSEC_POLICY)"); 393 free(buf); 394 } 395 #else /* IPSEC_POLICY_IPSEC */ 396 if (flags->auth) { 397 optval = IPSEC_LEVEL_REQUIRE; 398 if (setsockopt(s4, IPPROTO_IP, IP_AUTH_TRANS_LEVEL, 399 &optval, sizeof(optval)) == -1) { 400 syslog(LOG_ERR, "<%s> IP_AUTH_TRANS_LEVEL: %s", 401 __FUNCTION__, strerror(errno)); 402 exit(1); 403 } 404 } 405 if (flags->encrypt) { 406 optval = IPSEC_LEVEL_REQUIRE; 407 if (setsockopt(s4, IPPROTO_IP, IP_ESP_TRANS_LEVEL, 408 &optval, sizeof(optval)) == -1) { 409 syslog(LOG_ERR, "<%s> IP_ESP_TRANS_LEVEL: %s", 410 __FUNCTION__, strerror(errno)); 411 exit(1); 412 } 413 } 414 #endif /* IPSEC_POLICY_IPSEC */ 415 #endif /* IPSEC */ 416 417 return; 418 } 419 420 static void 421 rrenum_output(struct payload_list *pl, struct dst_list *dl) 422 { 423 int i, msglen = 0; 424 struct cmsghdr *cm; 425 struct in6_pktinfo *pi; 426 struct sockaddr_in6 *sin6 = NULL; 427 428 sndmhdr.msg_name = (caddr_t)dl->dl_dst; 429 if (dl->dl_dst->sa_family == AF_INET6) 430 sin6 = (struct sockaddr_in6 *)dl->dl_dst; 431 432 if (sin6 != NULL && 433 IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr)) { 434 int hoplimit = RR_MCHLIM_DEFAULT; 435 436 cm = CMSG_FIRSTHDR(&sndmhdr); 437 /* specify the outgoing interface */ 438 cm->cmsg_level = IPPROTO_IPV6; 439 cm->cmsg_type = IPV6_PKTINFO; 440 cm->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo)); 441 pi = (struct in6_pktinfo *)CMSG_DATA(cm); 442 memset(&pi->ipi6_addr, 0, sizeof(pi->ipi6_addr)); /*XXX*/ 443 pi->ipi6_ifindex = sin6->sin6_scope_id; 444 msglen += CMSG_LEN(sizeof(struct in6_pktinfo)); 445 446 /* specify the hop limit of the packet if dest is link local */ 447 /* not defined by router-renum-05.txt, but maybe its OK */ 448 cm = CMSG_NXTHDR(&sndmhdr, cm); 449 cm->cmsg_level = IPPROTO_IPV6; 450 cm->cmsg_type = IPV6_HOPLIMIT; 451 cm->cmsg_len = CMSG_LEN(sizeof(int)); 452 memcpy(CMSG_DATA(cm), &hoplimit, sizeof(int)); 453 msglen += CMSG_LEN(sizeof(int)); 454 } 455 sndmhdr.msg_controllen = msglen; 456 if (sndmhdr.msg_controllen == 0) 457 sndmhdr.msg_control = 0; 458 459 sndmhdr.msg_iov = &pl->pl_sndiov; 460 i = sendmsg(dl->dl_dst->sa_family == AF_INET ? s4 : s6, &sndmhdr, 0); 461 462 if (i < 0 || i != sndmhdr.msg_iov->iov_len) 463 syslog(LOG_ERR, "<%s> sendmsg: %s", __FUNCTION__, 464 strerror(errno)); 465 } 466 467 static void 468 rrenum_snd_eachdst(struct payload_list *pl) 469 { 470 struct dst_list *dl; 471 472 for (dl = dl_head; dl; dl = dl->dl_next) { 473 rrenum_output(pl, dl); 474 } 475 } 476 477 #if 0 478 static void 479 rrenum_snd_fullsequence() 480 { 481 struct payload_list *pl; 482 483 for (pl = pl_head; pl; pl = pl->pl_next) { 484 rrenum_snd_eachdst(pl); 485 } 486 } 487 #endif 488 489 static void 490 rrenum_input(int s) 491 { 492 int i; 493 struct icmp6_router_renum *rr; 494 495 /* get message */ 496 if ((i = recvmsg(s, &rcvmhdr, 0)) < 0) { 497 syslog(LOG_ERR, "<%s> recvmsg: %s", __FUNCTION__, 498 strerror(errno)); 499 return; 500 } 501 if (s == s4) 502 i -= sizeof(struct ip); 503 if (i < sizeof(struct icmp6_router_renum)) { 504 syslog(LOG_ERR, "<%s> packet size(%d) is too short", 505 __FUNCTION__, i); 506 return; 507 } 508 if (s == s4) { 509 struct ip *ip = (struct ip *)rcvmhdr.msg_iov->iov_base; 510 511 rr = (struct icmp6_router_renum *)(ip + 1); 512 } else /* s == s6 */ 513 rr = (struct icmp6_router_renum *)rcvmhdr.msg_iov->iov_base; 514 515 switch(rr->rr_code) { 516 case ICMP6_ROUTER_RENUMBERING_COMMAND: 517 /* COMMAND will be processed by rtadvd */ 518 break; 519 case ICMP6_ROUTER_RENUMBERING_RESULT: 520 /* TODO: receiving result message */ 521 break; 522 default: 523 syslog(LOG_ERR, "<%s> received unknown code %d", 524 __FUNCTION__, rr->rr_code); 525 break; 526 } 527 } 528 529 int 530 main(int argc, char *argv[]) 531 { 532 FILE *fp = stdin; 533 fd_set fdset; 534 struct timeval timeout; 535 int ch, i, maxfd = 0, send_counter = 0; 536 struct flags flags; 537 struct payload_list *pl; 538 #ifdef IPSEC_POLICY_IPSEC 539 char *policy = NULL; 540 #endif 541 542 memset(&flags, 0, sizeof(flags)); 543 openlog("rrenumd", LOG_PID, LOG_DAEMON); 544 545 /* get options */ 546 while ((ch = getopt(argc, argv, "c:sdf" 547 #ifdef IPSEC 548 #ifdef IPSEC_POLICY_IPSEC 549 "P:" 550 #else /* IPSEC_POLICY_IPSEC */ 551 "AE" 552 #endif /* IPSEC_POLICY_IPSEC */ 553 #endif /* IPSEC */ 554 )) != -1){ 555 switch (ch) { 556 case 'c': 557 if((fp = fopen(optarg, "r")) == NULL) { 558 syslog(LOG_ERR, 559 "<%s> config file %s open failed", 560 __FUNCTION__, optarg); 561 exit(1); 562 } 563 break; 564 case 's': 565 fp = stdin; 566 break; 567 case 'd': 568 flags.debug = 1; 569 break; 570 case 'f': 571 flags.fg = 1; 572 break; 573 #ifdef IPSEC 574 #ifdef IPSEC_POLICY_IPSEC 575 case 'P': 576 flags.policy = 1; 577 policy = strdup(optarg); 578 break; 579 #else /* IPSEC_POLICY_IPSEC */ 580 case 'A': 581 flags.auth = 1; 582 break; 583 case 'E': 584 flags.encrypt = 1; 585 break; 586 #endif /* IPSEC_POLICY_IPSEC */ 587 #endif /*IPSEC*/ 588 default: 589 show_usage(); 590 } 591 } 592 argc -= optind; 593 argv += optind; 594 595 /* set log level */ 596 if (flags.debug == 0) 597 (void)setlogmask(LOG_UPTO(LOG_ERR)); 598 if (flags.debug == 1) 599 (void)setlogmask(LOG_UPTO(LOG_INFO)); 600 601 /* init global variables */ 602 init_globals(); 603 604 config(&fp); 605 606 sock6_open(&flags 607 #ifdef IPSEC_POLICY_IPSEC 608 , policy 609 #endif /* IPSEC_POLICY_IPSEC */ 610 ); 611 sock4_open(&flags 612 #ifdef IPSEC_POLICY_IPSEC 613 , policy 614 #endif /* IPSEC_POLICY_IPSEC */ 615 ); 616 617 if (!flags.fg) 618 daemon(0, 0); 619 620 FD_ZERO(&fdset); 621 if (with_v6dest) { 622 FD_SET(s6, &fdset); 623 if (s6 > maxfd) 624 maxfd = s6; 625 } 626 if (with_v4dest) { 627 FD_SET(s4, &fdset); 628 if (s4 > maxfd) 629 maxfd = s4; 630 } 631 632 /* ADHOC: timeout each 30seconds */ 633 memset(&timeout, 0, sizeof(timeout)); 634 635 /* init temporary payload_list and send_counter*/ 636 pl = pl_head; 637 send_counter = retry + 1; 638 while (1) { 639 struct fd_set select_fd = fdset; /* reinitialize */ 640 641 if ((i = select(maxfd + 1, &select_fd, NULL, NULL, 642 &timeout)) < 0){ 643 syslog(LOG_ERR, "<%s> select: %s", 644 __FUNCTION__, strerror(errno)); 645 continue; 646 } 647 if (i == 0) { /* timeout */ 648 if (pl == NULL) 649 exit(0); 650 rrenum_snd_eachdst(pl); 651 send_counter--; 652 timeout.tv_sec = 30; 653 if (send_counter == 0) { 654 timeout.tv_sec = 0; 655 pl = pl->pl_next; 656 send_counter = retry + 1; 657 } 658 } 659 if (FD_ISSET(s4, &select_fd)) 660 rrenum_input(s4); 661 if (FD_ISSET(s6, &select_fd)) 662 rrenum_input(s6); 663 } 664 } 665