1 /* $NetBSD: l4check.c,v 1.2 2004/11/13 19:16:10 he Exp $ */
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)