1 1.1 christos /* $NetBSD: l4check.c,v 1.1.1.2 2012/07/22 13:44:38 darrenr Exp $ */ 2 1.1 christos 3 1.1 christos /* 4 1.1.1.2 darrenr * (C)Copyright (C) 2012 by Darren Reed. 5 1.1 christos */ 6 1.1 christos #include <sys/types.h> 7 1.1 christos #include <sys/stat.h> 8 1.1 christos #include <sys/mman.h> 9 1.1 christos #include <sys/socket.h> 10 1.1 christos #include <sys/time.h> 11 1.1 christos #include <sys/ioctl.h> 12 1.1 christos 13 1.1 christos #include <netinet/in.h> 14 1.1 christos #include <netinet/in_systm.h> 15 1.1 christos #include <netinet/ip.h> 16 1.1 christos 17 1.1 christos #include <net/if.h> 18 1.1 christos 19 1.1 christos #include <stdio.h> 20 1.1 christos #include <netdb.h> 21 1.1 christos #include <string.h> 22 1.1 christos #include <ctype.h> 23 1.1 christos #include <fcntl.h> 24 1.1 christos #include <errno.h> 25 1.1 christos #include <stdlib.h> 26 1.1 christos 27 1.1 christos #include "ip_compat.h" 28 1.1 christos #include "ip_fil.h" 29 1.1 christos #include "ip_nat.h" 30 1.1 christos 31 1.1 christos #include "ipf.h" 32 1.1 christos 33 1.1 christos extern char *optarg; 34 1.1 christos 35 1.1 christos 36 1.1 christos typedef struct l4cfg { 37 1.1 christos struct l4cfg *l4_next; 38 1.1 christos struct ipnat l4_nat; /* NAT rule */ 39 1.1 christos struct sockaddr_in l4_sin; /* remote socket to connect */ 40 1.1 christos time_t l4_last; /* when we last connected */ 41 1.1 christos int l4_alive; /* 1 = remote alive */ 42 1.1 christos int l4_fd; 43 1.1 christos int l4_rw; /* 0 = reading, 1 = writing */ 44 1.1 christos char *l4_rbuf; /* read buffer */ 45 1.1 christos int l4_rsize; /* size of buffer */ 46 1.1 christos int l4_rlen; /* how much used */ 47 1.1 christos char *l4_wptr; /* next byte to write */ 48 1.1 christos int l4_wlen; /* length yet to be written */ 49 1.1 christos } l4cfg_t; 50 1.1 christos 51 1.1 christos 52 1.1 christos l4cfg_t *l4list = NULL; 53 1.1 christos char *response = NULL; 54 1.1 christos char *probe = NULL; 55 1.1 christos l4cfg_t template; 56 1.1 christos int frequency = 20; 57 1.1 christos int ctimeout = 1; 58 1.1 christos int rtimeout = 1; 59 1.1 christos size_t plen = 0; 60 1.1 christos size_t rlen = 0; 61 1.1 christos int natfd = -1; 62 1.1 christos int opts = 0; 63 1.1 christos 64 1.1 christos #if defined(sun) && !defined(__svr4__) && !defined(__SVR4) 65 1.1 christos # define strerror(x) sys_errlist[x] 66 1.1 christos #endif 67 1.1 christos 68 1.1 christos 69 1.1 christos char *copystr(dst, src) 70 1.1 christos char *dst, *src; 71 1.1 christos { 72 1.1 christos register char *s, *t, c; 73 1.1 christos register int esc = 0; 74 1.1 christos 75 1.1 christos for (s = src, t = dst; s && t && (c = *s++); ) 76 1.1 christos if (esc) { 77 1.1 christos esc = 0; 78 1.1 christos switch (c) 79 1.1 christos { 80 1.1 christos case 'n' : 81 1.1 christos *t++ = '\n'; 82 1.1 christos break; 83 1.1 christos case 'r' : 84 1.1 christos *t++ = '\r'; 85 1.1 christos break; 86 1.1 christos case 't' : 87 1.1 christos *t++ = '\t'; 88 1.1 christos break; 89 1.1 christos } 90 1.1 christos } else if (c != '\\') 91 1.1 christos *t++ = c; 92 1.1 christos else 93 1.1 christos esc = 1; 94 1.1 christos *t = '\0'; 95 1.1 christos return dst; 96 1.1 christos } 97 1.1 christos 98 1.1 christos void addnat(l4) 99 1.1 christos l4cfg_t *l4; 100 1.1 christos { 101 1.1 christos ipnat_t *ipn = &l4->l4_nat; 102 1.1 christos 103 1.1 christos printf("Add NAT rule for %s/%#x,%u -> ", inet_ntoa(ipn->in_out[0]), 104 1.1 christos ipn->in_outmsk, ntohs(ipn->in_pmin)); 105 1.1 christos printf("%s,%u\n", inet_ntoa(ipn->in_in[0]), ntohs(ipn->in_pnext)); 106 1.1 christos if (!(opts & OPT_DONOTHING)) { 107 1.1 christos if (ioctl(natfd, SIOCADNAT, &ipn) == -1) 108 1.1 christos perror("ioctl(SIOCADNAT)"); 109 1.1 christos } 110 1.1 christos } 111 1.1 christos 112 1.1 christos 113 1.1 christos void delnat(l4) 114 1.1 christos l4cfg_t *l4; 115 1.1 christos { 116 1.1 christos ipnat_t *ipn = &l4->l4_nat; 117 1.1 christos 118 1.1 christos printf("Remove NAT rule for %s/%#x,%u -> ", 119 1.1 christos inet_ntoa(ipn->in_out[0]), ipn->in_outmsk, ipn->in_pmin); 120 1.1 christos printf("%s,%u\n", inet_ntoa(ipn->in_in[0]), ipn->in_pnext); 121 1.1 christos if (!(opts & OPT_DONOTHING)) { 122 1.1 christos if (ioctl(natfd, SIOCRMNAT, &ipn) == -1) 123 1.1 christos perror("ioctl(SIOCRMNAT)"); 124 1.1 christos } 125 1.1 christos } 126 1.1 christos 127 1.1 christos 128 1.1 christos void connectl4(l4) 129 1.1 christos l4cfg_t *l4; 130 1.1 christos { 131 1.1 christos l4->l4_rw = 1; 132 1.1 christos l4->l4_rlen = 0; 133 1.1 christos l4->l4_wlen = plen; 134 1.1 christos if (!l4->l4_wlen) { 135 1.1 christos l4->l4_alive = 1; 136 1.1 christos addnat(l4); 137 1.1 christos } else 138 1.1 christos l4->l4_wptr = probe; 139 1.1 christos } 140 1.1 christos 141 1.1 christos 142 1.1 christos void closel4(l4, dead) 143 1.1 christos l4cfg_t *l4; 144 1.1 christos int dead; 145 1.1 christos { 146 1.1 christos close(l4->l4_fd); 147 1.1 christos l4->l4_fd = -1; 148 1.1 christos l4->l4_rw = -1; 149 1.1 christos if (dead && l4->l4_alive) { 150 1.1 christos l4->l4_alive = 0; 151 1.1 christos delnat(l4); 152 1.1 christos } 153 1.1 christos } 154 1.1 christos 155 1.1 christos 156 1.1 christos void connectfd(l4) 157 1.1 christos l4cfg_t *l4; 158 1.1 christos { 159 1.1 christos if (connect(l4->l4_fd, (struct sockaddr *)&l4->l4_sin, 160 1.1 christos sizeof(l4->l4_sin)) == -1) { 161 1.1 christos if (errno == EISCONN) { 162 1.1 christos if (opts & OPT_VERBOSE) 163 1.1 christos fprintf(stderr, "Connected fd %d\n", 164 1.1 christos l4->l4_fd); 165 1.1 christos connectl4(l4); 166 1.1 christos return; 167 1.1 christos } 168 1.1 christos if (opts & OPT_VERBOSE) 169 1.1 christos fprintf(stderr, "Connect failed fd %d: %s\n", 170 1.1 christos l4->l4_fd, strerror(errno)); 171 1.1 christos closel4(l4, 1); 172 1.1 christos return; 173 1.1 christos } 174 1.1 christos l4->l4_rw = 1; 175 1.1 christos } 176 1.1 christos 177 1.1 christos 178 1.1 christos void writefd(l4) 179 1.1 christos l4cfg_t *l4; 180 1.1 christos { 181 1.1 christos char buf[80], *ptr; 182 1.1 christos int n, i, fd; 183 1.1 christos 184 1.1 christos fd = l4->l4_fd; 185 1.1 christos 186 1.1 christos if (l4->l4_rw == -2) { 187 1.1 christos connectfd(l4); 188 1.1 christos return; 189 1.1 christos } 190 1.1 christos 191 1.1 christos n = l4->l4_wlen; 192 1.1 christos 193 1.1 christos i = send(fd, l4->l4_wptr, n, 0); 194 1.1 christos if (i == 0 || i == -1) { 195 1.1 christos if (opts & OPT_VERBOSE) 196 1.1 christos fprintf(stderr, "Send on fd %d failed: %s\n", 197 1.1 christos fd, strerror(errno)); 198 1.1 christos closel4(l4, 1); 199 1.1 christos } else { 200 1.1 christos l4->l4_wptr += i; 201 1.1 christos l4->l4_wlen -= i; 202 1.1 christos if (l4->l4_wlen == 0) 203 1.1 christos l4->l4_rw = 0; 204 1.1 christos if (opts & OPT_VERBOSE) 205 1.1 christos fprintf(stderr, "Sent %d bytes to fd %d\n", i, fd); 206 1.1 christos } 207 1.1 christos } 208 1.1 christos 209 1.1 christos 210 1.1 christos void readfd(l4) 211 1.1 christos l4cfg_t *l4; 212 1.1 christos { 213 1.1 christos char buf[80], *ptr; 214 1.1 christos int n, i, fd; 215 1.1 christos 216 1.1 christos fd = l4->l4_fd; 217 1.1 christos 218 1.1 christos if (l4->l4_rw == -2) { 219 1.1 christos connectfd(l4); 220 1.1 christos return; 221 1.1 christos } 222 1.1 christos 223 1.1 christos if (l4->l4_rsize) { 224 1.1 christos n = l4->l4_rsize - l4->l4_rlen; 225 1.1 christos ptr = l4->l4_rbuf + l4->l4_rlen; 226 1.1 christos } else { 227 1.1 christos n = sizeof(buf) - 1; 228 1.1 christos ptr = buf; 229 1.1 christos } 230 1.1 christos 231 1.1 christos if (opts & OPT_VERBOSE) 232 1.1 christos fprintf(stderr, "Read %d bytes on fd %d to %p\n", 233 1.1 christos n, fd, ptr); 234 1.1 christos i = recv(fd, ptr, n, 0); 235 1.1 christos if (i == 0 || i == -1) { 236 1.1 christos if (opts & OPT_VERBOSE) 237 1.1 christos fprintf(stderr, "Read error on fd %d: %s\n", 238 1.1 christos fd, (i == 0) ? "EOF" : strerror(errno)); 239 1.1 christos closel4(l4, 1); 240 1.1 christos } else { 241 1.1 christos if (ptr == buf) 242 1.1 christos ptr[i] = '\0'; 243 1.1 christos if (opts & OPT_VERBOSE) 244 1.1 christos fprintf(stderr, "%d: Read %d bytes [%*.*s]\n", 245 1.1 christos fd, i, i, i, ptr); 246 1.1 christos if (ptr != buf) { 247 1.1 christos l4->l4_rlen += i; 248 1.1 christos if (l4->l4_rlen >= l4->l4_rsize) { 249 1.1 christos if (!strncmp(response, l4->l4_rbuf, 250 1.1 christos l4->l4_rsize)) { 251 1.1 christos printf("%d: Good response\n", 252 1.1 christos fd); 253 1.1 christos if (!l4->l4_alive) { 254 1.1 christos l4->l4_alive = 1; 255 1.1 christos addnat(l4); 256 1.1 christos } 257 1.1 christos closel4(l4, 0); 258 1.1 christos } else { 259 1.1 christos if (opts & OPT_VERBOSE) 260 1.1 christos printf("%d: Bad response\n", 261 1.1 christos fd); 262 1.1 christos closel4(l4, 1); 263 1.1 christos } 264 1.1 christos } 265 1.1 christos } else if (!l4->l4_alive) { 266 1.1 christos l4->l4_alive = 1; 267 1.1 christos addnat(l4); 268 1.1 christos closel4(l4, 0); 269 1.1 christos } 270 1.1 christos } 271 1.1 christos } 272 1.1 christos 273 1.1 christos 274 1.1 christos int runconfig() 275 1.1 christos { 276 1.1 christos int fd, opt, res, mfd, i; 277 1.1 christos struct timeval tv; 278 1.1 christos time_t now, now1; 279 1.1 christos fd_set rfd, wfd; 280 1.1 christos l4cfg_t *l4; 281 1.1 christos 282 1.1 christos mfd = 0; 283 1.1 christos opt = 1; 284 1.1 christos now = time(NULL); 285 1.1 christos 286 1.1 christos /* 287 1.1 christos * First, initiate connections that are closed, as required. 288 1.1 christos */ 289 1.1 christos for (l4 = l4list; l4; l4 = l4->l4_next) { 290 1.1 christos if ((l4->l4_last + frequency < now) && (l4->l4_fd == -1)) { 291 1.1 christos l4->l4_last = now; 292 1.1 christos fd = socket(AF_INET, SOCK_STREAM, 0); 293 1.1 christos if (fd == -1) 294 1.1 christos continue; 295 1.1 christos setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &opt, 296 1.1 christos sizeof(opt)); 297 1.1 christos #ifdef O_NONBLOCK 298 1.1 christos if ((res = fcntl(fd, F_GETFL, 0)) != -1) 299 1.1 christos fcntl(fd, F_SETFL, res | O_NONBLOCK); 300 1.1 christos #endif 301 1.1 christos if (opts & OPT_VERBOSE) 302 1.1 christos fprintf(stderr, 303 1.1 christos "Connecting to %s,%d (fd %d)...", 304 1.1 christos inet_ntoa(l4->l4_sin.sin_addr), 305 1.1 christos ntohs(l4->l4_sin.sin_port), fd); 306 1.1 christos if (connect(fd, (struct sockaddr *)&l4->l4_sin, 307 1.1 christos sizeof(l4->l4_sin)) == -1) { 308 1.1 christos if (errno != EINPROGRESS) { 309 1.1 christos if (opts & OPT_VERBOSE) 310 1.1 christos fprintf(stderr, "failed\n"); 311 1.1 christos perror("connect"); 312 1.1 christos close(fd); 313 1.1 christos fd = -1; 314 1.1 christos } else { 315 1.1 christos if (opts & OPT_VERBOSE) 316 1.1 christos fprintf(stderr, "waiting\n"); 317 1.1 christos l4->l4_rw = -2; 318 1.1 christos } 319 1.1 christos } else { 320 1.1 christos if (opts & OPT_VERBOSE) 321 1.1 christos fprintf(stderr, "connected\n"); 322 1.1 christos connectl4(l4); 323 1.1 christos } 324 1.1 christos l4->l4_fd = fd; 325 1.1 christos } 326 1.1 christos } 327 1.1 christos 328 1.1 christos /* 329 1.1 christos * Now look for fd's which we're expecting to read/write from. 330 1.1 christos */ 331 1.1 christos FD_ZERO(&rfd); 332 1.1 christos FD_ZERO(&wfd); 333 1.1 christos tv.tv_sec = MIN(rtimeout, ctimeout); 334 1.1 christos tv.tv_usec = 0; 335 1.1 christos 336 1.1 christos for (l4 = l4list; l4; l4 = l4->l4_next) 337 1.1 christos if (l4->l4_rw == 0) { 338 1.1 christos if (now - l4->l4_last > rtimeout) { 339 1.1 christos if (opts & OPT_VERBOSE) 340 1.1 christos fprintf(stderr, "%d: Read timeout\n", 341 1.1 christos l4->l4_fd); 342 1.1 christos closel4(l4, 1); 343 1.1 christos continue; 344 1.1 christos } 345 1.1 christos if (opts & OPT_VERBOSE) 346 1.1 christos fprintf(stderr, "Wait for read on fd %d\n", 347 1.1 christos l4->l4_fd); 348 1.1 christos FD_SET(l4->l4_fd, &rfd); 349 1.1 christos if (l4->l4_fd > mfd) 350 1.1 christos mfd = l4->l4_fd; 351 1.1 christos } else if ((l4->l4_rw == 1 && l4->l4_wlen) || 352 1.1 christos l4->l4_rw == -2) { 353 1.1 christos if ((l4->l4_rw == -2) && 354 1.1 christos (now - l4->l4_last > ctimeout)) { 355 1.1 christos if (opts & OPT_VERBOSE) 356 1.1 christos fprintf(stderr, 357 1.1 christos "%d: connect timeout\n", 358 1.1 christos l4->l4_fd); 359 1.1 christos closel4(l4); 360 1.1 christos continue; 361 1.1 christos } 362 1.1 christos if (opts & OPT_VERBOSE) 363 1.1 christos fprintf(stderr, "Wait for write on fd %d\n", 364 1.1 christos l4->l4_fd); 365 1.1 christos FD_SET(l4->l4_fd, &wfd); 366 1.1 christos if (l4->l4_fd > mfd) 367 1.1 christos mfd = l4->l4_fd; 368 1.1 christos } 369 1.1 christos 370 1.1 christos if (opts & OPT_VERBOSE) 371 1.1 christos fprintf(stderr, "Select: max fd %d wait %d\n", mfd + 1, 372 1.1 christos tv.tv_sec); 373 1.1 christos i = select(mfd + 1, &rfd, &wfd, NULL, &tv); 374 1.1 christos if (i == -1) { 375 1.1 christos perror("select"); 376 1.1 christos return -1; 377 1.1 christos } 378 1.1 christos 379 1.1 christos now1 = time(NULL); 380 1.1 christos 381 1.1 christos for (l4 = l4list; (i > 0) && l4; l4 = l4->l4_next) { 382 1.1 christos if (l4->l4_fd < 0) 383 1.1 christos continue; 384 1.1 christos if (FD_ISSET(l4->l4_fd, &rfd)) { 385 1.1 christos if (opts & OPT_VERBOSE) 386 1.1 christos fprintf(stderr, "Ready to read on fd %d\n", 387 1.1 christos l4->l4_fd); 388 1.1 christos readfd(l4); 389 1.1 christos i--; 390 1.1 christos } 391 1.1 christos 392 1.1 christos if ((l4->l4_fd >= 0) && FD_ISSET(l4->l4_fd, &wfd)) { 393 1.1 christos if (opts & OPT_VERBOSE) 394 1.1 christos fprintf(stderr, "Ready to write on fd %d\n", 395 1.1 christos l4->l4_fd); 396 1.1 christos writefd(l4); 397 1.1 christos i--; 398 1.1 christos } 399 1.1 christos } 400 1.1 christos return 0; 401 1.1 christos } 402 1.1 christos 403 1.1 christos 404 1.1 christos int gethostport(str, lnum, ipp, portp) 405 1.1 christos char *str; 406 1.1 christos int lnum; 407 1.1 christos u_32_t *ipp; 408 1.1 christos u_short *portp; 409 1.1 christos { 410 1.1 christos struct servent *sp; 411 1.1 christos struct hostent *hp; 412 1.1 christos char *host, *port; 413 1.1 christos struct in_addr ip; 414 1.1 christos 415 1.1 christos host = str; 416 1.1 christos port = strchr(host, ','); 417 1.1 christos if (port) 418 1.1 christos *port++ = '\0'; 419 1.1 christos 420 1.1 christos #ifdef HAVE_INET_ATON 421 1.1 christos if (ISDIGIT(*host) && inet_aton(host, &ip)) 422 1.1 christos *ipp = ip.s_addr; 423 1.1 christos #else 424 1.1 christos if (ISDIGIT(*host)) 425 1.1 christos *ipp = inet_addr(host); 426 1.1 christos #endif 427 1.1 christos else { 428 1.1 christos if (!(hp = gethostbyname(host))) { 429 1.1 christos fprintf(stderr, "%d: can't resolve hostname: %s\n", 430 1.1 christos lnum, host); 431 1.1 christos return 0; 432 1.1 christos } 433 1.1 christos *ipp = *(u_32_t *)hp->h_addr; 434 1.1 christos } 435 1.1 christos 436 1.1 christos if (port) { 437 1.1 christos if (ISDIGIT(*port)) 438 1.1 christos *portp = htons(atoi(port)); 439 1.1 christos else { 440 1.1 christos sp = getservbyname(port, "tcp"); 441 1.1 christos if (sp) 442 1.1 christos *portp = sp->s_port; 443 1.1 christos else { 444 1.1 christos fprintf(stderr, "%d: unknown service %s\n", 445 1.1 christos lnum, port); 446 1.1 christos return 0; 447 1.1 christos } 448 1.1 christos } 449 1.1 christos } else 450 1.1 christos *portp = 0; 451 1.1 christos return 1; 452 1.1 christos } 453 1.1 christos 454 1.1 christos 455 1.1 christos char *mapfile(file, sizep) 456 1.1 christos char *file; 457 1.1 christos size_t *sizep; 458 1.1 christos { 459 1.1 christos struct stat sb; 460 1.1 christos caddr_t addr; 461 1.1 christos int fd; 462 1.1 christos 463 1.1 christos fd = open(file, O_RDONLY); 464 1.1 christos if (fd == -1) { 465 1.1 christos perror("open(mapfile)"); 466 1.1 christos return NULL; 467 1.1 christos } 468 1.1 christos 469 1.1 christos if (fstat(fd, &sb) == -1) { 470 1.1 christos perror("fstat(mapfile)"); 471 1.1 christos close(fd); 472 1.1 christos return NULL; 473 1.1 christos } 474 1.1 christos 475 1.1 christos addr = mmap(NULL, sb.st_size, PROT_READ, MAP_SHARED, fd, 0); 476 1.1 christos if (addr == (caddr_t)-1) { 477 1.1 christos perror("mmap(mapfile)"); 478 1.1 christos close(fd); 479 1.1 christos return NULL; 480 1.1 christos } 481 1.1 christos close(fd); 482 1.1 christos *sizep = sb.st_size; 483 1.1 christos return (char *)addr; 484 1.1 christos } 485 1.1 christos 486 1.1 christos 487 1.1 christos int readconfig(filename) 488 1.1 christos char *filename; 489 1.1 christos { 490 1.1 christos char c, buf[512], *s, *t, *errtxt = NULL, *line; 491 1.1 christos int num, err = 0; 492 1.1 christos ipnat_t *ipn; 493 1.1 christos l4cfg_t *l4; 494 1.1 christos FILE *fp; 495 1.1 christos 496 1.1 christos fp = fopen(filename, "r"); 497 1.1 christos if (!fp) { 498 1.1 christos perror("open(configfile)"); 499 1.1 christos return -1; 500 1.1 christos } 501 1.1 christos 502 1.1 christos bzero((char *)&template, sizeof(template)); 503 1.1 christos template.l4_fd = -1; 504 1.1 christos template.l4_rw = -1; 505 1.1 christos template.l4_sin.sin_family = AF_INET; 506 1.1 christos ipn = &template.l4_nat; 507 1.1 christos ipn->in_flags = IPN_TCP|IPN_ROUNDR; 508 1.1 christos ipn->in_redir = NAT_REDIRECT; 509 1.1 christos 510 1.1 christos for (num = 1; fgets(buf, sizeof(buf), fp); num++) { 511 1.1 christos s = strchr(buf, '\n'); 512 1.1 christos if (!s) { 513 1.1 christos fprintf(stderr, "%d: line too long\n", num); 514 1.1 christos fclose(fp); 515 1.1 christos return -1; 516 1.1 christos } 517 1.1 christos 518 1.1 christos *s = '\0'; 519 1.1 christos 520 1.1 christos /* 521 1.1 christos * lines which are comments 522 1.1 christos */ 523 1.1 christos s = strchr(buf, '#'); 524 1.1 christos if (s) 525 1.1 christos *s = '\0'; 526 1.1 christos 527 1.1 christos /* 528 1.1 christos * Skip leading whitespace 529 1.1 christos */ 530 1.1 christos for (line = buf; (c = *line) && ISSPACE(c); line++) 531 1.1 christos ; 532 1.1 christos if (!*line) 533 1.1 christos continue; 534 1.1 christos 535 1.1 christos if (opts & OPT_VERBOSE) 536 1.1 christos fprintf(stderr, "Parsing: [%s]\n", line); 537 1.1 christos t = strtok(line, " \t"); 538 1.1 christos if (!t) 539 1.1 christos continue; 540 1.1 christos if (!strcasecmp(t, "interface")) { 541 1.1 christos s = strtok(NULL, " \t"); 542 1.1 christos if (s) 543 1.1 christos t = strtok(NULL, "\t"); 544 1.1 christos if (!s || !t) { 545 1.1 christos errtxt = line; 546 1.1 christos err = -1; 547 1.1 christos break; 548 1.1 christos } 549 1.1 christos 550 1.1 christos if (!strchr(t, ',')) { 551 1.1 christos fprintf(stderr, 552 1.1 christos "%d: local address,port missing\n", 553 1.1 christos num); 554 1.1 christos err = -1; 555 1.1 christos break; 556 1.1 christos } 557 1.1 christos 558 1.1 christos strncpy(ipn->in_ifname, s, sizeof(ipn->in_ifname)); 559 1.1 christos if (!gethostport(t, num, &ipn->in_outip, 560 1.1 christos &ipn->in_pmin)) { 561 1.1 christos errtxt = line; 562 1.1 christos err = -1; 563 1.1 christos break; 564 1.1 christos } 565 1.1 christos ipn->in_outmsk = 0xffffffff; 566 1.1 christos ipn->in_pmax = ipn->in_pmin; 567 1.1 christos if (opts & OPT_VERBOSE) 568 1.1 christos fprintf(stderr, 569 1.1 christos "Interface %s %s/%#x port %u\n", 570 1.1 christos ipn->in_ifname, 571 1.1 christos inet_ntoa(ipn->in_out[0]), 572 1.1 christos ipn->in_outmsk, ipn->in_pmin); 573 1.1 christos } else if (!strcasecmp(t, "remote")) { 574 1.1 christos if (!*ipn->in_ifname) { 575 1.1 christos fprintf(stderr, 576 1.1 christos "%d: ifname not set prior to remote\n", 577 1.1 christos num); 578 1.1 christos err = -1; 579 1.1 christos break; 580 1.1 christos } 581 1.1 christos s = strtok(NULL, " \t"); 582 1.1 christos if (s) 583 1.1 christos t = strtok(NULL, ""); 584 1.1 christos if (!s || !t || strcasecmp(s, "server")) { 585 1.1 christos errtxt = line; 586 1.1 christos err = -1; 587 1.1 christos break; 588 1.1 christos } 589 1.1 christos 590 1.1 christos ipn->in_pnext = 0; 591 1.1 christos if (!gethostport(t, num, &ipn->in_inip, 592 1.1 christos &ipn->in_pnext)) { 593 1.1 christos errtxt = line; 594 1.1 christos err = -1; 595 1.1 christos break; 596 1.1 christos } 597 1.1 christos ipn->in_inmsk = 0xffffffff; 598 1.1 christos if (ipn->in_pnext == 0) 599 1.1 christos ipn->in_pnext = ipn->in_pmin; 600 1.1 christos 601 1.1 christos l4 = (l4cfg_t *)malloc(sizeof(*l4)); 602 1.1 christos if (!l4) { 603 1.1 christos fprintf(stderr, "%d: out of memory (%d)\n", 604 1.1 christos num, sizeof(*l4)); 605 1.1 christos err = -1; 606 1.1 christos break; 607 1.1 christos } 608 1.1 christos bcopy((char *)&template, (char *)l4, sizeof(*l4)); 609 1.1 christos l4->l4_sin.sin_addr = ipn->in_in[0]; 610 1.1 christos l4->l4_sin.sin_port = ipn->in_pnext; 611 1.1 christos l4->l4_next = l4list; 612 1.1 christos l4list = l4; 613 1.1 christos } else if (!strcasecmp(t, "connect")) { 614 1.1 christos s = strtok(NULL, " \t"); 615 1.1 christos if (s) 616 1.1 christos t = strtok(NULL, "\t"); 617 1.1 christos if (!s || !t) { 618 1.1 christos errtxt = line; 619 1.1 christos err = -1; 620 1.1 christos break; 621 1.1 christos } else if (!strcasecmp(s, "timeout")) { 622 1.1 christos ctimeout = atoi(t); 623 1.1 christos if (opts & OPT_VERBOSE) 624 1.1 christos fprintf(stderr, "connect timeout %d\n", 625 1.1 christos ctimeout); 626 1.1 christos } else if (!strcasecmp(s, "frequency")) { 627 1.1 christos frequency = atoi(t); 628 1.1 christos if (opts & OPT_VERBOSE) 629 1.1 christos fprintf(stderr, 630 1.1 christos "connect frequency %d\n", 631 1.1 christos frequency); 632 1.1 christos } else { 633 1.1 christos errtxt = line; 634 1.1 christos err = -1; 635 1.1 christos break; 636 1.1 christos } 637 1.1 christos } else if (!strcasecmp(t, "probe")) { 638 1.1 christos s = strtok(NULL, " \t"); 639 1.1 christos if (!s) { 640 1.1 christos errtxt = line; 641 1.1 christos err = -1; 642 1.1 christos break; 643 1.1 christos } else if (!strcasecmp(s, "string")) { 644 1.1 christos if (probe) { 645 1.1 christos fprintf(stderr, 646 1.1 christos "%d: probe already set\n", 647 1.1 christos num); 648 1.1 christos err = -1; 649 1.1 christos break; 650 1.1 christos } 651 1.1 christos t = strtok(NULL, ""); 652 1.1 christos if (!t) { 653 1.1 christos fprintf(stderr, 654 1.1 christos "%d: No probe string\n", num); 655 1.1 christos err = -1; 656 1.1 christos break; 657 1.1 christos } 658 1.1 christos 659 1.1 christos probe = malloc(strlen(t)); 660 1.1 christos copystr(probe, t); 661 1.1 christos plen = strlen(probe); 662 1.1 christos if (opts & OPT_VERBOSE) 663 1.1 christos fprintf(stderr, "Probe string [%s]\n", 664 1.1 christos probe); 665 1.1 christos } else if (!strcasecmp(s, "file")) { 666 1.1 christos t = strtok(NULL, " \t"); 667 1.1 christos if (!t) { 668 1.1 christos errtxt = line; 669 1.1 christos err = -1; 670 1.1 christos break; 671 1.1 christos } 672 1.1 christos if (probe) { 673 1.1 christos fprintf(stderr, 674 1.1 christos "%d: probe already set\n", 675 1.1 christos num); 676 1.1 christos err = -1; 677 1.1 christos break; 678 1.1 christos } 679 1.1 christos probe = mapfile(t, &plen); 680 1.1 christos if (opts & OPT_VERBOSE) 681 1.1 christos fprintf(stderr, 682 1.1 christos "Probe file %s len %u@%p\n", 683 1.1 christos t, plen, probe); 684 1.1 christos } 685 1.1 christos } else if (!strcasecmp(t, "response")) { 686 1.1 christos s = strtok(NULL, " \t"); 687 1.1 christos if (!s) { 688 1.1 christos errtxt = line; 689 1.1 christos err = -1; 690 1.1 christos break; 691 1.1 christos } else if (!strcasecmp(s, "timeout")) { 692 1.1 christos t = strtok(NULL, " \t"); 693 1.1 christos if (!t) { 694 1.1 christos errtxt = line; 695 1.1 christos err = -1; 696 1.1 christos break; 697 1.1 christos } 698 1.1 christos rtimeout = atoi(t); 699 1.1 christos if (opts & OPT_VERBOSE) 700 1.1 christos fprintf(stderr, 701 1.1 christos "response timeout %d\n", 702 1.1 christos rtimeout); 703 1.1 christos } else if (!strcasecmp(s, "string")) { 704 1.1 christos if (response) { 705 1.1 christos fprintf(stderr, 706 1.1 christos "%d: response already set\n", 707 1.1 christos num); 708 1.1 christos err = -1; 709 1.1 christos break; 710 1.1 christos } 711 1.1 christos response = strdup(strtok(NULL, "")); 712 1.1 christos rlen = strlen(response); 713 1.1 christos template.l4_rsize = rlen; 714 1.1 christos template.l4_rbuf = malloc(rlen); 715 1.1 christos if (opts & OPT_VERBOSE) 716 1.1 christos fprintf(stderr, 717 1.1 christos "Response string [%s]\n", 718 1.1 christos response); 719 1.1 christos } else if (!strcasecmp(s, "file")) { 720 1.1 christos t = strtok(NULL, " \t"); 721 1.1 christos if (!t) { 722 1.1 christos errtxt = line; 723 1.1 christos err = -1; 724 1.1 christos break; 725 1.1 christos } 726 1.1 christos if (response) { 727 1.1 christos fprintf(stderr, 728 1.1 christos "%d: response already set\n", 729 1.1 christos num); 730 1.1 christos err = -1; 731 1.1 christos break; 732 1.1 christos } 733 1.1 christos response = mapfile(t, &rlen); 734 1.1 christos template.l4_rsize = rlen; 735 1.1 christos template.l4_rbuf = malloc(rlen); 736 1.1 christos if (opts & OPT_VERBOSE) 737 1.1 christos fprintf(stderr, 738 1.1 christos "Response file %s len %u@%p\n", 739 1.1 christos t, rlen, response); 740 1.1 christos } 741 1.1 christos } else { 742 1.1 christos errtxt = line; 743 1.1 christos err = -1; 744 1.1 christos break; 745 1.1 christos } 746 1.1 christos } 747 1.1 christos 748 1.1 christos if (errtxt) 749 1.1 christos fprintf(stderr, "%d: syntax error at \"%s\"\n", num, errtxt); 750 1.1 christos fclose(fp); 751 1.1 christos return err; 752 1.1 christos } 753 1.1 christos 754 1.1 christos 755 1.1 christos void usage(prog) 756 1.1 christos char *prog; 757 1.1 christos { 758 1.1 christos fprintf(stderr, "Usage: %s -f <configfile>\n", prog); 759 1.1 christos exit(1); 760 1.1 christos } 761 1.1 christos 762 1.1 christos 763 1.1 christos int main(argc, argv) 764 1.1 christos int argc; 765 1.1 christos char *argv[]; 766 1.1 christos { 767 1.1 christos char *config = NULL; 768 1.1 christos int c; 769 1.1 christos 770 1.1 christos while ((c = getopt(argc, argv, "f:nv")) != -1) 771 1.1 christos switch (c) 772 1.1 christos { 773 1.1 christos case 'f' : 774 1.1 christos config = optarg; 775 1.1 christos break; 776 1.1 christos case 'n' : 777 1.1 christos opts |= OPT_DONOTHING; 778 1.1 christos break; 779 1.1 christos case 'v' : 780 1.1 christos opts |= OPT_VERBOSE; 781 1.1 christos break; 782 1.1 christos } 783 1.1 christos 784 1.1 christos if (config == NULL) 785 1.1 christos usage(argv[0]); 786 1.1 christos 787 1.1 christos if (readconfig(config)) 788 1.1 christos exit(1); 789 1.1 christos 790 1.1 christos if (!l4list) { 791 1.1 christos fprintf(stderr, "No remote servers, exiting."); 792 1.1 christos exit(1); 793 1.1 christos } 794 1.1 christos 795 1.1 christos if (!(opts & OPT_DONOTHING)) { 796 1.1 christos natfd = open(IPL_NAT, O_RDWR); 797 1.1 christos if (natfd == -1) { 798 1.1 christos perror("open(IPL_NAT)"); 799 1.1 christos exit(1); 800 1.1 christos } 801 1.1 christos } 802 1.1 christos 803 1.1 christos if (opts & OPT_VERBOSE) 804 1.1 christos fprintf(stderr, "Starting...\n"); 805 1.1 christos while (runconfig() == 0) 806 1.1 christos ; 807 1.1 christos } 808