diff options
Diffstat (limited to 'contrib/ipfilter/l4check/l4check.c')
-rw-r--r-- | contrib/ipfilter/l4check/l4check.c | 822 |
1 files changed, 0 insertions, 822 deletions
diff --git a/contrib/ipfilter/l4check/l4check.c b/contrib/ipfilter/l4check/l4check.c deleted file mode 100644 index a096fff..0000000 --- a/contrib/ipfilter/l4check/l4check.c +++ /dev/null @@ -1,822 +0,0 @@ -/* - * (C)Copyright March, 2000 - Darren Reed. - */ -#include <sys/types.h> -#include <sys/stat.h> -#include <sys/mman.h> -#include <sys/socket.h> -#include <sys/time.h> -#include <sys/ioctl.h> - -#include <netinet/in.h> -#include <netinet/in_systm.h> -#include <netinet/ip.h> - -#include <net/if.h> - -#include <stdio.h> -#include <netdb.h> -#include <string.h> -#include <ctype.h> -#include <fcntl.h> -#include <errno.h> -#include <stdlib.h> - -#include "ip_compat.h" -#include "ip_fil.h" -#include "ip_nat.h" -#include "ipl.h" - -#include "ipf.h" - -extern char *optarg; - - -typedef struct l4cfg { - struct l4cfg *l4_next; - struct ipnat l4_nat; /* NAT rule */ - struct sockaddr_in l4_sin; /* remote socket to connect */ - time_t l4_last; /* when we last connected */ - int l4_alive; /* 1 = remote alive */ - int l4_fd; - int l4_rw; /* 0 = reading, 1 = writing */ - char *l4_rbuf; /* read buffer */ - int l4_rsize; /* size of buffer */ - int l4_rlen; /* how much used */ - char *l4_wptr; /* next byte to write */ - int l4_wlen; /* length yet to be written */ -} l4cfg_t; - - -l4cfg_t *l4list = NULL; -char *response = NULL; -char *probe = NULL; -l4cfg_t template; -int frequency = 20; -int ctimeout = 1; -int rtimeout = 1; -size_t plen = 0; -size_t rlen = 0; -int natfd = -1; -int opts = 0; - -#if defined(sun) && !defined(__svr4__) && !defined(__SVR4) -# define strerror(x) sys_errlist[x] -#endif - - -char *copystr(dst, src) -char *dst, *src; -{ - register char *s, *t, c; - register int esc = 0; - - for (s = src, t = dst; s && t && (c = *s++); ) - if (esc) { - esc = 0; - switch (c) - { - case 'n' : - *t++ = '\n'; - break; - case 'r' : - *t++ = '\r'; - break; - case 't' : - *t++ = '\t'; - break; - } - } else if (c != '\\') - *t++ = c; - else - esc = 1; - *t = '\0'; - return dst; -} - -void addnat(l4) -l4cfg_t *l4; -{ - - ipnat_t *ipn = &l4->l4_nat; - - printf("Add NAT rule for %s/%#x,%u -> ", inet_ntoa(ipn->in_out[0].in4), - ipn->in_outmsk, ntohs(ipn->in_pmin)); - printf("%s,%u\n", inet_ntoa(ipn->in_in[0].in4), ntohs(ipn->in_pnext)); - if (!(opts & OPT_DONOTHING)) { - ipfobj_t obj; - - bzero(&obj, sizeof(obj)); - obj.ipfo_rev = IPFILTER_VERSION; - obj.ipfo_size = sizeof(*ipn); - obj.ipfo_ptr = ipn; - - if (ioctl(natfd, SIOCADNAT, &obj) == -1) - perror("ioctl(SIOCADNAT)"); - } -} - - -void delnat(l4) -l4cfg_t *l4; -{ - ipnat_t *ipn = &l4->l4_nat; - - printf("Remove NAT rule for %s/%#x,%u -> ", - inet_ntoa(ipn->in_out[0].in4), ipn->in_outmsk, ipn->in_pmin); - printf("%s,%u\n", inet_ntoa(ipn->in_in[0].in4), ipn->in_pnext); - if (!(opts & OPT_DONOTHING)) { - ipfobj_t obj; - - bzero(&obj, sizeof(obj)); - obj.ipfo_rev = IPFILTER_VERSION; - obj.ipfo_size = sizeof(*ipn); - obj.ipfo_ptr = ipn; - - if (ioctl(natfd, SIOCRMNAT, &ipn) == -1) - perror("ioctl(SIOCRMNAT)"); - } -} - - -void connectl4(l4) -l4cfg_t *l4; -{ - l4->l4_rw = 1; - l4->l4_rlen = 0; - l4->l4_wlen = plen; - if (!l4->l4_wlen) { - l4->l4_alive = 1; - addnat(l4); - } else - l4->l4_wptr = probe; -} - - -void closel4(l4, dead) -l4cfg_t *l4; -int dead; -{ - close(l4->l4_fd); - l4->l4_fd = -1; - l4->l4_rw = -1; - if (dead && l4->l4_alive) { - l4->l4_alive = 0; - delnat(l4); - } -} - - -void connectfd(l4) -l4cfg_t *l4; -{ - if (connect(l4->l4_fd, (struct sockaddr *)&l4->l4_sin, - sizeof(l4->l4_sin)) == -1) { - if (errno == EISCONN) { - if (opts & OPT_VERBOSE) - fprintf(stderr, "Connected fd %d\n", - l4->l4_fd); - connectl4(l4); - return; - } - if (opts & OPT_VERBOSE) - fprintf(stderr, "Connect failed fd %d: %s\n", - l4->l4_fd, strerror(errno)); - closel4(l4, 1); - return; - } - l4->l4_rw = 1; -} - - -void writefd(l4) -l4cfg_t *l4; -{ - int n, i, fd; - - fd = l4->l4_fd; - - if (l4->l4_rw == -2) { - connectfd(l4); - return; - } - - n = l4->l4_wlen; - - i = send(fd, l4->l4_wptr, n, 0); - if (i == 0 || i == -1) { - if (opts & OPT_VERBOSE) - fprintf(stderr, "Send on fd %d failed: %s\n", - fd, strerror(errno)); - closel4(l4, 1); - } else { - l4->l4_wptr += i; - l4->l4_wlen -= i; - if (l4->l4_wlen == 0) - l4->l4_rw = 0; - if (opts & OPT_VERBOSE) - fprintf(stderr, "Sent %d bytes to fd %d\n", i, fd); - } -} - - -void readfd(l4) -l4cfg_t *l4; -{ - char buf[80], *ptr; - int n, i, fd; - - fd = l4->l4_fd; - - if (l4->l4_rw == -2) { - connectfd(l4); - return; - } - - if (l4->l4_rsize) { - n = l4->l4_rsize - l4->l4_rlen; - ptr = l4->l4_rbuf + l4->l4_rlen; - } else { - n = sizeof(buf) - 1; - ptr = buf; - } - - if (opts & OPT_VERBOSE) - fprintf(stderr, "Read %d bytes on fd %d to %p\n", - n, fd, ptr); - i = recv(fd, ptr, n, 0); - if (i == 0 || i == -1) { - if (opts & OPT_VERBOSE) - fprintf(stderr, "Read error on fd %d: %s\n", - fd, (i == 0) ? "EOF" : strerror(errno)); - closel4(l4, 1); - } else { - if (ptr == buf) - ptr[i] = '\0'; - if (opts & OPT_VERBOSE) - fprintf(stderr, "%d: Read %d bytes [%*.*s]\n", - fd, i, i, i, ptr); - if (ptr != buf) { - l4->l4_rlen += i; - if (l4->l4_rlen >= l4->l4_rsize) { - if (!strncmp(response, l4->l4_rbuf, - l4->l4_rsize)) { - printf("%d: Good response\n", - fd); - if (!l4->l4_alive) { - l4->l4_alive = 1; - addnat(l4); - } - closel4(l4, 0); - } else { - if (opts & OPT_VERBOSE) - printf("%d: Bad response\n", - fd); - closel4(l4, 1); - } - } - } else if (!l4->l4_alive) { - l4->l4_alive = 1; - addnat(l4); - closel4(l4, 0); - } - } -} - - -int runconfig() -{ - int fd, opt, res, mfd, i; - struct timeval tv; - time_t now, now1; - fd_set rfd, wfd; - l4cfg_t *l4; - - mfd = 0; - opt = 1; - now = time(NULL); - - /* - * First, initiate connections that are closed, as required. - */ - for (l4 = l4list; l4; l4 = l4->l4_next) { - if ((l4->l4_last + frequency < now) && (l4->l4_fd == -1)) { - l4->l4_last = now; - fd = socket(AF_INET, SOCK_STREAM, 0); - if (fd == -1) - continue; - setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &opt, - sizeof(opt)); -#ifdef O_NONBLOCK - if ((res = fcntl(fd, F_GETFL, 0)) != -1) - fcntl(fd, F_SETFL, res | O_NONBLOCK); -#endif - if (opts & OPT_VERBOSE) - fprintf(stderr, - "Connecting to %s,%d (fd %d)...", - inet_ntoa(l4->l4_sin.sin_addr), - ntohs(l4->l4_sin.sin_port), fd); - if (connect(fd, (struct sockaddr *)&l4->l4_sin, - sizeof(l4->l4_sin)) == -1) { - if (errno != EINPROGRESS) { - if (opts & OPT_VERBOSE) - fprintf(stderr, "failed\n"); - perror("connect"); - close(fd); - fd = -1; - } else { - if (opts & OPT_VERBOSE) - fprintf(stderr, "waiting\n"); - l4->l4_rw = -2; - } - } else { - if (opts & OPT_VERBOSE) - fprintf(stderr, "connected\n"); - connectl4(l4); - } - l4->l4_fd = fd; - } - } - - /* - * Now look for fd's which we're expecting to read/write from. - */ - FD_ZERO(&rfd); - FD_ZERO(&wfd); - tv.tv_sec = MIN(rtimeout, ctimeout); - tv.tv_usec = 0; - - for (l4 = l4list; l4; l4 = l4->l4_next) - if (l4->l4_rw == 0) { - if (now - l4->l4_last > rtimeout) { - if (opts & OPT_VERBOSE) - fprintf(stderr, "%d: Read timeout\n", - l4->l4_fd); - closel4(l4, 1); - continue; - } - if (opts & OPT_VERBOSE) - fprintf(stderr, "Wait for read on fd %d\n", - l4->l4_fd); - FD_SET(l4->l4_fd, &rfd); - if (l4->l4_fd > mfd) - mfd = l4->l4_fd; - } else if ((l4->l4_rw == 1 && l4->l4_wlen) || - l4->l4_rw == -2) { - if ((l4->l4_rw == -2) && - (now - l4->l4_last > ctimeout)) { - if (opts & OPT_VERBOSE) - fprintf(stderr, - "%d: connect timeout\n", - l4->l4_fd); - closel4(l4); - continue; - } - if (opts & OPT_VERBOSE) - fprintf(stderr, "Wait for write on fd %d\n", - l4->l4_fd); - FD_SET(l4->l4_fd, &wfd); - if (l4->l4_fd > mfd) - mfd = l4->l4_fd; - } - - if (opts & OPT_VERBOSE) - fprintf(stderr, "Select: max fd %d wait %d\n", mfd + 1, - tv.tv_sec); - i = select(mfd + 1, &rfd, &wfd, NULL, &tv); - if (i == -1) { - perror("select"); - return -1; - } - - now1 = time(NULL); - - for (l4 = l4list; (i > 0) && l4; l4 = l4->l4_next) { - if (l4->l4_fd < 0) - continue; - if (FD_ISSET(l4->l4_fd, &rfd)) { - if (opts & OPT_VERBOSE) - fprintf(stderr, "Ready to read on fd %d\n", - l4->l4_fd); - readfd(l4); - i--; - } - - if ((l4->l4_fd >= 0) && FD_ISSET(l4->l4_fd, &wfd)) { - if (opts & OPT_VERBOSE) - fprintf(stderr, "Ready to write on fd %d\n", - l4->l4_fd); - writefd(l4); - i--; - } - } - return 0; -} - - -int gethostport(str, lnum, ipp, portp) -char *str; -int lnum; -u_32_t *ipp; -u_short *portp; -{ - struct servent *sp; - struct hostent *hp; - char *host, *port; - - host = str; - port = strchr(host, ','); - if (port) - *port++ = '\0'; - -#ifdef HAVE_INET_ATON - if (ISDIGIT(*host) && inet_aton(host, &ip)) - *ipp = ip.s_addr; -#else - if (ISDIGIT(*host)) - *ipp = inet_addr(host); -#endif - else { - if (!(hp = gethostbyname(host))) { - fprintf(stderr, "%d: can't resolve hostname: %s\n", - lnum, host); - return 0; - } - *ipp = *(u_32_t *)hp->h_addr; - } - - if (port) { - if (ISDIGIT(*port)) - *portp = htons(atoi(port)); - else { - sp = getservbyname(port, "tcp"); - if (sp) - *portp = sp->s_port; - else { - fprintf(stderr, "%d: unknown service %s\n", - lnum, port); - return 0; - } - } - } else - *portp = 0; - return 1; -} - - -char *mapfile(file, sizep) -char *file; -size_t *sizep; -{ - struct stat sb; - caddr_t addr; - int fd; - - fd = open(file, O_RDONLY); - if (fd == -1) { - perror("open(mapfile)"); - return NULL; - } - - if (fstat(fd, &sb) == -1) { - perror("fstat(mapfile)"); - close(fd); - return NULL; - } - - addr = mmap(NULL, sb.st_size, PROT_READ, MAP_SHARED, fd, 0); - if (addr == (caddr_t)-1) { - perror("mmap(mapfile)"); - close(fd); - return NULL; - } - close(fd); - *sizep = sb.st_size; - return (char *)addr; -} - - -int readconfig(filename) -char *filename; -{ - char c, buf[512], *s, *t, *errtxt = NULL, *line; - int num, err = 0; - ipnat_t *ipn; - l4cfg_t *l4; - FILE *fp; - - fp = fopen(filename, "r"); - if (!fp) { - perror("open(configfile)"); - return -1; - } - - bzero((char *)&template, sizeof(template)); - template.l4_fd = -1; - template.l4_rw = -1; - template.l4_sin.sin_family = AF_INET; - ipn = &template.l4_nat; - ipn->in_flags = IPN_TCP|IPN_ROUNDR; - ipn->in_redir = NAT_REDIRECT; - - for (num = 1; fgets(buf, sizeof(buf), fp); num++) { - s = strchr(buf, '\n'); - if (!s) { - fprintf(stderr, "%d: line too long\n", num); - fclose(fp); - return -1; - } - - *s = '\0'; - - /* - * lines which are comments - */ - s = strchr(buf, '#'); - if (s) - *s = '\0'; - - /* - * Skip leading whitespace - */ - for (line = buf; (c = *line) && ISSPACE(c); line++) - ; - if (!*line) - continue; - - if (opts & OPT_VERBOSE) - fprintf(stderr, "Parsing: [%s]\n", line); - t = strtok(line, " \t"); - if (!t) - continue; - if (!strcasecmp(t, "interface")) { - s = strtok(NULL, " \t"); - if (s) - t = strtok(NULL, "\t"); - if (!s || !t) { - errtxt = line; - err = -1; - break; - } - - if (!strchr(t, ',')) { - fprintf(stderr, - "%d: local address,port missing\n", - num); - err = -1; - break; - } - - strncpy(ipn->in_ifnames[0], s, LIFNAMSIZ); - strncpy(ipn->in_ifnames[1], s, LIFNAMSIZ); - if (!gethostport(t, num, &ipn->in_outip, - &ipn->in_pmin)) { - errtxt = line; - err = -1; - break; - } - ipn->in_outmsk = 0xffffffff; - ipn->in_pmax = ipn->in_pmin; - if (opts & OPT_VERBOSE) - fprintf(stderr, - "Interface %s %s/%#x port %u\n", - ipn->in_ifnames[0], - inet_ntoa(ipn->in_out[0].in4), - ipn->in_outmsk, ipn->in_pmin); - } else if (!strcasecmp(t, "remote")) { - if (!*ipn->in_ifnames[0]) { - fprintf(stderr, - "%d: ifname not set prior to remote\n", - num); - err = -1; - break; - } - s = strtok(NULL, " \t"); - if (s) - t = strtok(NULL, ""); - if (!s || !t || strcasecmp(s, "server")) { - errtxt = line; - err = -1; - break; - } - - ipn->in_pnext = 0; - if (!gethostport(t, num, &ipn->in_inip, - &ipn->in_pnext)) { - errtxt = line; - err = -1; - break; - } - ipn->in_inmsk = 0xffffffff; - if (ipn->in_pnext == 0) - ipn->in_pnext = ipn->in_pmin; - - l4 = (l4cfg_t *)malloc(sizeof(*l4)); - if (!l4) { - fprintf(stderr, "%d: out of memory (%d)\n", - num, sizeof(*l4)); - err = -1; - break; - } - bcopy((char *)&template, (char *)l4, sizeof(*l4)); - l4->l4_sin.sin_addr = ipn->in_in[0].in4; - l4->l4_sin.sin_port = ipn->in_pnext; - l4->l4_next = l4list; - l4list = l4; - } else if (!strcasecmp(t, "connect")) { - s = strtok(NULL, " \t"); - if (s) - t = strtok(NULL, "\t"); - if (!s || !t) { - errtxt = line; - err = -1; - break; - } else if (!strcasecmp(s, "timeout")) { - ctimeout = atoi(t); - if (opts & OPT_VERBOSE) - fprintf(stderr, "connect timeout %d\n", - ctimeout); - } else if (!strcasecmp(s, "frequency")) { - frequency = atoi(t); - if (opts & OPT_VERBOSE) - fprintf(stderr, - "connect frequency %d\n", - frequency); - } else { - errtxt = line; - err = -1; - break; - } - } else if (!strcasecmp(t, "probe")) { - s = strtok(NULL, " \t"); - if (!s) { - errtxt = line; - err = -1; - break; - } else if (!strcasecmp(s, "string")) { - if (probe) { - fprintf(stderr, - "%d: probe already set\n", - num); - err = -1; - break; - } - t = strtok(NULL, ""); - if (!t) { - fprintf(stderr, - "%d: No probe string\n", num); - err = -1; - break; - } - - probe = malloc(strlen(t)); - copystr(probe, t); - plen = strlen(probe); - if (opts & OPT_VERBOSE) - fprintf(stderr, "Probe string [%s]\n", - probe); - } else if (!strcasecmp(s, "file")) { - t = strtok(NULL, " \t"); - if (!t) { - errtxt = line; - err = -1; - break; - } - if (probe) { - fprintf(stderr, - "%d: probe already set\n", - num); - err = -1; - break; - } - probe = mapfile(t, &plen); - if (opts & OPT_VERBOSE) - fprintf(stderr, - "Probe file %s len %u@%p\n", - t, plen, probe); - } - } else if (!strcasecmp(t, "response")) { - s = strtok(NULL, " \t"); - if (!s) { - errtxt = line; - err = -1; - break; - } else if (!strcasecmp(s, "timeout")) { - t = strtok(NULL, " \t"); - if (!t) { - errtxt = line; - err = -1; - break; - } - rtimeout = atoi(t); - if (opts & OPT_VERBOSE) - fprintf(stderr, - "response timeout %d\n", - rtimeout); - } else if (!strcasecmp(s, "string")) { - if (response) { - fprintf(stderr, - "%d: response already set\n", - num); - err = -1; - break; - } - response = strdup(strtok(NULL, "")); - rlen = strlen(response); - template.l4_rsize = rlen; - template.l4_rbuf = malloc(rlen); - if (opts & OPT_VERBOSE) - fprintf(stderr, - "Response string [%s]\n", - response); - } else if (!strcasecmp(s, "file")) { - t = strtok(NULL, " \t"); - if (!t) { - errtxt = line; - err = -1; - break; - } - if (response) { - fprintf(stderr, - "%d: response already set\n", - num); - err = -1; - break; - } - response = mapfile(t, &rlen); - template.l4_rsize = rlen; - template.l4_rbuf = malloc(rlen); - if (opts & OPT_VERBOSE) - fprintf(stderr, - "Response file %s len %u@%p\n", - t, rlen, response); - } - } else { - errtxt = line; - err = -1; - break; - } - } - - if (errtxt) - fprintf(stderr, "%d: syntax error at \"%s\"\n", num, errtxt); - fclose(fp); - return err; -} - - -void usage(prog) -char *prog; -{ - fprintf(stderr, "Usage: %s -f <configfile>\n", prog); - exit(1); -} - - -int main(argc, argv) -int argc; -char *argv[]; -{ - char *config = NULL; - int c; - - while ((c = getopt(argc, argv, "f:nv")) != -1) - switch (c) - { - case 'f' : - config = optarg; - break; - case 'n' : - opts |= OPT_DONOTHING; - break; - case 'v' : - opts |= OPT_VERBOSE; - break; - } - - if (config == NULL) - usage(argv[0]); - - if (readconfig(config)) - exit(1); - - if (!l4list) { - fprintf(stderr, "No remote servers, exiting."); - exit(1); - } - - if (!(opts & OPT_DONOTHING)) { - natfd = open(IPNAT_NAME, O_RDWR); - if (natfd == -1) { - perror("open(IPL_NAT)"); - exit(1); - } - } - - if (opts & OPT_VERBOSE) - fprintf(stderr, "Starting...\n"); - while (runconfig() == 0) - ; - - exit(1); -} |