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