809 lines
15 KiB
C
809 lines
15 KiB
C
/* $NetBSD: l4check.c,v 1.1.1.2 2002/05/02 16:57:24 martti Exp $ */
|
|
|
|
/*
|
|
* (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 "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]),
|
|
ipn->in_outmsk, ntohs(ipn->in_pmin));
|
|
printf("%s,%u\n", inet_ntoa(ipn->in_in[0]), ntohs(ipn->in_pnext));
|
|
if (!(opts & OPT_DONOTHING)) {
|
|
if (ioctl(natfd, SIOCADNAT, &ipn) == -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]), ipn->in_outmsk, ipn->in_pmin);
|
|
printf("%s,%u\n", inet_ntoa(ipn->in_in[0]), ipn->in_pnext);
|
|
if (!(opts & OPT_DONOTHING)) {
|
|
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;
|
|
{
|
|
if (l4->l4_fd != -1)
|
|
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;
|
|
{
|
|
char buf[80], *ptr;
|
|
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");
|
|
closel4(l4, 1);
|
|
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;
|
|
struct in_addr ip;
|
|
|
|
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_ifname, s, sizeof(ipn->in_ifname));
|
|
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_ifname,
|
|
inet_ntoa(ipn->in_out[0]),
|
|
ipn->in_outmsk, ipn->in_pmin);
|
|
} else if (!strcasecmp(t, "remote")) {
|
|
if (!*ipn->in_ifname) {
|
|
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];
|
|
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(IPL_NAT, O_RDWR);
|
|
if (natfd == -1) {
|
|
perror("open(IPL_NAT)");
|
|
exit(1);
|
|
}
|
|
}
|
|
|
|
if (opts & OPT_VERBOSE)
|
|
fprintf(stderr, "Starting...\n");
|
|
while (runconfig() == 0)
|
|
;
|
|
}
|