1145519Sdarrenr/* $FreeBSD$ */ 2145510Sdarrenr 360841Sdarrenr/* 4255332Scy * (C)Copyright (C) 2012 by Darren Reed. 560841Sdarrenr */ 660841Sdarrenr#include <sys/types.h> 760841Sdarrenr#include <sys/stat.h> 860841Sdarrenr#include <sys/mman.h> 960841Sdarrenr#include <sys/socket.h> 1060841Sdarrenr#include <sys/time.h> 1160841Sdarrenr#include <sys/ioctl.h> 1260841Sdarrenr 1360841Sdarrenr#include <netinet/in.h> 1460841Sdarrenr#include <netinet/in_systm.h> 1560841Sdarrenr#include <netinet/ip.h> 1660841Sdarrenr 1760841Sdarrenr#include <net/if.h> 1860841Sdarrenr 1960841Sdarrenr#include <stdio.h> 2060841Sdarrenr#include <netdb.h> 2160841Sdarrenr#include <string.h> 2260841Sdarrenr#include <ctype.h> 2360841Sdarrenr#include <fcntl.h> 2460841Sdarrenr#include <errno.h> 2560841Sdarrenr#include <stdlib.h> 2660841Sdarrenr 2760841Sdarrenr#include "ip_compat.h" 2860841Sdarrenr#include "ip_fil.h" 2960841Sdarrenr#include "ip_nat.h" 3060841Sdarrenr 3160841Sdarrenr#include "ipf.h" 3260841Sdarrenr 3360841Sdarrenrextern char *optarg; 3460841Sdarrenr 3560841Sdarrenr 3660841Sdarrenrtypedef struct l4cfg { 3760841Sdarrenr struct l4cfg *l4_next; 3860841Sdarrenr struct ipnat l4_nat; /* NAT rule */ 3960841Sdarrenr struct sockaddr_in l4_sin; /* remote socket to connect */ 4060841Sdarrenr time_t l4_last; /* when we last connected */ 4160841Sdarrenr int l4_alive; /* 1 = remote alive */ 4260841Sdarrenr int l4_fd; 4360841Sdarrenr int l4_rw; /* 0 = reading, 1 = writing */ 4460841Sdarrenr char *l4_rbuf; /* read buffer */ 4560841Sdarrenr int l4_rsize; /* size of buffer */ 4660841Sdarrenr int l4_rlen; /* how much used */ 4760841Sdarrenr char *l4_wptr; /* next byte to write */ 4860841Sdarrenr int l4_wlen; /* length yet to be written */ 4960841Sdarrenr} l4cfg_t; 5060841Sdarrenr 5160841Sdarrenr 5260841Sdarrenrl4cfg_t *l4list = NULL; 5360841Sdarrenrchar *response = NULL; 5460841Sdarrenrchar *probe = NULL; 5560841Sdarrenrl4cfg_t template; 5660841Sdarrenrint frequency = 20; 5760841Sdarrenrint ctimeout = 1; 5860841Sdarrenrint rtimeout = 1; 5960841Sdarrenrsize_t plen = 0; 6060841Sdarrenrsize_t rlen = 0; 6160841Sdarrenrint natfd = -1; 6260841Sdarrenrint opts = 0; 6360841Sdarrenr 6460841Sdarrenr#if defined(sun) && !defined(__svr4__) && !defined(__SVR4) 6560841Sdarrenr# define strerror(x) sys_errlist[x] 6660841Sdarrenr#endif 6760841Sdarrenr 6860841Sdarrenr 6960841Sdarrenrchar *copystr(dst, src) 70255332Scy char *dst, *src; 7160841Sdarrenr{ 7260841Sdarrenr register char *s, *t, c; 7360841Sdarrenr register int esc = 0; 7460841Sdarrenr 7560841Sdarrenr for (s = src, t = dst; s && t && (c = *s++); ) 7660841Sdarrenr if (esc) { 7760841Sdarrenr esc = 0; 7860841Sdarrenr switch (c) 7960841Sdarrenr { 8060841Sdarrenr case 'n' : 8160841Sdarrenr *t++ = '\n'; 8260841Sdarrenr break; 8360841Sdarrenr case 'r' : 8460841Sdarrenr *t++ = '\r'; 8560841Sdarrenr break; 8660841Sdarrenr case 't' : 8760841Sdarrenr *t++ = '\t'; 8860841Sdarrenr break; 8960841Sdarrenr } 9060841Sdarrenr } else if (c != '\\') 9160841Sdarrenr *t++ = c; 9260841Sdarrenr else 9360841Sdarrenr esc = 1; 9460841Sdarrenr *t = '\0'; 9560841Sdarrenr return dst; 9660841Sdarrenr} 9760841Sdarrenr 9860841Sdarrenrvoid addnat(l4) 99255332Scy l4cfg_t *l4; 10060841Sdarrenr{ 10160841Sdarrenr ipnat_t *ipn = &l4->l4_nat; 10260841Sdarrenr 103255332Scy printf("Add NAT rule for %s/%#x,%u -> ", inet_ntoa(ipn->in_out[0]), 10460841Sdarrenr ipn->in_outmsk, ntohs(ipn->in_pmin)); 105255332Scy printf("%s,%u\n", inet_ntoa(ipn->in_in[0]), ntohs(ipn->in_pnext)); 10660841Sdarrenr if (!(opts & OPT_DONOTHING)) { 107255332Scy if (ioctl(natfd, SIOCADNAT, &ipn) == -1) 10860841Sdarrenr perror("ioctl(SIOCADNAT)"); 10960841Sdarrenr } 11060841Sdarrenr} 11160841Sdarrenr 11260841Sdarrenr 11360841Sdarrenrvoid delnat(l4) 114255332Scy l4cfg_t *l4; 11560841Sdarrenr{ 11660841Sdarrenr ipnat_t *ipn = &l4->l4_nat; 11760841Sdarrenr 11860841Sdarrenr printf("Remove NAT rule for %s/%#x,%u -> ", 119255332Scy inet_ntoa(ipn->in_out[0]), ipn->in_outmsk, ipn->in_pmin); 120255332Scy printf("%s,%u\n", inet_ntoa(ipn->in_in[0]), ipn->in_pnext); 12160841Sdarrenr if (!(opts & OPT_DONOTHING)) { 12260841Sdarrenr if (ioctl(natfd, SIOCRMNAT, &ipn) == -1) 12360841Sdarrenr perror("ioctl(SIOCRMNAT)"); 12460841Sdarrenr } 12560841Sdarrenr} 12660841Sdarrenr 12760841Sdarrenr 12860841Sdarrenrvoid connectl4(l4) 129255332Scy l4cfg_t *l4; 13060841Sdarrenr{ 13160841Sdarrenr l4->l4_rw = 1; 13260841Sdarrenr l4->l4_rlen = 0; 13360841Sdarrenr l4->l4_wlen = plen; 13460841Sdarrenr if (!l4->l4_wlen) { 13560841Sdarrenr l4->l4_alive = 1; 13660841Sdarrenr addnat(l4); 13760841Sdarrenr } else 13860841Sdarrenr l4->l4_wptr = probe; 13960841Sdarrenr} 14060841Sdarrenr 14160841Sdarrenr 14260841Sdarrenrvoid closel4(l4, dead) 143255332Scy l4cfg_t *l4; 144255332Scy int dead; 14560841Sdarrenr{ 146145510Sdarrenr close(l4->l4_fd); 14760841Sdarrenr l4->l4_fd = -1; 14860841Sdarrenr l4->l4_rw = -1; 14960841Sdarrenr if (dead && l4->l4_alive) { 15060841Sdarrenr l4->l4_alive = 0; 15160841Sdarrenr delnat(l4); 15260841Sdarrenr } 15360841Sdarrenr} 15460841Sdarrenr 15560841Sdarrenr 15660841Sdarrenrvoid connectfd(l4) 157255332Scy l4cfg_t *l4; 15860841Sdarrenr{ 15960841Sdarrenr if (connect(l4->l4_fd, (struct sockaddr *)&l4->l4_sin, 16060841Sdarrenr sizeof(l4->l4_sin)) == -1) { 16160841Sdarrenr if (errno == EISCONN) { 16260841Sdarrenr if (opts & OPT_VERBOSE) 16360841Sdarrenr fprintf(stderr, "Connected fd %d\n", 16460841Sdarrenr l4->l4_fd); 16560841Sdarrenr connectl4(l4); 16660841Sdarrenr return; 16760841Sdarrenr } 16860841Sdarrenr if (opts & OPT_VERBOSE) 16960841Sdarrenr fprintf(stderr, "Connect failed fd %d: %s\n", 17060841Sdarrenr l4->l4_fd, strerror(errno)); 17160841Sdarrenr closel4(l4, 1); 17260841Sdarrenr return; 17360841Sdarrenr } 17460841Sdarrenr l4->l4_rw = 1; 17560841Sdarrenr} 17660841Sdarrenr 17760841Sdarrenr 17860841Sdarrenrvoid writefd(l4) 179255332Scy l4cfg_t *l4; 18060841Sdarrenr{ 181255332Scy char buf[80], *ptr; 18260841Sdarrenr int n, i, fd; 18360841Sdarrenr 18460841Sdarrenr fd = l4->l4_fd; 18560841Sdarrenr 18660841Sdarrenr if (l4->l4_rw == -2) { 18760841Sdarrenr connectfd(l4); 18860841Sdarrenr return; 18960841Sdarrenr } 19060841Sdarrenr 19160841Sdarrenr n = l4->l4_wlen; 19260841Sdarrenr 19360841Sdarrenr i = send(fd, l4->l4_wptr, n, 0); 19460841Sdarrenr if (i == 0 || i == -1) { 19560841Sdarrenr if (opts & OPT_VERBOSE) 19660841Sdarrenr fprintf(stderr, "Send on fd %d failed: %s\n", 19760841Sdarrenr fd, strerror(errno)); 19860841Sdarrenr closel4(l4, 1); 19960841Sdarrenr } else { 20060841Sdarrenr l4->l4_wptr += i; 20160841Sdarrenr l4->l4_wlen -= i; 20260841Sdarrenr if (l4->l4_wlen == 0) 20360841Sdarrenr l4->l4_rw = 0; 20460841Sdarrenr if (opts & OPT_VERBOSE) 20560841Sdarrenr fprintf(stderr, "Sent %d bytes to fd %d\n", i, fd); 20660841Sdarrenr } 20760841Sdarrenr} 20860841Sdarrenr 20960841Sdarrenr 21060841Sdarrenrvoid readfd(l4) 211255332Scy l4cfg_t *l4; 21260841Sdarrenr{ 21360841Sdarrenr char buf[80], *ptr; 21460841Sdarrenr int n, i, fd; 21560841Sdarrenr 21660841Sdarrenr fd = l4->l4_fd; 21760841Sdarrenr 21860841Sdarrenr if (l4->l4_rw == -2) { 21960841Sdarrenr connectfd(l4); 22060841Sdarrenr return; 22160841Sdarrenr } 22260841Sdarrenr 22360841Sdarrenr if (l4->l4_rsize) { 22460841Sdarrenr n = l4->l4_rsize - l4->l4_rlen; 22560841Sdarrenr ptr = l4->l4_rbuf + l4->l4_rlen; 22660841Sdarrenr } else { 22760841Sdarrenr n = sizeof(buf) - 1; 22860841Sdarrenr ptr = buf; 22960841Sdarrenr } 23060841Sdarrenr 23160841Sdarrenr if (opts & OPT_VERBOSE) 23260841Sdarrenr fprintf(stderr, "Read %d bytes on fd %d to %p\n", 23360841Sdarrenr n, fd, ptr); 23460841Sdarrenr i = recv(fd, ptr, n, 0); 23560841Sdarrenr if (i == 0 || i == -1) { 23660841Sdarrenr if (opts & OPT_VERBOSE) 23760841Sdarrenr fprintf(stderr, "Read error on fd %d: %s\n", 23860841Sdarrenr fd, (i == 0) ? "EOF" : strerror(errno)); 23960841Sdarrenr closel4(l4, 1); 24060841Sdarrenr } else { 24160841Sdarrenr if (ptr == buf) 24260841Sdarrenr ptr[i] = '\0'; 24360841Sdarrenr if (opts & OPT_VERBOSE) 24460841Sdarrenr fprintf(stderr, "%d: Read %d bytes [%*.*s]\n", 24560841Sdarrenr fd, i, i, i, ptr); 24660841Sdarrenr if (ptr != buf) { 24760841Sdarrenr l4->l4_rlen += i; 24860841Sdarrenr if (l4->l4_rlen >= l4->l4_rsize) { 24960841Sdarrenr if (!strncmp(response, l4->l4_rbuf, 25060841Sdarrenr l4->l4_rsize)) { 25160841Sdarrenr printf("%d: Good response\n", 25260841Sdarrenr fd); 25360841Sdarrenr if (!l4->l4_alive) { 25460841Sdarrenr l4->l4_alive = 1; 25560841Sdarrenr addnat(l4); 25660841Sdarrenr } 25760841Sdarrenr closel4(l4, 0); 25860841Sdarrenr } else { 25960841Sdarrenr if (opts & OPT_VERBOSE) 26060841Sdarrenr printf("%d: Bad response\n", 26160841Sdarrenr fd); 26260841Sdarrenr closel4(l4, 1); 26360841Sdarrenr } 26460841Sdarrenr } 26560841Sdarrenr } else if (!l4->l4_alive) { 26660841Sdarrenr l4->l4_alive = 1; 26760841Sdarrenr addnat(l4); 26860841Sdarrenr closel4(l4, 0); 26960841Sdarrenr } 27060841Sdarrenr } 27160841Sdarrenr} 27260841Sdarrenr 27360841Sdarrenr 27460841Sdarrenrint runconfig() 27560841Sdarrenr{ 27660841Sdarrenr int fd, opt, res, mfd, i; 27760841Sdarrenr struct timeval tv; 27860841Sdarrenr time_t now, now1; 27960841Sdarrenr fd_set rfd, wfd; 28060841Sdarrenr l4cfg_t *l4; 28160841Sdarrenr 28260841Sdarrenr mfd = 0; 28360841Sdarrenr opt = 1; 28460841Sdarrenr now = time(NULL); 28560841Sdarrenr 28660841Sdarrenr /* 28760841Sdarrenr * First, initiate connections that are closed, as required. 28860841Sdarrenr */ 28960841Sdarrenr for (l4 = l4list; l4; l4 = l4->l4_next) { 29060841Sdarrenr if ((l4->l4_last + frequency < now) && (l4->l4_fd == -1)) { 29160841Sdarrenr l4->l4_last = now; 29260841Sdarrenr fd = socket(AF_INET, SOCK_STREAM, 0); 29360841Sdarrenr if (fd == -1) 29460841Sdarrenr continue; 29560841Sdarrenr setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &opt, 29660841Sdarrenr sizeof(opt)); 29760841Sdarrenr#ifdef O_NONBLOCK 29860841Sdarrenr if ((res = fcntl(fd, F_GETFL, 0)) != -1) 29960841Sdarrenr fcntl(fd, F_SETFL, res | O_NONBLOCK); 30060841Sdarrenr#endif 30160841Sdarrenr if (opts & OPT_VERBOSE) 30260841Sdarrenr fprintf(stderr, 30360841Sdarrenr "Connecting to %s,%d (fd %d)...", 30460841Sdarrenr inet_ntoa(l4->l4_sin.sin_addr), 30560841Sdarrenr ntohs(l4->l4_sin.sin_port), fd); 30660841Sdarrenr if (connect(fd, (struct sockaddr *)&l4->l4_sin, 30760841Sdarrenr sizeof(l4->l4_sin)) == -1) { 30860841Sdarrenr if (errno != EINPROGRESS) { 30960841Sdarrenr if (opts & OPT_VERBOSE) 31060841Sdarrenr fprintf(stderr, "failed\n"); 31160841Sdarrenr perror("connect"); 312145510Sdarrenr close(fd); 31360841Sdarrenr fd = -1; 31460841Sdarrenr } else { 31560841Sdarrenr if (opts & OPT_VERBOSE) 31660841Sdarrenr fprintf(stderr, "waiting\n"); 31760841Sdarrenr l4->l4_rw = -2; 31860841Sdarrenr } 31960841Sdarrenr } else { 32060841Sdarrenr if (opts & OPT_VERBOSE) 32160841Sdarrenr fprintf(stderr, "connected\n"); 32260841Sdarrenr connectl4(l4); 32360841Sdarrenr } 32460841Sdarrenr l4->l4_fd = fd; 32560841Sdarrenr } 32660841Sdarrenr } 32760841Sdarrenr 32860841Sdarrenr /* 32960841Sdarrenr * Now look for fd's which we're expecting to read/write from. 33060841Sdarrenr */ 33160841Sdarrenr FD_ZERO(&rfd); 33260841Sdarrenr FD_ZERO(&wfd); 33360841Sdarrenr tv.tv_sec = MIN(rtimeout, ctimeout); 33460841Sdarrenr tv.tv_usec = 0; 33560841Sdarrenr 33660841Sdarrenr for (l4 = l4list; l4; l4 = l4->l4_next) 33760841Sdarrenr if (l4->l4_rw == 0) { 33860841Sdarrenr if (now - l4->l4_last > rtimeout) { 33960841Sdarrenr if (opts & OPT_VERBOSE) 34060841Sdarrenr fprintf(stderr, "%d: Read timeout\n", 34160841Sdarrenr l4->l4_fd); 34260841Sdarrenr closel4(l4, 1); 34360841Sdarrenr continue; 34460841Sdarrenr } 34560841Sdarrenr if (opts & OPT_VERBOSE) 34660841Sdarrenr fprintf(stderr, "Wait for read on fd %d\n", 34760841Sdarrenr l4->l4_fd); 34860841Sdarrenr FD_SET(l4->l4_fd, &rfd); 34960841Sdarrenr if (l4->l4_fd > mfd) 35060841Sdarrenr mfd = l4->l4_fd; 35160841Sdarrenr } else if ((l4->l4_rw == 1 && l4->l4_wlen) || 35260841Sdarrenr l4->l4_rw == -2) { 35360841Sdarrenr if ((l4->l4_rw == -2) && 35460841Sdarrenr (now - l4->l4_last > ctimeout)) { 35560841Sdarrenr if (opts & OPT_VERBOSE) 35660841Sdarrenr fprintf(stderr, 35760841Sdarrenr "%d: connect timeout\n", 35860841Sdarrenr l4->l4_fd); 35960841Sdarrenr closel4(l4); 36060841Sdarrenr continue; 36160841Sdarrenr } 36260841Sdarrenr if (opts & OPT_VERBOSE) 36360841Sdarrenr fprintf(stderr, "Wait for write on fd %d\n", 36460841Sdarrenr l4->l4_fd); 36560841Sdarrenr FD_SET(l4->l4_fd, &wfd); 36660841Sdarrenr if (l4->l4_fd > mfd) 36760841Sdarrenr mfd = l4->l4_fd; 36860841Sdarrenr } 36960841Sdarrenr 37060841Sdarrenr if (opts & OPT_VERBOSE) 37160841Sdarrenr fprintf(stderr, "Select: max fd %d wait %d\n", mfd + 1, 37260841Sdarrenr tv.tv_sec); 37360841Sdarrenr i = select(mfd + 1, &rfd, &wfd, NULL, &tv); 37460841Sdarrenr if (i == -1) { 37560841Sdarrenr perror("select"); 37660841Sdarrenr return -1; 37760841Sdarrenr } 37860841Sdarrenr 37960841Sdarrenr now1 = time(NULL); 38060841Sdarrenr 38160841Sdarrenr for (l4 = l4list; (i > 0) && l4; l4 = l4->l4_next) { 38260841Sdarrenr if (l4->l4_fd < 0) 38360841Sdarrenr continue; 38460841Sdarrenr if (FD_ISSET(l4->l4_fd, &rfd)) { 38560841Sdarrenr if (opts & OPT_VERBOSE) 38660841Sdarrenr fprintf(stderr, "Ready to read on fd %d\n", 38760841Sdarrenr l4->l4_fd); 38860841Sdarrenr readfd(l4); 38960841Sdarrenr i--; 39060841Sdarrenr } 39160841Sdarrenr 39260841Sdarrenr if ((l4->l4_fd >= 0) && FD_ISSET(l4->l4_fd, &wfd)) { 39360841Sdarrenr if (opts & OPT_VERBOSE) 39460841Sdarrenr fprintf(stderr, "Ready to write on fd %d\n", 39560841Sdarrenr l4->l4_fd); 39660841Sdarrenr writefd(l4); 39760841Sdarrenr i--; 39860841Sdarrenr } 39960841Sdarrenr } 40060841Sdarrenr return 0; 40160841Sdarrenr} 40260841Sdarrenr 40360841Sdarrenr 40460841Sdarrenrint gethostport(str, lnum, ipp, portp) 405255332Scy char *str; 406255332Scy int lnum; 407255332Scy u_32_t *ipp; 408255332Scy u_short *portp; 40960841Sdarrenr{ 41060841Sdarrenr struct servent *sp; 41160841Sdarrenr struct hostent *hp; 41260841Sdarrenr char *host, *port; 413255332Scy struct in_addr ip; 41460841Sdarrenr 41560841Sdarrenr host = str; 41660841Sdarrenr port = strchr(host, ','); 41760841Sdarrenr if (port) 41860841Sdarrenr *port++ = '\0'; 41960841Sdarrenr 42060841Sdarrenr#ifdef HAVE_INET_ATON 421145510Sdarrenr if (ISDIGIT(*host) && inet_aton(host, &ip)) 42260841Sdarrenr *ipp = ip.s_addr; 42360841Sdarrenr#else 424145510Sdarrenr if (ISDIGIT(*host)) 42560841Sdarrenr *ipp = inet_addr(host); 42660841Sdarrenr#endif 42760841Sdarrenr else { 42860841Sdarrenr if (!(hp = gethostbyname(host))) { 42960841Sdarrenr fprintf(stderr, "%d: can't resolve hostname: %s\n", 43060841Sdarrenr lnum, host); 43160841Sdarrenr return 0; 43260841Sdarrenr } 43360841Sdarrenr *ipp = *(u_32_t *)hp->h_addr; 43460841Sdarrenr } 43560841Sdarrenr 43660841Sdarrenr if (port) { 437145510Sdarrenr if (ISDIGIT(*port)) 43860841Sdarrenr *portp = htons(atoi(port)); 43960841Sdarrenr else { 44060841Sdarrenr sp = getservbyname(port, "tcp"); 44160841Sdarrenr if (sp) 44260841Sdarrenr *portp = sp->s_port; 44360841Sdarrenr else { 44460841Sdarrenr fprintf(stderr, "%d: unknown service %s\n", 44560841Sdarrenr lnum, port); 44660841Sdarrenr return 0; 44760841Sdarrenr } 44860841Sdarrenr } 44960841Sdarrenr } else 45060841Sdarrenr *portp = 0; 45160841Sdarrenr return 1; 45260841Sdarrenr} 45360841Sdarrenr 45460841Sdarrenr 45560841Sdarrenrchar *mapfile(file, sizep) 456255332Scy char *file; 457255332Scy size_t *sizep; 45860841Sdarrenr{ 45960841Sdarrenr struct stat sb; 46060841Sdarrenr caddr_t addr; 46160841Sdarrenr int fd; 46260841Sdarrenr 46360841Sdarrenr fd = open(file, O_RDONLY); 46460841Sdarrenr if (fd == -1) { 46560841Sdarrenr perror("open(mapfile)"); 46660841Sdarrenr return NULL; 46760841Sdarrenr } 46860841Sdarrenr 46960841Sdarrenr if (fstat(fd, &sb) == -1) { 47060841Sdarrenr perror("fstat(mapfile)"); 47160841Sdarrenr close(fd); 47260841Sdarrenr return NULL; 47360841Sdarrenr } 47460841Sdarrenr 47560841Sdarrenr addr = mmap(NULL, sb.st_size, PROT_READ, MAP_SHARED, fd, 0); 47660841Sdarrenr if (addr == (caddr_t)-1) { 47760841Sdarrenr perror("mmap(mapfile)"); 47860841Sdarrenr close(fd); 47960841Sdarrenr return NULL; 48060841Sdarrenr } 48160841Sdarrenr close(fd); 48260841Sdarrenr *sizep = sb.st_size; 48360841Sdarrenr return (char *)addr; 48460841Sdarrenr} 48560841Sdarrenr 48660841Sdarrenr 48760841Sdarrenrint readconfig(filename) 488255332Scy char *filename; 48960841Sdarrenr{ 49060841Sdarrenr char c, buf[512], *s, *t, *errtxt = NULL, *line; 49160841Sdarrenr int num, err = 0; 49260841Sdarrenr ipnat_t *ipn; 49360841Sdarrenr l4cfg_t *l4; 49460841Sdarrenr FILE *fp; 49560841Sdarrenr 49660841Sdarrenr fp = fopen(filename, "r"); 49760841Sdarrenr if (!fp) { 49860841Sdarrenr perror("open(configfile)"); 49960841Sdarrenr return -1; 50060841Sdarrenr } 50160841Sdarrenr 50260841Sdarrenr bzero((char *)&template, sizeof(template)); 50360841Sdarrenr template.l4_fd = -1; 50460841Sdarrenr template.l4_rw = -1; 50560841Sdarrenr template.l4_sin.sin_family = AF_INET; 50660841Sdarrenr ipn = &template.l4_nat; 50760841Sdarrenr ipn->in_flags = IPN_TCP|IPN_ROUNDR; 50860841Sdarrenr ipn->in_redir = NAT_REDIRECT; 50960841Sdarrenr 51060841Sdarrenr for (num = 1; fgets(buf, sizeof(buf), fp); num++) { 51160841Sdarrenr s = strchr(buf, '\n'); 51260841Sdarrenr if (!s) { 51360841Sdarrenr fprintf(stderr, "%d: line too long\n", num); 51460841Sdarrenr fclose(fp); 51560841Sdarrenr return -1; 51660841Sdarrenr } 51760841Sdarrenr 51860841Sdarrenr *s = '\0'; 51960841Sdarrenr 52060841Sdarrenr /* 52160841Sdarrenr * lines which are comments 52260841Sdarrenr */ 52360841Sdarrenr s = strchr(buf, '#'); 52460841Sdarrenr if (s) 52560841Sdarrenr *s = '\0'; 52660841Sdarrenr 52760841Sdarrenr /* 52860841Sdarrenr * Skip leading whitespace 52960841Sdarrenr */ 530145510Sdarrenr for (line = buf; (c = *line) && ISSPACE(c); line++) 53160841Sdarrenr ; 53260841Sdarrenr if (!*line) 53360841Sdarrenr continue; 53460841Sdarrenr 53560841Sdarrenr if (opts & OPT_VERBOSE) 53660841Sdarrenr fprintf(stderr, "Parsing: [%s]\n", line); 53760841Sdarrenr t = strtok(line, " \t"); 53860841Sdarrenr if (!t) 53960841Sdarrenr continue; 54060841Sdarrenr if (!strcasecmp(t, "interface")) { 54160841Sdarrenr s = strtok(NULL, " \t"); 54260841Sdarrenr if (s) 54360841Sdarrenr t = strtok(NULL, "\t"); 54460841Sdarrenr if (!s || !t) { 54560841Sdarrenr errtxt = line; 54660841Sdarrenr err = -1; 54760841Sdarrenr break; 54860841Sdarrenr } 54960841Sdarrenr 55060841Sdarrenr if (!strchr(t, ',')) { 55160841Sdarrenr fprintf(stderr, 55260841Sdarrenr "%d: local address,port missing\n", 55360841Sdarrenr num); 55460841Sdarrenr err = -1; 55560841Sdarrenr break; 55660841Sdarrenr } 55760841Sdarrenr 558255332Scy strncpy(ipn->in_ifname, s, sizeof(ipn->in_ifname)); 55960841Sdarrenr if (!gethostport(t, num, &ipn->in_outip, 56060841Sdarrenr &ipn->in_pmin)) { 56160841Sdarrenr errtxt = line; 56260841Sdarrenr err = -1; 56360841Sdarrenr break; 56460841Sdarrenr } 56560841Sdarrenr ipn->in_outmsk = 0xffffffff; 56660841Sdarrenr ipn->in_pmax = ipn->in_pmin; 56760841Sdarrenr if (opts & OPT_VERBOSE) 56860841Sdarrenr fprintf(stderr, 56960841Sdarrenr "Interface %s %s/%#x port %u\n", 570255332Scy ipn->in_ifname, 571255332Scy inet_ntoa(ipn->in_out[0]), 57260841Sdarrenr ipn->in_outmsk, ipn->in_pmin); 57360841Sdarrenr } else if (!strcasecmp(t, "remote")) { 574255332Scy if (!*ipn->in_ifname) { 57560841Sdarrenr fprintf(stderr, 57660841Sdarrenr "%d: ifname not set prior to remote\n", 57760841Sdarrenr num); 57860841Sdarrenr err = -1; 57960841Sdarrenr break; 58060841Sdarrenr } 58160841Sdarrenr s = strtok(NULL, " \t"); 58260841Sdarrenr if (s) 58360841Sdarrenr t = strtok(NULL, ""); 58460841Sdarrenr if (!s || !t || strcasecmp(s, "server")) { 58560841Sdarrenr errtxt = line; 58660841Sdarrenr err = -1; 58760841Sdarrenr break; 58860841Sdarrenr } 58960841Sdarrenr 59060841Sdarrenr ipn->in_pnext = 0; 59160841Sdarrenr if (!gethostport(t, num, &ipn->in_inip, 59260841Sdarrenr &ipn->in_pnext)) { 59360841Sdarrenr errtxt = line; 59460841Sdarrenr err = -1; 59560841Sdarrenr break; 59660841Sdarrenr } 59760841Sdarrenr ipn->in_inmsk = 0xffffffff; 59860841Sdarrenr if (ipn->in_pnext == 0) 59960841Sdarrenr ipn->in_pnext = ipn->in_pmin; 60060841Sdarrenr 60160841Sdarrenr l4 = (l4cfg_t *)malloc(sizeof(*l4)); 60260841Sdarrenr if (!l4) { 60360841Sdarrenr fprintf(stderr, "%d: out of memory (%d)\n", 60460841Sdarrenr num, sizeof(*l4)); 60560841Sdarrenr err = -1; 60660841Sdarrenr break; 60760841Sdarrenr } 60860841Sdarrenr bcopy((char *)&template, (char *)l4, sizeof(*l4)); 609255332Scy l4->l4_sin.sin_addr = ipn->in_in[0]; 610145510Sdarrenr l4->l4_sin.sin_port = ipn->in_pnext; 61160841Sdarrenr l4->l4_next = l4list; 61260841Sdarrenr l4list = l4; 61360841Sdarrenr } else if (!strcasecmp(t, "connect")) { 61460841Sdarrenr s = strtok(NULL, " \t"); 61560841Sdarrenr if (s) 61660841Sdarrenr t = strtok(NULL, "\t"); 617145510Sdarrenr if (!s || !t) { 61860841Sdarrenr errtxt = line; 61960841Sdarrenr err = -1; 62060841Sdarrenr break; 62160841Sdarrenr } else if (!strcasecmp(s, "timeout")) { 62260841Sdarrenr ctimeout = atoi(t); 62360841Sdarrenr if (opts & OPT_VERBOSE) 62460841Sdarrenr fprintf(stderr, "connect timeout %d\n", 62560841Sdarrenr ctimeout); 62660841Sdarrenr } else if (!strcasecmp(s, "frequency")) { 62760841Sdarrenr frequency = atoi(t); 62860841Sdarrenr if (opts & OPT_VERBOSE) 62960841Sdarrenr fprintf(stderr, 63060841Sdarrenr "connect frequency %d\n", 63160841Sdarrenr frequency); 63260841Sdarrenr } else { 63360841Sdarrenr errtxt = line; 63460841Sdarrenr err = -1; 63560841Sdarrenr break; 63660841Sdarrenr } 63760841Sdarrenr } else if (!strcasecmp(t, "probe")) { 63860841Sdarrenr s = strtok(NULL, " \t"); 639145510Sdarrenr if (!s) { 64060841Sdarrenr errtxt = line; 64160841Sdarrenr err = -1; 64260841Sdarrenr break; 64360841Sdarrenr } else if (!strcasecmp(s, "string")) { 64460841Sdarrenr if (probe) { 64560841Sdarrenr fprintf(stderr, 64660841Sdarrenr "%d: probe already set\n", 64760841Sdarrenr num); 64860841Sdarrenr err = -1; 64960841Sdarrenr break; 65060841Sdarrenr } 65160841Sdarrenr t = strtok(NULL, ""); 65260841Sdarrenr if (!t) { 65360841Sdarrenr fprintf(stderr, 65460841Sdarrenr "%d: No probe string\n", num); 65560841Sdarrenr err = -1; 65660841Sdarrenr break; 65760841Sdarrenr } 65860841Sdarrenr 65960841Sdarrenr probe = malloc(strlen(t)); 66060841Sdarrenr copystr(probe, t); 66160841Sdarrenr plen = strlen(probe); 66260841Sdarrenr if (opts & OPT_VERBOSE) 66360841Sdarrenr fprintf(stderr, "Probe string [%s]\n", 66460841Sdarrenr probe); 66560841Sdarrenr } else if (!strcasecmp(s, "file")) { 66660841Sdarrenr t = strtok(NULL, " \t"); 66760841Sdarrenr if (!t) { 66860841Sdarrenr errtxt = line; 66960841Sdarrenr err = -1; 67060841Sdarrenr break; 67160841Sdarrenr } 67260841Sdarrenr if (probe) { 67360841Sdarrenr fprintf(stderr, 67460841Sdarrenr "%d: probe already set\n", 67560841Sdarrenr num); 67660841Sdarrenr err = -1; 67760841Sdarrenr break; 67860841Sdarrenr } 67960841Sdarrenr probe = mapfile(t, &plen); 68060841Sdarrenr if (opts & OPT_VERBOSE) 68160841Sdarrenr fprintf(stderr, 68260841Sdarrenr "Probe file %s len %u@%p\n", 68360841Sdarrenr t, plen, probe); 68460841Sdarrenr } 68560841Sdarrenr } else if (!strcasecmp(t, "response")) { 68660841Sdarrenr s = strtok(NULL, " \t"); 687145510Sdarrenr if (!s) { 68860841Sdarrenr errtxt = line; 68960841Sdarrenr err = -1; 69060841Sdarrenr break; 69160841Sdarrenr } else if (!strcasecmp(s, "timeout")) { 69260841Sdarrenr t = strtok(NULL, " \t"); 693145510Sdarrenr if (!t) { 69460841Sdarrenr errtxt = line; 69560841Sdarrenr err = -1; 69660841Sdarrenr break; 69760841Sdarrenr } 69860841Sdarrenr rtimeout = atoi(t); 69960841Sdarrenr if (opts & OPT_VERBOSE) 70060841Sdarrenr fprintf(stderr, 70160841Sdarrenr "response timeout %d\n", 70260841Sdarrenr rtimeout); 70360841Sdarrenr } else if (!strcasecmp(s, "string")) { 70460841Sdarrenr if (response) { 70560841Sdarrenr fprintf(stderr, 70660841Sdarrenr "%d: response already set\n", 70760841Sdarrenr num); 70860841Sdarrenr err = -1; 70960841Sdarrenr break; 71060841Sdarrenr } 71160841Sdarrenr response = strdup(strtok(NULL, "")); 71260841Sdarrenr rlen = strlen(response); 71360841Sdarrenr template.l4_rsize = rlen; 71460841Sdarrenr template.l4_rbuf = malloc(rlen); 71560841Sdarrenr if (opts & OPT_VERBOSE) 71660841Sdarrenr fprintf(stderr, 71760841Sdarrenr "Response string [%s]\n", 71860841Sdarrenr response); 71960841Sdarrenr } else if (!strcasecmp(s, "file")) { 72060841Sdarrenr t = strtok(NULL, " \t"); 72160841Sdarrenr if (!t) { 72260841Sdarrenr errtxt = line; 72360841Sdarrenr err = -1; 72460841Sdarrenr break; 72560841Sdarrenr } 72660841Sdarrenr if (response) { 72760841Sdarrenr fprintf(stderr, 72860841Sdarrenr "%d: response already set\n", 72960841Sdarrenr num); 73060841Sdarrenr err = -1; 73160841Sdarrenr break; 73260841Sdarrenr } 73360841Sdarrenr response = mapfile(t, &rlen); 73460841Sdarrenr template.l4_rsize = rlen; 73560841Sdarrenr template.l4_rbuf = malloc(rlen); 73660841Sdarrenr if (opts & OPT_VERBOSE) 73760841Sdarrenr fprintf(stderr, 73860841Sdarrenr "Response file %s len %u@%p\n", 73960841Sdarrenr t, rlen, response); 74060841Sdarrenr } 74160841Sdarrenr } else { 74260841Sdarrenr errtxt = line; 74360841Sdarrenr err = -1; 74460841Sdarrenr break; 74560841Sdarrenr } 74660841Sdarrenr } 74760841Sdarrenr 74860841Sdarrenr if (errtxt) 74960841Sdarrenr fprintf(stderr, "%d: syntax error at \"%s\"\n", num, errtxt); 75060841Sdarrenr fclose(fp); 75160841Sdarrenr return err; 75260841Sdarrenr} 75360841Sdarrenr 75460841Sdarrenr 75560841Sdarrenrvoid usage(prog) 756255332Scy char *prog; 75760841Sdarrenr{ 75860841Sdarrenr fprintf(stderr, "Usage: %s -f <configfile>\n", prog); 75960841Sdarrenr exit(1); 76060841Sdarrenr} 76160841Sdarrenr 76260841Sdarrenr 76360841Sdarrenrint main(argc, argv) 764255332Scy int argc; 765255332Scy char *argv[]; 76660841Sdarrenr{ 76760841Sdarrenr char *config = NULL; 76860841Sdarrenr int c; 76960841Sdarrenr 77060841Sdarrenr while ((c = getopt(argc, argv, "f:nv")) != -1) 77160841Sdarrenr switch (c) 77260841Sdarrenr { 77360841Sdarrenr case 'f' : 77460841Sdarrenr config = optarg; 77560841Sdarrenr break; 77660841Sdarrenr case 'n' : 77760841Sdarrenr opts |= OPT_DONOTHING; 77860841Sdarrenr break; 77960841Sdarrenr case 'v' : 78060841Sdarrenr opts |= OPT_VERBOSE; 78160841Sdarrenr break; 78260841Sdarrenr } 78360841Sdarrenr 78460841Sdarrenr if (config == NULL) 78560841Sdarrenr usage(argv[0]); 78660841Sdarrenr 78760841Sdarrenr if (readconfig(config)) 78860841Sdarrenr exit(1); 78960841Sdarrenr 79060841Sdarrenr if (!l4list) { 79160841Sdarrenr fprintf(stderr, "No remote servers, exiting."); 79260841Sdarrenr exit(1); 79360841Sdarrenr } 79460841Sdarrenr 79560841Sdarrenr if (!(opts & OPT_DONOTHING)) { 796255332Scy natfd = open(IPL_NAT, O_RDWR); 79760841Sdarrenr if (natfd == -1) { 79860841Sdarrenr perror("open(IPL_NAT)"); 79960841Sdarrenr exit(1); 80060841Sdarrenr } 80160841Sdarrenr } 80260841Sdarrenr 80360841Sdarrenr if (opts & OPT_VERBOSE) 80460841Sdarrenr fprintf(stderr, "Starting...\n"); 80560841Sdarrenr while (runconfig() == 0) 80660841Sdarrenr ; 80760841Sdarrenr} 808