l4check.c revision 145519
1170754Sdelphij/* $FreeBSD: head/contrib/ipfilter/l4check/l4check.c 145519 2005-04-25 18:20:15Z darrenr $ */ 2170754Sdelphij 3170754Sdelphij/* 4170754Sdelphij * (C)Copyright March, 2000 - Darren Reed. 5170754Sdelphij */ 6170754Sdelphij#include <sys/types.h> 7170754Sdelphij#include <sys/stat.h> 8170754Sdelphij#include <sys/mman.h> 9170754Sdelphij#include <sys/socket.h> 10170754Sdelphij#include <sys/time.h> 11170754Sdelphij#include <sys/ioctl.h> 12170754Sdelphij 13170754Sdelphij#include <netinet/in.h> 14170754Sdelphij#include <netinet/in_systm.h> 15170754Sdelphij#include <netinet/ip.h> 16170754Sdelphij 17170754Sdelphij#include <net/if.h> 18170754Sdelphij 19170754Sdelphij#include <stdio.h> 20170754Sdelphij#include <netdb.h> 21170754Sdelphij#include <string.h> 22170754Sdelphij#include <ctype.h> 23170754Sdelphij#include <fcntl.h> 24170754Sdelphij#include <errno.h> 25170754Sdelphij#include <stdlib.h> 26170754Sdelphij 27170754Sdelphij#include "ip_compat.h" 28170754Sdelphij#include "ip_fil.h" 29170754Sdelphij#include "ip_nat.h" 30170754Sdelphij 31170754Sdelphij#include "ipf.h" 32170754Sdelphij 33170754Sdelphijextern char *optarg; 34170754Sdelphij 35170754Sdelphij 36170754Sdelphijtypedef struct l4cfg { 37170754Sdelphij struct l4cfg *l4_next; 38170754Sdelphij struct ipnat l4_nat; /* NAT rule */ 39170754Sdelphij struct sockaddr_in l4_sin; /* remote socket to connect */ 40170754Sdelphij time_t l4_last; /* when we last connected */ 41170754Sdelphij int l4_alive; /* 1 = remote alive */ 42170754Sdelphij int l4_fd; 43170754Sdelphij int l4_rw; /* 0 = reading, 1 = writing */ 44170754Sdelphij char *l4_rbuf; /* read buffer */ 45170754Sdelphij int l4_rsize; /* size of buffer */ 46170754Sdelphij int l4_rlen; /* how much used */ 47170754Sdelphij char *l4_wptr; /* next byte to write */ 48170754Sdelphij int l4_wlen; /* length yet to be written */ 49170754Sdelphij} l4cfg_t; 50170754Sdelphij 51170754Sdelphij 52170754Sdelphijl4cfg_t *l4list = NULL; 53170754Sdelphijchar *response = NULL; 54170754Sdelphijchar *probe = NULL; 55170754Sdelphijl4cfg_t template; 56170754Sdelphijint frequency = 20; 57170754Sdelphijint ctimeout = 1; 58170754Sdelphijint rtimeout = 1; 59170754Sdelphijsize_t plen = 0; 60170754Sdelphijsize_t rlen = 0; 61170754Sdelphijint natfd = -1; 62170754Sdelphijint opts = 0; 63170754Sdelphij 64170754Sdelphij#if defined(sun) && !defined(__svr4__) && !defined(__SVR4) 65170754Sdelphij# define strerror(x) sys_errlist[x] 66170754Sdelphij#endif 67170754Sdelphij 68170754Sdelphij 69170754Sdelphijchar *copystr(dst, src) 70170754Sdelphijchar *dst, *src; 71170754Sdelphij{ 72170754Sdelphij register char *s, *t, c; 73170754Sdelphij register int esc = 0; 74170754Sdelphij 75170754Sdelphij for (s = src, t = dst; s && t && (c = *s++); ) 76170754Sdelphij if (esc) { 77170754Sdelphij esc = 0; 78170754Sdelphij switch (c) 79170754Sdelphij { 80170754Sdelphij case 'n' : 81170754Sdelphij *t++ = '\n'; 82170754Sdelphij break; 83170754Sdelphij case 'r' : 84170754Sdelphij *t++ = '\r'; 85170754Sdelphij break; 86170754Sdelphij case 't' : 87170754Sdelphij *t++ = '\t'; 88170754Sdelphij break; 89170754Sdelphij } 90170754Sdelphij } else if (c != '\\') 91170754Sdelphij *t++ = c; 92170754Sdelphij else 93170754Sdelphij esc = 1; 94170754Sdelphij *t = '\0'; 95170754Sdelphij return dst; 96170754Sdelphij} 97170754Sdelphij 98170754Sdelphijvoid addnat(l4) 99170754Sdelphijl4cfg_t *l4; 100170754Sdelphij{ 101170754Sdelphij ipnat_t *ipn = &l4->l4_nat; 102170754Sdelphij 103170754Sdelphij printf("Add NAT rule for %s/%#x,%u -> ", inet_ntoa(ipn->in_out[0]), 104170754Sdelphij ipn->in_outmsk, ntohs(ipn->in_pmin)); 105170754Sdelphij printf("%s,%u\n", inet_ntoa(ipn->in_in[0]), ntohs(ipn->in_pnext)); 106170754Sdelphij if (!(opts & OPT_DONOTHING)) { 107170754Sdelphij if (ioctl(natfd, SIOCADNAT, &ipn) == -1) 108170754Sdelphij perror("ioctl(SIOCADNAT)"); 109170754Sdelphij } 110170754Sdelphij} 111170754Sdelphij 112170754Sdelphij 113170754Sdelphijvoid delnat(l4) 114170754Sdelphijl4cfg_t *l4; 115170754Sdelphij{ 116170754Sdelphij ipnat_t *ipn = &l4->l4_nat; 117170754Sdelphij 118170754Sdelphij printf("Remove NAT rule for %s/%#x,%u -> ", 119170754Sdelphij inet_ntoa(ipn->in_out[0]), ipn->in_outmsk, ipn->in_pmin); 120170754Sdelphij printf("%s,%u\n", inet_ntoa(ipn->in_in[0]), ipn->in_pnext); 121170754Sdelphij if (!(opts & OPT_DONOTHING)) { 122170754Sdelphij if (ioctl(natfd, SIOCRMNAT, &ipn) == -1) 123170754Sdelphij perror("ioctl(SIOCRMNAT)"); 124170754Sdelphij } 125170754Sdelphij} 126170754Sdelphij 127170754Sdelphij 128170754Sdelphijvoid connectl4(l4) 129170754Sdelphijl4cfg_t *l4; 130170754Sdelphij{ 131170754Sdelphij l4->l4_rw = 1; 132170754Sdelphij l4->l4_rlen = 0; 133170754Sdelphij l4->l4_wlen = plen; 134170754Sdelphij if (!l4->l4_wlen) { 135170754Sdelphij l4->l4_alive = 1; 136170754Sdelphij addnat(l4); 137170754Sdelphij } else 138170754Sdelphij l4->l4_wptr = probe; 139170754Sdelphij} 140170754Sdelphij 141170754Sdelphij 142170754Sdelphijvoid closel4(l4, dead) 143170754Sdelphijl4cfg_t *l4; 144170754Sdelphijint dead; 145170754Sdelphij{ 146170754Sdelphij close(l4->l4_fd); 147170754Sdelphij l4->l4_fd = -1; 148170754Sdelphij l4->l4_rw = -1; 149170754Sdelphij if (dead && l4->l4_alive) { 150170754Sdelphij l4->l4_alive = 0; 151170754Sdelphij delnat(l4); 152170754Sdelphij } 153170754Sdelphij} 154170754Sdelphij 155170754Sdelphij 156170754Sdelphijvoid connectfd(l4) 157170754Sdelphijl4cfg_t *l4; 158170754Sdelphij{ 159170754Sdelphij if (connect(l4->l4_fd, (struct sockaddr *)&l4->l4_sin, 160170754Sdelphij sizeof(l4->l4_sin)) == -1) { 161170754Sdelphij if (errno == EISCONN) { 162170754Sdelphij if (opts & OPT_VERBOSE) 163170754Sdelphij fprintf(stderr, "Connected fd %d\n", 164170754Sdelphij l4->l4_fd); 165170754Sdelphij connectl4(l4); 166170754Sdelphij return; 167170754Sdelphij } 168170754Sdelphij if (opts & OPT_VERBOSE) 169170754Sdelphij fprintf(stderr, "Connect failed fd %d: %s\n", 170170754Sdelphij l4->l4_fd, strerror(errno)); 171170754Sdelphij closel4(l4, 1); 172170754Sdelphij return; 173170754Sdelphij } 174170754Sdelphij l4->l4_rw = 1; 175170754Sdelphij} 176170754Sdelphij 177170754Sdelphij 178170754Sdelphijvoid writefd(l4) 179170754Sdelphijl4cfg_t *l4; 180170754Sdelphij{ 181170754Sdelphij char buf[80], *ptr; 182170754Sdelphij int n, i, fd; 183170754Sdelphij 184170754Sdelphij fd = l4->l4_fd; 185170754Sdelphij 186170754Sdelphij if (l4->l4_rw == -2) { 187170754Sdelphij connectfd(l4); 188170754Sdelphij return; 189170754Sdelphij } 190170754Sdelphij 191170754Sdelphij n = l4->l4_wlen; 192170754Sdelphij 193170754Sdelphij i = send(fd, l4->l4_wptr, n, 0); 194170754Sdelphij if (i == 0 || i == -1) { 195170754Sdelphij if (opts & OPT_VERBOSE) 196170754Sdelphij fprintf(stderr, "Send on fd %d failed: %s\n", 197170754Sdelphij fd, strerror(errno)); 198170754Sdelphij closel4(l4, 1); 199170754Sdelphij } else { 200170754Sdelphij l4->l4_wptr += i; 201170754Sdelphij l4->l4_wlen -= i; 202170754Sdelphij if (l4->l4_wlen == 0) 203170754Sdelphij l4->l4_rw = 0; 204170754Sdelphij if (opts & OPT_VERBOSE) 205170754Sdelphij fprintf(stderr, "Sent %d bytes to fd %d\n", i, fd); 206170754Sdelphij } 207170754Sdelphij} 208170754Sdelphij 209170754Sdelphij 210170754Sdelphijvoid readfd(l4) 211170754Sdelphijl4cfg_t *l4; 212170754Sdelphij{ 213170754Sdelphij char buf[80], *ptr; 214170754Sdelphij int n, i, fd; 215170754Sdelphij 216170754Sdelphij fd = l4->l4_fd; 217170754Sdelphij 218170754Sdelphij if (l4->l4_rw == -2) { 219170754Sdelphij connectfd(l4); 220170754Sdelphij return; 221170754Sdelphij } 222170754Sdelphij 223170754Sdelphij if (l4->l4_rsize) { 224170754Sdelphij n = l4->l4_rsize - l4->l4_rlen; 225170754Sdelphij ptr = l4->l4_rbuf + l4->l4_rlen; 226170754Sdelphij } else { 227170754Sdelphij n = sizeof(buf) - 1; 228170754Sdelphij ptr = buf; 229170754Sdelphij } 230170754Sdelphij 231170754Sdelphij if (opts & OPT_VERBOSE) 232170754Sdelphij fprintf(stderr, "Read %d bytes on fd %d to %p\n", 233170754Sdelphij n, fd, ptr); 234170754Sdelphij i = recv(fd, ptr, n, 0); 235170754Sdelphij if (i == 0 || i == -1) { 236170754Sdelphij if (opts & OPT_VERBOSE) 237170754Sdelphij fprintf(stderr, "Read error on fd %d: %s\n", 238170754Sdelphij fd, (i == 0) ? "EOF" : strerror(errno)); 239170754Sdelphij closel4(l4, 1); 240170754Sdelphij } else { 241170754Sdelphij if (ptr == buf) 242170754Sdelphij ptr[i] = '\0'; 243170754Sdelphij if (opts & OPT_VERBOSE) 244170754Sdelphij fprintf(stderr, "%d: Read %d bytes [%*.*s]\n", 245170754Sdelphij fd, i, i, i, ptr); 246170754Sdelphij if (ptr != buf) { 247170754Sdelphij l4->l4_rlen += i; 248170754Sdelphij if (l4->l4_rlen >= l4->l4_rsize) { 249170754Sdelphij if (!strncmp(response, l4->l4_rbuf, 250170754Sdelphij l4->l4_rsize)) { 251170754Sdelphij printf("%d: Good response\n", 252170754Sdelphij fd); 253170754Sdelphij if (!l4->l4_alive) { 254170754Sdelphij l4->l4_alive = 1; 255170754Sdelphij addnat(l4); 256170754Sdelphij } 257170754Sdelphij closel4(l4, 0); 258170754Sdelphij } else { 259170754Sdelphij if (opts & OPT_VERBOSE) 260170754Sdelphij printf("%d: Bad response\n", 261170754Sdelphij fd); 262170754Sdelphij closel4(l4, 1); 263170754Sdelphij } 264170754Sdelphij } 265170754Sdelphij } else if (!l4->l4_alive) { 266170754Sdelphij l4->l4_alive = 1; 267170754Sdelphij addnat(l4); 268170754Sdelphij closel4(l4, 0); 269170754Sdelphij } 270170754Sdelphij } 271170754Sdelphij} 272170754Sdelphij 273170754Sdelphij 274170754Sdelphijint runconfig() 275170754Sdelphij{ 276170754Sdelphij int fd, opt, res, mfd, i; 277170754Sdelphij struct timeval tv; 278170754Sdelphij time_t now, now1; 279170754Sdelphij fd_set rfd, wfd; 280170754Sdelphij l4cfg_t *l4; 281170754Sdelphij 282170754Sdelphij mfd = 0; 283170754Sdelphij opt = 1; 284170754Sdelphij now = time(NULL); 285170754Sdelphij 286170754Sdelphij /* 287170754Sdelphij * First, initiate connections that are closed, as required. 288170754Sdelphij */ 289170754Sdelphij for (l4 = l4list; l4; l4 = l4->l4_next) { 290170754Sdelphij if ((l4->l4_last + frequency < now) && (l4->l4_fd == -1)) { 291170754Sdelphij l4->l4_last = now; 292170754Sdelphij fd = socket(AF_INET, SOCK_STREAM, 0); 293170754Sdelphij if (fd == -1) 294170754Sdelphij continue; 295170754Sdelphij setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &opt, 296170754Sdelphij sizeof(opt)); 297170754Sdelphij#ifdef O_NONBLOCK 298170754Sdelphij if ((res = fcntl(fd, F_GETFL, 0)) != -1) 299170754Sdelphij fcntl(fd, F_SETFL, res | O_NONBLOCK); 300170754Sdelphij#endif 301170754Sdelphij if (opts & OPT_VERBOSE) 302170754Sdelphij fprintf(stderr, 303170754Sdelphij "Connecting to %s,%d (fd %d)...", 304170754Sdelphij inet_ntoa(l4->l4_sin.sin_addr), 305170754Sdelphij ntohs(l4->l4_sin.sin_port), fd); 306170754Sdelphij if (connect(fd, (struct sockaddr *)&l4->l4_sin, 307170754Sdelphij sizeof(l4->l4_sin)) == -1) { 308170754Sdelphij if (errno != EINPROGRESS) { 309170754Sdelphij if (opts & OPT_VERBOSE) 310170754Sdelphij fprintf(stderr, "failed\n"); 311170754Sdelphij perror("connect"); 312170754Sdelphij close(fd); 313170754Sdelphij fd = -1; 314170754Sdelphij } else { 315170754Sdelphij if (opts & OPT_VERBOSE) 316170754Sdelphij fprintf(stderr, "waiting\n"); 317170754Sdelphij l4->l4_rw = -2; 318170754Sdelphij } 319170754Sdelphij } else { 320170754Sdelphij if (opts & OPT_VERBOSE) 321170754Sdelphij fprintf(stderr, "connected\n"); 322170754Sdelphij connectl4(l4); 323170754Sdelphij } 324170754Sdelphij l4->l4_fd = fd; 325170754Sdelphij } 326170754Sdelphij } 327170754Sdelphij 328170754Sdelphij /* 329170754Sdelphij * Now look for fd's which we're expecting to read/write from. 330170754Sdelphij */ 331170754Sdelphij FD_ZERO(&rfd); 332170754Sdelphij FD_ZERO(&wfd); 333170754Sdelphij tv.tv_sec = MIN(rtimeout, ctimeout); 334170754Sdelphij tv.tv_usec = 0; 335170754Sdelphij 336170754Sdelphij for (l4 = l4list; l4; l4 = l4->l4_next) 337170754Sdelphij if (l4->l4_rw == 0) { 338170754Sdelphij if (now - l4->l4_last > rtimeout) { 339170754Sdelphij if (opts & OPT_VERBOSE) 340170754Sdelphij fprintf(stderr, "%d: Read timeout\n", 341170754Sdelphij l4->l4_fd); 342170754Sdelphij closel4(l4, 1); 343170754Sdelphij continue; 344170754Sdelphij } 345170754Sdelphij if (opts & OPT_VERBOSE) 346170754Sdelphij fprintf(stderr, "Wait for read on fd %d\n", 347170754Sdelphij l4->l4_fd); 348170754Sdelphij FD_SET(l4->l4_fd, &rfd); 349170754Sdelphij if (l4->l4_fd > mfd) 350170754Sdelphij mfd = l4->l4_fd; 351170754Sdelphij } else if ((l4->l4_rw == 1 && l4->l4_wlen) || 352170754Sdelphij l4->l4_rw == -2) { 353170754Sdelphij if ((l4->l4_rw == -2) && 354170754Sdelphij (now - l4->l4_last > ctimeout)) { 355170754Sdelphij if (opts & OPT_VERBOSE) 356170754Sdelphij fprintf(stderr, 357170754Sdelphij "%d: connect timeout\n", 358170754Sdelphij l4->l4_fd); 359170754Sdelphij closel4(l4); 360170754Sdelphij continue; 361170754Sdelphij } 362170754Sdelphij if (opts & OPT_VERBOSE) 363170754Sdelphij fprintf(stderr, "Wait for write on fd %d\n", 364170754Sdelphij l4->l4_fd); 365170754Sdelphij FD_SET(l4->l4_fd, &wfd); 366170754Sdelphij if (l4->l4_fd > mfd) 367170754Sdelphij mfd = l4->l4_fd; 368170754Sdelphij } 369170754Sdelphij 370170754Sdelphij if (opts & OPT_VERBOSE) 371170754Sdelphij fprintf(stderr, "Select: max fd %d wait %d\n", mfd + 1, 372170754Sdelphij tv.tv_sec); 373170754Sdelphij i = select(mfd + 1, &rfd, &wfd, NULL, &tv); 374170754Sdelphij if (i == -1) { 375170754Sdelphij perror("select"); 376170754Sdelphij return -1; 377170754Sdelphij } 378170754Sdelphij 379170754Sdelphij now1 = time(NULL); 380170754Sdelphij 381170754Sdelphij for (l4 = l4list; (i > 0) && l4; l4 = l4->l4_next) { 382170754Sdelphij if (l4->l4_fd < 0) 383170754Sdelphij continue; 384170754Sdelphij if (FD_ISSET(l4->l4_fd, &rfd)) { 385170754Sdelphij if (opts & OPT_VERBOSE) 386170754Sdelphij fprintf(stderr, "Ready to read on fd %d\n", 387170754Sdelphij l4->l4_fd); 388170754Sdelphij readfd(l4); 389170754Sdelphij i--; 390170754Sdelphij } 391170754Sdelphij 392170754Sdelphij if ((l4->l4_fd >= 0) && FD_ISSET(l4->l4_fd, &wfd)) { 393170754Sdelphij if (opts & OPT_VERBOSE) 394170754Sdelphij fprintf(stderr, "Ready to write on fd %d\n", 395170754Sdelphij l4->l4_fd); 396170754Sdelphij writefd(l4); 397170754Sdelphij i--; 398170754Sdelphij } 399170754Sdelphij } 400170754Sdelphij return 0; 401170754Sdelphij} 402170754Sdelphij 403170754Sdelphij 404170754Sdelphijint gethostport(str, lnum, ipp, portp) 405170754Sdelphijchar *str; 406170754Sdelphijint lnum; 407170754Sdelphiju_32_t *ipp; 408170754Sdelphiju_short *portp; 409170754Sdelphij{ 410170754Sdelphij struct servent *sp; 411170754Sdelphij struct hostent *hp; 412170754Sdelphij char *host, *port; 413170754Sdelphij struct in_addr ip; 414170754Sdelphij 415170754Sdelphij host = str; 416170754Sdelphij port = strchr(host, ','); 417170754Sdelphij if (port) 418170754Sdelphij *port++ = '\0'; 419170754Sdelphij 420170754Sdelphij#ifdef HAVE_INET_ATON 421170754Sdelphij if (ISDIGIT(*host) && inet_aton(host, &ip)) 422170754Sdelphij *ipp = ip.s_addr; 423170754Sdelphij#else 424170754Sdelphij if (ISDIGIT(*host)) 425170754Sdelphij *ipp = inet_addr(host); 426170754Sdelphij#endif 427170754Sdelphij else { 428170754Sdelphij if (!(hp = gethostbyname(host))) { 429170754Sdelphij fprintf(stderr, "%d: can't resolve hostname: %s\n", 430170754Sdelphij lnum, host); 431170754Sdelphij return 0; 432170754Sdelphij } 433170754Sdelphij *ipp = *(u_32_t *)hp->h_addr; 434170754Sdelphij } 435170754Sdelphij 436170754Sdelphij if (port) { 437170754Sdelphij if (ISDIGIT(*port)) 438170754Sdelphij *portp = htons(atoi(port)); 439170754Sdelphij else { 440170754Sdelphij sp = getservbyname(port, "tcp"); 441170754Sdelphij if (sp) 442170754Sdelphij *portp = sp->s_port; 443170754Sdelphij else { 444170754Sdelphij fprintf(stderr, "%d: unknown service %s\n", 445170754Sdelphij lnum, port); 446170754Sdelphij return 0; 447170754Sdelphij } 448170754Sdelphij } 449170754Sdelphij } else 450170754Sdelphij *portp = 0; 451170754Sdelphij return 1; 452170754Sdelphij} 453170754Sdelphij 454170754Sdelphij 455170754Sdelphijchar *mapfile(file, sizep) 456170754Sdelphijchar *file; 457170754Sdelphijsize_t *sizep; 458170754Sdelphij{ 459170754Sdelphij struct stat sb; 460170754Sdelphij caddr_t addr; 461170754Sdelphij int fd; 462170754Sdelphij 463170754Sdelphij fd = open(file, O_RDONLY); 464170754Sdelphij if (fd == -1) { 465170754Sdelphij perror("open(mapfile)"); 466170754Sdelphij return NULL; 467170754Sdelphij } 468170754Sdelphij 469170754Sdelphij if (fstat(fd, &sb) == -1) { 470170754Sdelphij perror("fstat(mapfile)"); 471170754Sdelphij close(fd); 472170754Sdelphij return NULL; 473170754Sdelphij } 474170754Sdelphij 475170754Sdelphij addr = mmap(NULL, sb.st_size, PROT_READ, MAP_SHARED, fd, 0); 476170754Sdelphij if (addr == (caddr_t)-1) { 477170754Sdelphij perror("mmap(mapfile)"); 478170754Sdelphij close(fd); 479170754Sdelphij return NULL; 480170754Sdelphij } 481170754Sdelphij close(fd); 482170754Sdelphij *sizep = sb.st_size; 483170754Sdelphij return (char *)addr; 484170754Sdelphij} 485170754Sdelphij 486170754Sdelphij 487170754Sdelphijint readconfig(filename) 488170754Sdelphijchar *filename; 489170754Sdelphij{ 490170754Sdelphij char c, buf[512], *s, *t, *errtxt = NULL, *line; 491170754Sdelphij int num, err = 0; 492170754Sdelphij ipnat_t *ipn; 493170754Sdelphij l4cfg_t *l4; 494170754Sdelphij FILE *fp; 495170754Sdelphij 496170754Sdelphij fp = fopen(filename, "r"); 497170754Sdelphij if (!fp) { 498170754Sdelphij perror("open(configfile)"); 499170754Sdelphij return -1; 500170754Sdelphij } 501170754Sdelphij 502170754Sdelphij bzero((char *)&template, sizeof(template)); 503170754Sdelphij template.l4_fd = -1; 504170754Sdelphij template.l4_rw = -1; 505170754Sdelphij template.l4_sin.sin_family = AF_INET; 506170754Sdelphij ipn = &template.l4_nat; 507170754Sdelphij ipn->in_flags = IPN_TCP|IPN_ROUNDR; 508170754Sdelphij ipn->in_redir = NAT_REDIRECT; 509170754Sdelphij 510170754Sdelphij for (num = 1; fgets(buf, sizeof(buf), fp); num++) { 511170754Sdelphij s = strchr(buf, '\n'); 512170754Sdelphij if (!s) { 513170754Sdelphij fprintf(stderr, "%d: line too long\n", num); 514170754Sdelphij fclose(fp); 515170754Sdelphij return -1; 516170754Sdelphij } 517170754Sdelphij 518170754Sdelphij *s = '\0'; 519170754Sdelphij 520170754Sdelphij /* 521170754Sdelphij * lines which are comments 522170754Sdelphij */ 523170754Sdelphij s = strchr(buf, '#'); 524170754Sdelphij if (s) 525170754Sdelphij *s = '\0'; 526170754Sdelphij 527170754Sdelphij /* 528170754Sdelphij * Skip leading whitespace 529170754Sdelphij */ 530170754Sdelphij for (line = buf; (c = *line) && ISSPACE(c); line++) 531170754Sdelphij ; 532170754Sdelphij if (!*line) 533170754Sdelphij continue; 534170754Sdelphij 535170754Sdelphij if (opts & OPT_VERBOSE) 536170754Sdelphij fprintf(stderr, "Parsing: [%s]\n", line); 537170754Sdelphij t = strtok(line, " \t"); 538170754Sdelphij if (!t) 539170754Sdelphij continue; 540170754Sdelphij if (!strcasecmp(t, "interface")) { 541170754Sdelphij s = strtok(NULL, " \t"); 542170754Sdelphij if (s) 543170754Sdelphij t = strtok(NULL, "\t"); 544170754Sdelphij if (!s || !t) { 545170754Sdelphij errtxt = line; 546170754Sdelphij err = -1; 547170754Sdelphij break; 548170754Sdelphij } 549170754Sdelphij 550170754Sdelphij if (!strchr(t, ',')) { 551170754Sdelphij fprintf(stderr, 552170754Sdelphij "%d: local address,port missing\n", 553170754Sdelphij num); 554170754Sdelphij err = -1; 555170754Sdelphij break; 556170754Sdelphij } 557170754Sdelphij 558170754Sdelphij strncpy(ipn->in_ifname, s, sizeof(ipn->in_ifname)); 559170754Sdelphij if (!gethostport(t, num, &ipn->in_outip, 560170754Sdelphij &ipn->in_pmin)) { 561170754Sdelphij errtxt = line; 562170754Sdelphij err = -1; 563170754Sdelphij break; 564170754Sdelphij } 565170754Sdelphij ipn->in_outmsk = 0xffffffff; 566170754Sdelphij ipn->in_pmax = ipn->in_pmin; 567170754Sdelphij if (opts & OPT_VERBOSE) 568170754Sdelphij fprintf(stderr, 569170754Sdelphij "Interface %s %s/%#x port %u\n", 570170754Sdelphij ipn->in_ifname, 571170754Sdelphij inet_ntoa(ipn->in_out[0]), 572170754Sdelphij ipn->in_outmsk, ipn->in_pmin); 573170754Sdelphij } else if (!strcasecmp(t, "remote")) { 574170754Sdelphij if (!*ipn->in_ifname) { 575170754Sdelphij fprintf(stderr, 576170754Sdelphij "%d: ifname not set prior to remote\n", 577170754Sdelphij num); 578170754Sdelphij err = -1; 579170754Sdelphij break; 580170754Sdelphij } 581170754Sdelphij s = strtok(NULL, " \t"); 582170754Sdelphij if (s) 583170754Sdelphij t = strtok(NULL, ""); 584170754Sdelphij if (!s || !t || strcasecmp(s, "server")) { 585170754Sdelphij errtxt = line; 586170754Sdelphij err = -1; 587170754Sdelphij break; 588170754Sdelphij } 589170754Sdelphij 590170754Sdelphij ipn->in_pnext = 0; 591170754Sdelphij if (!gethostport(t, num, &ipn->in_inip, 592170754Sdelphij &ipn->in_pnext)) { 593170754Sdelphij errtxt = line; 594170754Sdelphij err = -1; 595170754Sdelphij break; 596170754Sdelphij } 597170754Sdelphij ipn->in_inmsk = 0xffffffff; 598170754Sdelphij if (ipn->in_pnext == 0) 599170754Sdelphij ipn->in_pnext = ipn->in_pmin; 600170754Sdelphij 601170754Sdelphij l4 = (l4cfg_t *)malloc(sizeof(*l4)); 602170754Sdelphij if (!l4) { 603170754Sdelphij fprintf(stderr, "%d: out of memory (%d)\n", 604170754Sdelphij num, sizeof(*l4)); 605170754Sdelphij err = -1; 606170754Sdelphij break; 607170754Sdelphij } 608170754Sdelphij bcopy((char *)&template, (char *)l4, sizeof(*l4)); 609170754Sdelphij l4->l4_sin.sin_addr = ipn->in_in[0]; 610170754Sdelphij l4->l4_sin.sin_port = ipn->in_pnext; 611170754Sdelphij l4->l4_next = l4list; 612170754Sdelphij l4list = l4; 613170754Sdelphij } else if (!strcasecmp(t, "connect")) { 614170754Sdelphij s = strtok(NULL, " \t"); 615170754Sdelphij if (s) 616170754Sdelphij t = strtok(NULL, "\t"); 617170754Sdelphij if (!s || !t) { 618170754Sdelphij errtxt = line; 619170754Sdelphij err = -1; 620170754Sdelphij break; 621170754Sdelphij } else if (!strcasecmp(s, "timeout")) { 622170754Sdelphij ctimeout = atoi(t); 623170754Sdelphij if (opts & OPT_VERBOSE) 624170754Sdelphij fprintf(stderr, "connect timeout %d\n", 625170754Sdelphij ctimeout); 626170754Sdelphij } else if (!strcasecmp(s, "frequency")) { 627170754Sdelphij frequency = atoi(t); 628170754Sdelphij if (opts & OPT_VERBOSE) 629170754Sdelphij fprintf(stderr, 630170754Sdelphij "connect frequency %d\n", 631170754Sdelphij frequency); 632170754Sdelphij } else { 633170754Sdelphij errtxt = line; 634170754Sdelphij err = -1; 635170754Sdelphij break; 636170754Sdelphij } 637170754Sdelphij } else if (!strcasecmp(t, "probe")) { 638170754Sdelphij s = strtok(NULL, " \t"); 639170754Sdelphij if (!s) { 640170754Sdelphij errtxt = line; 641170754Sdelphij err = -1; 642170754Sdelphij break; 643170754Sdelphij } else if (!strcasecmp(s, "string")) { 644170754Sdelphij if (probe) { 645170754Sdelphij fprintf(stderr, 646170754Sdelphij "%d: probe already set\n", 647170754Sdelphij num); 648170754Sdelphij err = -1; 649170754Sdelphij break; 650170754Sdelphij } 651170754Sdelphij t = strtok(NULL, ""); 652170754Sdelphij if (!t) { 653170754Sdelphij fprintf(stderr, 654170754Sdelphij "%d: No probe string\n", num); 655170754Sdelphij err = -1; 656170754Sdelphij break; 657170754Sdelphij } 658170754Sdelphij 659170754Sdelphij probe = malloc(strlen(t)); 660170754Sdelphij copystr(probe, t); 661170754Sdelphij plen = strlen(probe); 662170754Sdelphij if (opts & OPT_VERBOSE) 663170754Sdelphij fprintf(stderr, "Probe string [%s]\n", 664170754Sdelphij probe); 665170754Sdelphij } else if (!strcasecmp(s, "file")) { 666170754Sdelphij t = strtok(NULL, " \t"); 667170754Sdelphij if (!t) { 668170754Sdelphij errtxt = line; 669170754Sdelphij err = -1; 670170754Sdelphij break; 671170754Sdelphij } 672170754Sdelphij if (probe) { 673170754Sdelphij fprintf(stderr, 674170754Sdelphij "%d: probe already set\n", 675170754Sdelphij num); 676170754Sdelphij err = -1; 677170754Sdelphij break; 678170754Sdelphij } 679170754Sdelphij probe = mapfile(t, &plen); 680170754Sdelphij if (opts & OPT_VERBOSE) 681170754Sdelphij fprintf(stderr, 682170754Sdelphij "Probe file %s len %u@%p\n", 683170754Sdelphij t, plen, probe); 684170754Sdelphij } 685170754Sdelphij } else if (!strcasecmp(t, "response")) { 686170754Sdelphij s = strtok(NULL, " \t"); 687170754Sdelphij if (!s) { 688170754Sdelphij errtxt = line; 689170754Sdelphij err = -1; 690170754Sdelphij break; 691170754Sdelphij } else if (!strcasecmp(s, "timeout")) { 692170754Sdelphij t = strtok(NULL, " \t"); 693170754Sdelphij if (!t) { 694170754Sdelphij errtxt = line; 695170754Sdelphij err = -1; 696170754Sdelphij break; 697170754Sdelphij } 698170754Sdelphij rtimeout = atoi(t); 699170754Sdelphij if (opts & OPT_VERBOSE) 700170754Sdelphij fprintf(stderr, 701170754Sdelphij "response timeout %d\n", 702170754Sdelphij rtimeout); 703170754Sdelphij } else if (!strcasecmp(s, "string")) { 704170754Sdelphij if (response) { 705170754Sdelphij fprintf(stderr, 706170754Sdelphij "%d: response already set\n", 707170754Sdelphij num); 708170754Sdelphij err = -1; 709170754Sdelphij break; 710170754Sdelphij } 711170754Sdelphij response = strdup(strtok(NULL, "")); 712170754Sdelphij rlen = strlen(response); 713170754Sdelphij template.l4_rsize = rlen; 714170754Sdelphij template.l4_rbuf = malloc(rlen); 715170754Sdelphij if (opts & OPT_VERBOSE) 716170754Sdelphij fprintf(stderr, 717170754Sdelphij "Response string [%s]\n", 718170754Sdelphij response); 719170754Sdelphij } else if (!strcasecmp(s, "file")) { 720170754Sdelphij t = strtok(NULL, " \t"); 721170754Sdelphij if (!t) { 722170754Sdelphij errtxt = line; 723170754Sdelphij err = -1; 724170754Sdelphij break; 725170754Sdelphij } 726170754Sdelphij if (response) { 727170754Sdelphij fprintf(stderr, 728170754Sdelphij "%d: response already set\n", 729170754Sdelphij num); 730170754Sdelphij err = -1; 731170754Sdelphij break; 732170754Sdelphij } 733170754Sdelphij response = mapfile(t, &rlen); 734170754Sdelphij template.l4_rsize = rlen; 735170754Sdelphij template.l4_rbuf = malloc(rlen); 736170754Sdelphij if (opts & OPT_VERBOSE) 737170754Sdelphij fprintf(stderr, 738170754Sdelphij "Response file %s len %u@%p\n", 739170754Sdelphij t, rlen, response); 740170754Sdelphij } 741170754Sdelphij } else { 742170754Sdelphij errtxt = line; 743170754Sdelphij err = -1; 744170754Sdelphij break; 745170754Sdelphij } 746170754Sdelphij } 747170754Sdelphij 748170754Sdelphij if (errtxt) 749170754Sdelphij fprintf(stderr, "%d: syntax error at \"%s\"\n", num, errtxt); 750170754Sdelphij fclose(fp); 751170754Sdelphij return err; 752170754Sdelphij} 753170754Sdelphij 754170754Sdelphij 755170754Sdelphijvoid usage(prog) 756170754Sdelphijchar *prog; 757170754Sdelphij{ 758170754Sdelphij fprintf(stderr, "Usage: %s -f <configfile>\n", prog); 759170754Sdelphij exit(1); 760170754Sdelphij} 761170754Sdelphij 762170754Sdelphij 763170754Sdelphijint main(argc, argv) 764170754Sdelphijint argc; 765170754Sdelphijchar *argv[]; 766170754Sdelphij{ 767170754Sdelphij char *config = NULL; 768170754Sdelphij int c; 769170754Sdelphij 770170754Sdelphij while ((c = getopt(argc, argv, "f:nv")) != -1) 771170754Sdelphij switch (c) 772170754Sdelphij { 773170754Sdelphij case 'f' : 774170754Sdelphij config = optarg; 775170754Sdelphij break; 776 case 'n' : 777 opts |= OPT_DONOTHING; 778 break; 779 case 'v' : 780 opts |= OPT_VERBOSE; 781 break; 782 } 783 784 if (config == NULL) 785 usage(argv[0]); 786 787 if (readconfig(config)) 788 exit(1); 789 790 if (!l4list) { 791 fprintf(stderr, "No remote servers, exiting."); 792 exit(1); 793 } 794 795 if (!(opts & OPT_DONOTHING)) { 796 natfd = open(IPL_NAT, O_RDWR); 797 if (natfd == -1) { 798 perror("open(IPL_NAT)"); 799 exit(1); 800 } 801 } 802 803 if (opts & OPT_VERBOSE) 804 fprintf(stderr, "Starting...\n"); 805 while (runconfig() == 0) 806 ; 807} 808