4 * (C)Copyright March, 2000 - Darren Reed.
9 #include <sys/socket.h>
11 #include <sys/ioctl.h>
13 #include <netinet/in.h>
14 #include <netinet/in_systm.h>
15 #include <netinet/ip.h>
27 #include "ip_compat.h"
37 typedef struct l4cfg {
38 struct l4cfg *l4_next;
39 struct ipnat l4_nat; /* NAT rule */
40 struct sockaddr_in l4_sin; /* remote socket to connect */
41 time_t l4_last; /* when we last connected */
42 int l4_alive; /* 1 = remote alive */
44 int l4_rw; /* 0 = reading, 1 = writing */
45 char *l4_rbuf; /* read buffer */
46 int l4_rsize; /* size of buffer */
47 int l4_rlen; /* how much used */
48 char *l4_wptr; /* next byte to write */
49 int l4_wlen; /* length yet to be written */
53 l4cfg_t *l4list = NULL;
54 char *response = NULL;
65 #if defined(sun) && !defined(__svr4__) && !defined(__SVR4)
66 # define strerror(x) sys_errlist[x]
70 char *copystr(dst, src)
73 register char *s, *t, c;
76 for (s = src, t = dst; s && t && (c = *s++); )
103 ipnat_t *ipn = &l4->l4_nat;
105 printf("Add NAT rule for %s/%#x,%u -> ", inet_ntoa(ipn->in_out[0].in4),
106 ipn->in_outmsk, ntohs(ipn->in_pmin));
107 printf("%s,%u\n", inet_ntoa(ipn->in_in[0].in4), ntohs(ipn->in_pnext));
108 if (!(opts & OPT_DONOTHING)) {
111 bzero(&obj, sizeof(obj));
112 obj.ipfo_rev = IPFILTER_VERSION;
113 obj.ipfo_size = sizeof(*ipn);
116 if (ioctl(natfd, SIOCADNAT, &obj) == -1)
117 perror("ioctl(SIOCADNAT)");
125 ipnat_t *ipn = &l4->l4_nat;
127 printf("Remove NAT rule for %s/%#x,%u -> ",
128 inet_ntoa(ipn->in_out[0].in4), ipn->in_outmsk, ipn->in_pmin);
129 printf("%s,%u\n", inet_ntoa(ipn->in_in[0].in4), ipn->in_pnext);
130 if (!(opts & OPT_DONOTHING)) {
133 bzero(&obj, sizeof(obj));
134 obj.ipfo_rev = IPFILTER_VERSION;
135 obj.ipfo_size = sizeof(*ipn);
138 if (ioctl(natfd, SIOCRMNAT, &ipn) == -1)
139 perror("ioctl(SIOCRMNAT)");
158 void closel4(l4, dead)
165 if (dead && l4->l4_alive) {
175 if (connect(l4->l4_fd, (struct sockaddr *)&l4->l4_sin,
176 sizeof(l4->l4_sin)) == -1) {
177 if (errno == EISCONN) {
178 if (opts & OPT_VERBOSE)
179 fprintf(stderr, "Connected fd %d\n",
184 if (opts & OPT_VERBOSE)
185 fprintf(stderr, "Connect failed fd %d: %s\n",
186 l4->l4_fd, strerror(errno));
201 if (l4->l4_rw == -2) {
208 i = send(fd, l4->l4_wptr, n, 0);
209 if (i == 0 || i == -1) {
210 if (opts & OPT_VERBOSE)
211 fprintf(stderr, "Send on fd %d failed: %s\n",
212 fd, strerror(errno));
217 if (l4->l4_wlen == 0)
219 if (opts & OPT_VERBOSE)
220 fprintf(stderr, "Sent %d bytes to fd %d\n", i, fd);
233 if (l4->l4_rw == -2) {
239 n = l4->l4_rsize - l4->l4_rlen;
240 ptr = l4->l4_rbuf + l4->l4_rlen;
246 if (opts & OPT_VERBOSE)
247 fprintf(stderr, "Read %d bytes on fd %d to %p\n",
249 i = recv(fd, ptr, n, 0);
250 if (i == 0 || i == -1) {
251 if (opts & OPT_VERBOSE)
252 fprintf(stderr, "Read error on fd %d: %s\n",
253 fd, (i == 0) ? "EOF" : strerror(errno));
258 if (opts & OPT_VERBOSE)
259 fprintf(stderr, "%d: Read %d bytes [%*.*s]\n",
263 if (l4->l4_rlen >= l4->l4_rsize) {
264 if (!strncmp(response, l4->l4_rbuf,
266 printf("%d: Good response\n",
274 if (opts & OPT_VERBOSE)
275 printf("%d: Bad response\n",
280 } else if (!l4->l4_alive) {
291 int fd, opt, res, mfd, i;
302 * First, initiate connections that are closed, as required.
304 for (l4 = l4list; l4; l4 = l4->l4_next) {
305 if ((l4->l4_last + frequency < now) && (l4->l4_fd == -1)) {
307 fd = socket(AF_INET, SOCK_STREAM, 0);
310 setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &opt,
313 if ((res = fcntl(fd, F_GETFL, 0)) != -1)
314 fcntl(fd, F_SETFL, res | O_NONBLOCK);
316 if (opts & OPT_VERBOSE)
318 "Connecting to %s,%d (fd %d)...",
319 inet_ntoa(l4->l4_sin.sin_addr),
320 ntohs(l4->l4_sin.sin_port), fd);
321 if (connect(fd, (struct sockaddr *)&l4->l4_sin,
322 sizeof(l4->l4_sin)) == -1) {
323 if (errno != EINPROGRESS) {
324 if (opts & OPT_VERBOSE)
325 fprintf(stderr, "failed\n");
330 if (opts & OPT_VERBOSE)
331 fprintf(stderr, "waiting\n");
335 if (opts & OPT_VERBOSE)
336 fprintf(stderr, "connected\n");
344 * Now look for fd's which we're expecting to read/write from.
348 tv.tv_sec = MIN(rtimeout, ctimeout);
351 for (l4 = l4list; l4; l4 = l4->l4_next)
352 if (l4->l4_rw == 0) {
353 if (now - l4->l4_last > rtimeout) {
354 if (opts & OPT_VERBOSE)
355 fprintf(stderr, "%d: Read timeout\n",
360 if (opts & OPT_VERBOSE)
361 fprintf(stderr, "Wait for read on fd %d\n",
363 FD_SET(l4->l4_fd, &rfd);
366 } else if ((l4->l4_rw == 1 && l4->l4_wlen) ||
368 if ((l4->l4_rw == -2) &&
369 (now - l4->l4_last > ctimeout)) {
370 if (opts & OPT_VERBOSE)
372 "%d: connect timeout\n",
377 if (opts & OPT_VERBOSE)
378 fprintf(stderr, "Wait for write on fd %d\n",
380 FD_SET(l4->l4_fd, &wfd);
385 if (opts & OPT_VERBOSE)
386 fprintf(stderr, "Select: max fd %d wait %d\n", mfd + 1,
388 i = select(mfd + 1, &rfd, &wfd, NULL, &tv);
396 for (l4 = l4list; (i > 0) && l4; l4 = l4->l4_next) {
399 if (FD_ISSET(l4->l4_fd, &rfd)) {
400 if (opts & OPT_VERBOSE)
401 fprintf(stderr, "Ready to read on fd %d\n",
407 if ((l4->l4_fd >= 0) && FD_ISSET(l4->l4_fd, &wfd)) {
408 if (opts & OPT_VERBOSE)
409 fprintf(stderr, "Ready to write on fd %d\n",
419 int gethostport(str, lnum, ipp, portp)
430 port = strchr(host, ',');
434 #ifdef HAVE_INET_ATON
435 if (ISDIGIT(*host) && inet_aton(host, &ip))
439 *ipp = inet_addr(host);
442 if (!(hp = gethostbyname(host))) {
443 fprintf(stderr, "%d: can't resolve hostname: %s\n",
447 *ipp = *(u_32_t *)hp->h_addr;
452 *portp = htons(atoi(port));
454 sp = getservbyname(port, "tcp");
458 fprintf(stderr, "%d: unknown service %s\n",
469 char *mapfile(file, sizep)
477 fd = open(file, O_RDONLY);
479 perror("open(mapfile)");
483 if (fstat(fd, &sb) == -1) {
484 perror("fstat(mapfile)");
489 addr = mmap(NULL, sb.st_size, PROT_READ, MAP_SHARED, fd, 0);
490 if (addr == (caddr_t)-1) {
491 perror("mmap(mapfile)");
501 int readconfig(filename)
504 char c, buf[512], *s, *t, *errtxt = NULL, *line;
510 fp = fopen(filename, "r");
512 perror("open(configfile)");
516 bzero((char *)&template, sizeof(template));
519 template.l4_sin.sin_family = AF_INET;
520 ipn = &template.l4_nat;
521 ipn->in_flags = IPN_TCP|IPN_ROUNDR;
522 ipn->in_redir = NAT_REDIRECT;
524 for (num = 1; fgets(buf, sizeof(buf), fp); num++) {
525 s = strchr(buf, '\n');
527 fprintf(stderr, "%d: line too long\n", num);
535 * lines which are comments
537 s = strchr(buf, '#');
542 * Skip leading whitespace
544 for (line = buf; (c = *line) && ISSPACE(c); line++)
549 if (opts & OPT_VERBOSE)
550 fprintf(stderr, "Parsing: [%s]\n", line);
551 t = strtok(line, " \t");
554 if (!strcasecmp(t, "interface")) {
555 s = strtok(NULL, " \t");
557 t = strtok(NULL, "\t");
564 if (!strchr(t, ',')) {
566 "%d: local address,port missing\n",
572 strncpy(ipn->in_ifnames[0], s, LIFNAMSIZ);
573 strncpy(ipn->in_ifnames[1], s, LIFNAMSIZ);
574 if (!gethostport(t, num, &ipn->in_outip,
580 ipn->in_outmsk = 0xffffffff;
581 ipn->in_pmax = ipn->in_pmin;
582 if (opts & OPT_VERBOSE)
584 "Interface %s %s/%#x port %u\n",
586 inet_ntoa(ipn->in_out[0].in4),
587 ipn->in_outmsk, ipn->in_pmin);
588 } else if (!strcasecmp(t, "remote")) {
589 if (!*ipn->in_ifnames[0]) {
591 "%d: ifname not set prior to remote\n",
596 s = strtok(NULL, " \t");
598 t = strtok(NULL, "");
599 if (!s || !t || strcasecmp(s, "server")) {
606 if (!gethostport(t, num, &ipn->in_inip,
612 ipn->in_inmsk = 0xffffffff;
613 if (ipn->in_pnext == 0)
614 ipn->in_pnext = ipn->in_pmin;
616 l4 = (l4cfg_t *)malloc(sizeof(*l4));
618 fprintf(stderr, "%d: out of memory (%d)\n",
623 bcopy((char *)&template, (char *)l4, sizeof(*l4));
624 l4->l4_sin.sin_addr = ipn->in_in[0].in4;
625 l4->l4_sin.sin_port = ipn->in_pnext;
626 l4->l4_next = l4list;
628 } else if (!strcasecmp(t, "connect")) {
629 s = strtok(NULL, " \t");
631 t = strtok(NULL, "\t");
636 } else if (!strcasecmp(s, "timeout")) {
638 if (opts & OPT_VERBOSE)
639 fprintf(stderr, "connect timeout %d\n",
641 } else if (!strcasecmp(s, "frequency")) {
643 if (opts & OPT_VERBOSE)
645 "connect frequency %d\n",
652 } else if (!strcasecmp(t, "probe")) {
653 s = strtok(NULL, " \t");
658 } else if (!strcasecmp(s, "string")) {
661 "%d: probe already set\n",
666 t = strtok(NULL, "");
669 "%d: No probe string\n", num);
674 probe = malloc(strlen(t));
676 plen = strlen(probe);
677 if (opts & OPT_VERBOSE)
678 fprintf(stderr, "Probe string [%s]\n",
680 } else if (!strcasecmp(s, "file")) {
681 t = strtok(NULL, " \t");
689 "%d: probe already set\n",
694 probe = mapfile(t, &plen);
695 if (opts & OPT_VERBOSE)
697 "Probe file %s len %u@%p\n",
700 } else if (!strcasecmp(t, "response")) {
701 s = strtok(NULL, " \t");
706 } else if (!strcasecmp(s, "timeout")) {
707 t = strtok(NULL, " \t");
714 if (opts & OPT_VERBOSE)
716 "response timeout %d\n",
718 } else if (!strcasecmp(s, "string")) {
721 "%d: response already set\n",
726 response = strdup(strtok(NULL, ""));
727 rlen = strlen(response);
728 template.l4_rsize = rlen;
729 template.l4_rbuf = malloc(rlen);
730 if (opts & OPT_VERBOSE)
732 "Response string [%s]\n",
734 } else if (!strcasecmp(s, "file")) {
735 t = strtok(NULL, " \t");
743 "%d: response already set\n",
748 response = mapfile(t, &rlen);
749 template.l4_rsize = rlen;
750 template.l4_rbuf = malloc(rlen);
751 if (opts & OPT_VERBOSE)
753 "Response file %s len %u@%p\n",
764 fprintf(stderr, "%d: syntax error at \"%s\"\n", num, errtxt);
773 fprintf(stderr, "Usage: %s -f <configfile>\n", prog);
785 while ((c = getopt(argc, argv, "f:nv")) != -1)
792 opts |= OPT_DONOTHING;
802 if (readconfig(config))
806 fprintf(stderr, "No remote servers, exiting.");
810 if (!(opts & OPT_DONOTHING)) {
811 natfd = open(IPNAT_NAME, O_RDWR);
813 perror("open(IPL_NAT)");
818 if (opts & OPT_VERBOSE)
819 fprintf(stderr, "Starting...\n");
820 while (runconfig() == 0)