1 /* $KAME: rrenumd.c,v 1.20 2000/11/08 02:40:53 itojun Exp $ */ 2 3 /*- 4 * SPDX-License-Identifier: BSD-3-Clause 5 * 6 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. 7 * All rights reserved. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 3. Neither the name of the project nor the names of its contributors 18 * may be used to endorse or promote products derived from this software 19 * without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 * 33 * $FreeBSD$ 34 */ 35 36 #include <sys/param.h> 37 #include <sys/socket.h> 38 #include <sys/uio.h> 39 #include <sys/time.h> 40 41 #include <string.h> 42 43 #include <net/route.h> 44 45 #include <netinet/in_systm.h> 46 #include <netinet/in.h> 47 #include <netinet/ip.h> 48 #include <netinet/ip6.h> 49 #include <netinet/icmp6.h> 50 51 #include <arpa/inet.h> 52 53 #ifdef IPSEC 54 #include <netipsec/ipsec.h> 55 #endif 56 57 #include <stdio.h> 58 #include <err.h> 59 #include <errno.h> 60 #include <stdlib.h> 61 #include <unistd.h> 62 #include <syslog.h> 63 64 #include "rrenumd.h" 65 66 #define LL_ALLROUTERS "ff02::2" 67 #define SL_ALLROUTERS "ff05::2" 68 69 #define RR_MCHLIM_DEFAULT 64 70 71 #ifndef IN6_IS_SCOPE_LINKLOCAL 72 #define IN6_IS_SCOPE_LINKLOCAL(a) \ 73 ((IN6_IS_ADDR_LINKLOCAL(a)) || \ 74 (IN6_IS_ADDR_MC_LINKLOCAL(a))) 75 #endif /* IN6_IS_SCOPE_LINKLOCAL */ 76 77 struct flags { 78 u_long debug : 1; 79 u_long fg : 1; 80 #ifdef IPSEC 81 #ifdef IPSEC_POLICY_IPSEC 82 u_long policy : 1; 83 #else /* IPSEC_POLICY_IPSEC */ 84 u_long auth : 1; 85 u_long encrypt : 1; 86 #endif /* IPSEC_POLICY_IPSEC */ 87 #endif /*IPSEC*/ 88 }; 89 90 struct msghdr sndmhdr; 91 struct msghdr rcvmhdr; 92 struct sockaddr_in6 from; 93 struct sockaddr_in6 sin6_ll_allrouters; 94 95 int s4, s6; 96 int with_v4dest, with_v6dest; 97 struct in6_addr prefix; /* ADHOC */ 98 int prefixlen = 64; /* ADHOC */ 99 100 extern int parse(FILE **); 101 102 static void show_usage(void); 103 static void init_sin6(struct sockaddr_in6 *, const char *); 104 #if 0 105 static void join_multi(const char *); 106 #endif 107 static void init_globals(void); 108 static void config(FILE **); 109 #ifdef IPSEC_POLICY_IPSEC 110 static void sock6_open(struct flags *, char *); 111 static void sock4_open(struct flags *, char *); 112 #else 113 static void sock6_open(struct flags *); 114 static void sock4_open(struct flags *); 115 #endif 116 static void rrenum_output(struct payload_list *, struct dst_list *); 117 static void rrenum_snd_eachdst(struct payload_list *); 118 #if 0 119 static void rrenum_snd_fullsequence(void); 120 #endif 121 static void rrenum_input(int); 122 int main(int, char *[]); 123 124 125 /* Print usage. Don't call this after daemonized. */ 126 static void 127 show_usage() 128 { 129 fprintf(stderr, "usage: rrenumd [-c conf_file|-s] [-df" 130 #ifdef IPSEC 131 #ifdef IPSEC_POLICY_IPSEC 132 "] [-P policy" 133 #else /* IPSEC_POLICY_IPSEC */ 134 "AE" 135 #endif /* IPSEC_POLICY_IPSEC */ 136 #endif /* IPSEC */ 137 "]\n"); 138 exit(1); 139 } 140 141 static void 142 init_sin6(struct sockaddr_in6 *sin6, const char *addr_ascii) 143 { 144 memset(sin6, 0, sizeof(*sin6)); 145 sin6->sin6_len = sizeof(*sin6); 146 sin6->sin6_family = AF_INET6; 147 if (inet_pton(AF_INET6, addr_ascii, &sin6->sin6_addr) != 1) 148 ; /* XXX do something */ 149 } 150 151 #if 0 /* XXX: not necessary ?? */ 152 static void 153 join_multi(const char *addrname) 154 { 155 struct ipv6_mreq mreq; 156 157 if (inet_pton(AF_INET6, addrname, &mreq.ipv6mr_multiaddr.s6_addr) 158 != 1) { 159 syslog(LOG_ERR, "<%s> inet_pton failed(library bug?)", 160 __func__); 161 exit(1); 162 } 163 /* ADHOC: currently join only one */ 164 { 165 if ((mreq.ipv6mr_interface = if_nametoindex(ifname)) == 0) { 166 syslog(LOG_ERR, "<%s> ifname %s should be invalid: %s", 167 __func__, ifname, strerror(errno)); 168 exit(1); 169 } 170 if (setsockopt(s, IPPROTO_IPV6, IPV6_JOIN_GROUP, 171 &mreq, 172 sizeof(mreq)) < 0) { 173 syslog(LOG_ERR, "<%s> IPV6_JOIN_GROUP on %s: %s", 174 __func__, ifname, strerror(errno)); 175 exit(1); 176 } 177 } 178 } 179 #endif 180 181 static void 182 init_globals() 183 { 184 static struct iovec rcviov; 185 static u_char rprdata[4500]; /* maximal MTU of connected links */ 186 static u_char *rcvcmsgbuf = NULL; 187 static u_char *sndcmsgbuf = NULL; 188 int sndcmsglen, rcvcmsglen; 189 190 /* init ll_allrouters */ 191 init_sin6(&sin6_ll_allrouters, LL_ALLROUTERS); 192 193 /* initialize msghdr for receiving packets */ 194 rcviov.iov_base = (caddr_t)rprdata; 195 rcviov.iov_len = sizeof(rprdata); 196 rcvmhdr.msg_namelen = sizeof(struct sockaddr_in6); 197 rcvmhdr.msg_iov = &rcviov; 198 rcvmhdr.msg_iovlen = 1; 199 rcvcmsglen = CMSG_SPACE(sizeof(struct in6_pktinfo)) + 200 CMSG_SPACE(sizeof(int)); 201 if (rcvcmsgbuf == NULL && 202 (rcvcmsgbuf = (u_char *)malloc(rcvcmsglen)) == NULL) { 203 syslog(LOG_ERR, "<%s>: malloc failed", __func__); 204 exit(1); 205 } 206 rcvmhdr.msg_control = (caddr_t)rcvcmsgbuf; 207 rcvmhdr.msg_controllen = rcvcmsglen; 208 209 /* initialize msghdr for sending packets */ 210 sndmhdr.msg_namelen = sizeof(struct sockaddr_in6); 211 sndmhdr.msg_iovlen = 1; 212 sndcmsglen = CMSG_SPACE(sizeof(struct in6_pktinfo)) + 213 CMSG_SPACE(sizeof(int)); 214 if (sndcmsgbuf == NULL && 215 (sndcmsgbuf = (u_char *)malloc(sndcmsglen)) == NULL) { 216 syslog(LOG_ERR, "<%s>: malloc failed", __func__); 217 exit(1); 218 } 219 sndmhdr.msg_control = (caddr_t)sndcmsgbuf; 220 sndmhdr.msg_controllen = sndcmsglen; 221 } 222 223 static void 224 config(FILE **fpp) 225 { 226 struct payload_list *pl; 227 struct iovec *iov; 228 struct icmp6_router_renum *irr; 229 struct rr_pco_match *rpm; 230 231 if (parse(fpp) < 0) { 232 syslog(LOG_ERR, "<%s> parse failed", __func__); 233 exit(1); 234 } 235 236 /* initialize fields not configured by parser */ 237 for (pl = pl_head; pl; pl = pl->pl_next) { 238 iov = (struct iovec *)&pl->pl_sndiov; 239 irr = (struct icmp6_router_renum *)&pl->pl_irr; 240 rpm = (struct rr_pco_match *)&pl->pl_rpm; 241 242 irr->rr_type = ICMP6_ROUTER_RENUMBERING; 243 irr->rr_code = 0; 244 /* 245 * now we don't support multiple PCOs in a rr message. 246 * so segment number is not supported. 247 */ 248 /* TODO: rr flags config in parser */ 249 irr->rr_flags |= ICMP6_RR_FLAGS_SPECSITE; 250 /* TODO: max delay config in parser */ 251 252 /* 253 * means only 1 use_prefix is contained as router-renum-05.txt. 254 * now we don't support multiple PCOs in a rr message, 255 * nor multiple use_prefix in one PCO. 256 */ 257 rpm->rpm_len = 4*1 +3; 258 rpm->rpm_ordinal = 0; 259 iov->iov_base = (caddr_t)irr; 260 iov->iov_len = sizeof(struct icmp6_router_renum) 261 + sizeof(struct rr_pco_match) 262 + sizeof(struct rr_pco_use); 263 } 264 } 265 266 static void 267 sock6_open(struct flags *flags 268 #ifdef IPSEC_POLICY_IPSEC 269 , char *policy 270 #endif /* IPSEC_POLICY_IPSEC */ 271 ) 272 { 273 struct icmp6_filter filt; 274 int on; 275 #ifdef IPSEC 276 #ifndef IPSEC_POLICY_IPSEC 277 int optval; 278 #endif 279 #endif 280 281 if (with_v6dest == 0) 282 return; 283 if (with_v6dest && 284 (s6 = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6)) < 0) { 285 syslog(LOG_ERR, "<%s> socket(v6): %s", __func__, 286 strerror(errno)); 287 exit(1); 288 } 289 290 /* 291 * join all routers multicast addresses. 292 */ 293 #if 0 /* XXX: not necessary ?? */ 294 join_multi(LL_ALLROUTERS); 295 join_multi(SL_ALLROUTERS); 296 #endif 297 298 /* set icmpv6 filter */ 299 ICMP6_FILTER_SETBLOCKALL(&filt); 300 ICMP6_FILTER_SETPASS(ICMP6_ROUTER_RENUMBERING, &filt); 301 if (setsockopt(s6, IPPROTO_ICMPV6, ICMP6_FILTER, &filt, 302 sizeof(filt)) < 0) { 303 syslog(LOG_ERR, "<%s> IICMP6_FILTER: %s", 304 __func__, strerror(errno)); 305 exit(1); 306 } 307 308 /* specify to tell receiving interface */ 309 on = 1; 310 if (setsockopt(s6, IPPROTO_IPV6, IPV6_RECVPKTINFO, &on, 311 sizeof(on)) < 0) { 312 syslog(LOG_ERR, "<%s> IPV6_RECVPKTINFO: %s", 313 __func__, strerror(errno)); 314 exit(1); 315 } 316 317 #ifdef IPSEC 318 #ifdef IPSEC_POLICY_IPSEC 319 if (flags->policy) { 320 char *buf; 321 buf = ipsec_set_policy(policy, strlen(policy)); 322 if (buf == NULL) 323 errx(1, "%s", ipsec_strerror()); 324 /* XXX should handle in/out bound policy. */ 325 if (setsockopt(s6, IPPROTO_IPV6, IPV6_IPSEC_POLICY, 326 buf, ipsec_get_policylen(buf)) < 0) 327 err(1, "setsockopt(IPV6_IPSEC_POLICY)"); 328 free(buf); 329 } 330 #else /* IPSEC_POLICY_IPSEC */ 331 if (flags->auth) { 332 optval = IPSEC_LEVEL_REQUIRE; 333 if (setsockopt(s6, IPPROTO_IPV6, IPV6_AUTH_TRANS_LEVEL, 334 &optval, sizeof(optval)) == -1) { 335 syslog(LOG_ERR, "<%s> IPV6_AUTH_TRANS_LEVEL: %s", 336 __func__, strerror(errno)); 337 exit(1); 338 } 339 } 340 if (flags->encrypt) { 341 optval = IPSEC_LEVEL_REQUIRE; 342 if (setsockopt(s6, IPPROTO_IPV6, IPV6_ESP_TRANS_LEVEL, 343 &optval, sizeof(optval)) == -1) { 344 syslog(LOG_ERR, "<%s> IPV6_ESP_TRANS_LEVEL: %s", 345 __func__, strerror(errno)); 346 exit(1); 347 } 348 } 349 #endif /* IPSEC_POLICY_IPSEC */ 350 #endif /* IPSEC */ 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 417 static void 418 rrenum_output(struct payload_list *pl, struct dst_list *dl) 419 { 420 int i, msglen = 0; 421 struct cmsghdr *cm; 422 struct in6_pktinfo *pi; 423 struct sockaddr_in6 *sin6 = NULL; 424 425 sndmhdr.msg_name = (caddr_t)dl->dl_dst; 426 if (dl->dl_dst->sa_family == AF_INET6) 427 sin6 = (struct sockaddr_in6 *)dl->dl_dst; 428 429 if (sin6 != NULL && 430 IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr)) { 431 int hoplimit = RR_MCHLIM_DEFAULT; 432 433 cm = CMSG_FIRSTHDR(&sndmhdr); 434 /* specify the outgoing interface */ 435 cm->cmsg_level = IPPROTO_IPV6; 436 cm->cmsg_type = IPV6_PKTINFO; 437 cm->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo)); 438 pi = (struct in6_pktinfo *)CMSG_DATA(cm); 439 memset(&pi->ipi6_addr, 0, sizeof(pi->ipi6_addr)); /*XXX*/ 440 pi->ipi6_ifindex = sin6->sin6_scope_id; 441 msglen += CMSG_LEN(sizeof(struct in6_pktinfo)); 442 443 /* specify the hop limit of the packet if dest is link local */ 444 /* not defined by router-renum-05.txt, but maybe its OK */ 445 cm = CMSG_NXTHDR(&sndmhdr, cm); 446 cm->cmsg_level = IPPROTO_IPV6; 447 cm->cmsg_type = IPV6_HOPLIMIT; 448 cm->cmsg_len = CMSG_LEN(sizeof(int)); 449 memcpy(CMSG_DATA(cm), &hoplimit, sizeof(int)); 450 msglen += CMSG_LEN(sizeof(int)); 451 } 452 sndmhdr.msg_controllen = msglen; 453 if (sndmhdr.msg_controllen == 0) 454 sndmhdr.msg_control = 0; 455 456 sndmhdr.msg_iov = &pl->pl_sndiov; 457 i = sendmsg(dl->dl_dst->sa_family == AF_INET ? s4 : s6, &sndmhdr, 0); 458 459 if (i < 0 || i != sndmhdr.msg_iov->iov_len) 460 syslog(LOG_ERR, "<%s> sendmsg: %s", __func__, 461 strerror(errno)); 462 } 463 464 static void 465 rrenum_snd_eachdst(struct payload_list *pl) 466 { 467 struct dst_list *dl; 468 469 for (dl = dl_head; dl; dl = dl->dl_next) { 470 rrenum_output(pl, dl); 471 } 472 } 473 474 #if 0 475 static void 476 rrenum_snd_fullsequence() 477 { 478 struct payload_list *pl; 479 480 for (pl = pl_head; pl; pl = pl->pl_next) { 481 rrenum_snd_eachdst(pl); 482 } 483 } 484 #endif 485 486 static void 487 rrenum_input(int s) 488 { 489 int i; 490 struct icmp6_router_renum *rr; 491 492 /* get message */ 493 if ((i = recvmsg(s, &rcvmhdr, 0)) < 0) { 494 syslog(LOG_ERR, "<%s> recvmsg: %s", __func__, 495 strerror(errno)); 496 return; 497 } 498 if (s == s4) 499 i -= sizeof(struct ip); 500 if (i < sizeof(struct icmp6_router_renum)) { 501 syslog(LOG_ERR, "<%s> packet size(%d) is too short", 502 __func__, i); 503 return; 504 } 505 if (s == s4) { 506 struct ip *ip = (struct ip *)rcvmhdr.msg_iov->iov_base; 507 508 rr = (struct icmp6_router_renum *)(ip + 1); 509 } else /* s == s6 */ 510 rr = (struct icmp6_router_renum *)rcvmhdr.msg_iov->iov_base; 511 512 switch(rr->rr_code) { 513 case ICMP6_ROUTER_RENUMBERING_COMMAND: 514 /* COMMAND will be processed by rtadvd */ 515 break; 516 case ICMP6_ROUTER_RENUMBERING_RESULT: 517 /* TODO: receiving result message */ 518 break; 519 default: 520 syslog(LOG_ERR, "<%s> received unknown code %d", 521 __func__, rr->rr_code); 522 break; 523 } 524 } 525 526 int 527 main(int argc, char *argv[]) 528 { 529 FILE *fp = stdin; 530 fd_set fdset; 531 struct timeval timeout; 532 int ch, i, maxfd = 0, send_counter = 0; 533 struct flags flags; 534 struct payload_list *pl; 535 #ifdef IPSEC_POLICY_IPSEC 536 char *policy = NULL; 537 #endif 538 539 memset(&flags, 0, sizeof(flags)); 540 openlog("rrenumd", LOG_PID, LOG_DAEMON); 541 542 /* get options */ 543 while ((ch = getopt(argc, argv, "c:sdf" 544 #ifdef IPSEC 545 #ifdef IPSEC_POLICY_IPSEC 546 "P:" 547 #else /* IPSEC_POLICY_IPSEC */ 548 "AE" 549 #endif /* IPSEC_POLICY_IPSEC */ 550 #endif /* IPSEC */ 551 )) != -1){ 552 switch (ch) { 553 case 'c': 554 if((fp = fopen(optarg, "r")) == NULL) { 555 syslog(LOG_ERR, 556 "<%s> config file %s open failed", 557 __func__, optarg); 558 exit(1); 559 } 560 break; 561 case 's': 562 fp = stdin; 563 break; 564 case 'd': 565 flags.debug = 1; 566 break; 567 case 'f': 568 flags.fg = 1; 569 break; 570 #ifdef IPSEC 571 #ifdef IPSEC_POLICY_IPSEC 572 case 'P': 573 flags.policy = 1; 574 policy = strdup(optarg); 575 break; 576 #else /* IPSEC_POLICY_IPSEC */ 577 case 'A': 578 flags.auth = 1; 579 break; 580 case 'E': 581 flags.encrypt = 1; 582 break; 583 #endif /* IPSEC_POLICY_IPSEC */ 584 #endif /*IPSEC*/ 585 default: 586 show_usage(); 587 } 588 } 589 argc -= optind; 590 argv += optind; 591 592 /* set log level */ 593 if (flags.debug == 0) 594 (void)setlogmask(LOG_UPTO(LOG_ERR)); 595 if (flags.debug == 1) 596 (void)setlogmask(LOG_UPTO(LOG_INFO)); 597 598 /* init global variables */ 599 init_globals(); 600 601 config(&fp); 602 603 sock6_open(&flags 604 #ifdef IPSEC_POLICY_IPSEC 605 , policy 606 #endif /* IPSEC_POLICY_IPSEC */ 607 ); 608 sock4_open(&flags 609 #ifdef IPSEC_POLICY_IPSEC 610 , policy 611 #endif /* IPSEC_POLICY_IPSEC */ 612 ); 613 614 if (!flags.fg) 615 daemon(0, 0); 616 617 FD_ZERO(&fdset); 618 if (with_v6dest) { 619 FD_SET(s6, &fdset); 620 if (s6 > maxfd) 621 maxfd = s6; 622 } 623 if (with_v4dest) { 624 FD_SET(s4, &fdset); 625 if (s4 > maxfd) 626 maxfd = s4; 627 } 628 629 /* ADHOC: timeout each 30seconds */ 630 memset(&timeout, 0, sizeof(timeout)); 631 632 /* init temporary payload_list and send_counter*/ 633 pl = pl_head; 634 send_counter = retry + 1; 635 while (1) { 636 struct fd_set select_fd = fdset; /* reinitialize */ 637 638 if ((i = select(maxfd + 1, &select_fd, NULL, NULL, 639 &timeout)) < 0){ 640 syslog(LOG_ERR, "<%s> select: %s", 641 __func__, strerror(errno)); 642 continue; 643 } 644 if (i == 0) { /* timeout */ 645 if (pl == NULL) 646 exit(0); 647 rrenum_snd_eachdst(pl); 648 send_counter--; 649 timeout.tv_sec = 30; 650 if (send_counter == 0) { 651 timeout.tv_sec = 0; 652 pl = pl->pl_next; 653 send_counter = retry + 1; 654 } 655 } 656 if (FD_ISSET(s4, &select_fd)) 657 rrenum_input(s4); 658 if (FD_ISSET(s6, &select_fd)) 659 rrenum_input(s6); 660 } 661 } 662