l4check.c revision 1.1.1.2 1 1.1 christos /* $NetBSD: l4check.c,v 1.1.1.2 2012/07/22 13:44:38 darrenr Exp $ */
2 1.1 christos
3 1.1 christos /*
4 1.1.1.2 darrenr * (C)Copyright (C) 2012 by Darren Reed.
5 1.1 christos */
6 1.1 christos #include <sys/types.h>
7 1.1 christos #include <sys/stat.h>
8 1.1 christos #include <sys/mman.h>
9 1.1 christos #include <sys/socket.h>
10 1.1 christos #include <sys/time.h>
11 1.1 christos #include <sys/ioctl.h>
12 1.1 christos
13 1.1 christos #include <netinet/in.h>
14 1.1 christos #include <netinet/in_systm.h>
15 1.1 christos #include <netinet/ip.h>
16 1.1 christos
17 1.1 christos #include <net/if.h>
18 1.1 christos
19 1.1 christos #include <stdio.h>
20 1.1 christos #include <netdb.h>
21 1.1 christos #include <string.h>
22 1.1 christos #include <ctype.h>
23 1.1 christos #include <fcntl.h>
24 1.1 christos #include <errno.h>
25 1.1 christos #include <stdlib.h>
26 1.1 christos
27 1.1 christos #include "ip_compat.h"
28 1.1 christos #include "ip_fil.h"
29 1.1 christos #include "ip_nat.h"
30 1.1 christos
31 1.1 christos #include "ipf.h"
32 1.1 christos
33 1.1 christos extern char *optarg;
34 1.1 christos
35 1.1 christos
36 1.1 christos typedef struct l4cfg {
37 1.1 christos struct l4cfg *l4_next;
38 1.1 christos struct ipnat l4_nat; /* NAT rule */
39 1.1 christos struct sockaddr_in l4_sin; /* remote socket to connect */
40 1.1 christos time_t l4_last; /* when we last connected */
41 1.1 christos int l4_alive; /* 1 = remote alive */
42 1.1 christos int l4_fd;
43 1.1 christos int l4_rw; /* 0 = reading, 1 = writing */
44 1.1 christos char *l4_rbuf; /* read buffer */
45 1.1 christos int l4_rsize; /* size of buffer */
46 1.1 christos int l4_rlen; /* how much used */
47 1.1 christos char *l4_wptr; /* next byte to write */
48 1.1 christos int l4_wlen; /* length yet to be written */
49 1.1 christos } l4cfg_t;
50 1.1 christos
51 1.1 christos
52 1.1 christos l4cfg_t *l4list = NULL;
53 1.1 christos char *response = NULL;
54 1.1 christos char *probe = NULL;
55 1.1 christos l4cfg_t template;
56 1.1 christos int frequency = 20;
57 1.1 christos int ctimeout = 1;
58 1.1 christos int rtimeout = 1;
59 1.1 christos size_t plen = 0;
60 1.1 christos size_t rlen = 0;
61 1.1 christos int natfd = -1;
62 1.1 christos int opts = 0;
63 1.1 christos
64 1.1 christos #if defined(sun) && !defined(__svr4__) && !defined(__SVR4)
65 1.1 christos # define strerror(x) sys_errlist[x]
66 1.1 christos #endif
67 1.1 christos
68 1.1 christos
69 1.1 christos char *copystr(dst, src)
70 1.1 christos char *dst, *src;
71 1.1 christos {
72 1.1 christos register char *s, *t, c;
73 1.1 christos register int esc = 0;
74 1.1 christos
75 1.1 christos for (s = src, t = dst; s && t && (c = *s++); )
76 1.1 christos if (esc) {
77 1.1 christos esc = 0;
78 1.1 christos switch (c)
79 1.1 christos {
80 1.1 christos case 'n' :
81 1.1 christos *t++ = '\n';
82 1.1 christos break;
83 1.1 christos case 'r' :
84 1.1 christos *t++ = '\r';
85 1.1 christos break;
86 1.1 christos case 't' :
87 1.1 christos *t++ = '\t';
88 1.1 christos break;
89 1.1 christos }
90 1.1 christos } else if (c != '\\')
91 1.1 christos *t++ = c;
92 1.1 christos else
93 1.1 christos esc = 1;
94 1.1 christos *t = '\0';
95 1.1 christos return dst;
96 1.1 christos }
97 1.1 christos
98 1.1 christos void addnat(l4)
99 1.1 christos l4cfg_t *l4;
100 1.1 christos {
101 1.1 christos ipnat_t *ipn = &l4->l4_nat;
102 1.1 christos
103 1.1 christos printf("Add NAT rule for %s/%#x,%u -> ", inet_ntoa(ipn->in_out[0]),
104 1.1 christos ipn->in_outmsk, ntohs(ipn->in_pmin));
105 1.1 christos printf("%s,%u\n", inet_ntoa(ipn->in_in[0]), ntohs(ipn->in_pnext));
106 1.1 christos if (!(opts & OPT_DONOTHING)) {
107 1.1 christos if (ioctl(natfd, SIOCADNAT, &ipn) == -1)
108 1.1 christos perror("ioctl(SIOCADNAT)");
109 1.1 christos }
110 1.1 christos }
111 1.1 christos
112 1.1 christos
113 1.1 christos void delnat(l4)
114 1.1 christos l4cfg_t *l4;
115 1.1 christos {
116 1.1 christos ipnat_t *ipn = &l4->l4_nat;
117 1.1 christos
118 1.1 christos printf("Remove NAT rule for %s/%#x,%u -> ",
119 1.1 christos inet_ntoa(ipn->in_out[0]), ipn->in_outmsk, ipn->in_pmin);
120 1.1 christos printf("%s,%u\n", inet_ntoa(ipn->in_in[0]), ipn->in_pnext);
121 1.1 christos if (!(opts & OPT_DONOTHING)) {
122 1.1 christos if (ioctl(natfd, SIOCRMNAT, &ipn) == -1)
123 1.1 christos perror("ioctl(SIOCRMNAT)");
124 1.1 christos }
125 1.1 christos }
126 1.1 christos
127 1.1 christos
128 1.1 christos void connectl4(l4)
129 1.1 christos l4cfg_t *l4;
130 1.1 christos {
131 1.1 christos l4->l4_rw = 1;
132 1.1 christos l4->l4_rlen = 0;
133 1.1 christos l4->l4_wlen = plen;
134 1.1 christos if (!l4->l4_wlen) {
135 1.1 christos l4->l4_alive = 1;
136 1.1 christos addnat(l4);
137 1.1 christos } else
138 1.1 christos l4->l4_wptr = probe;
139 1.1 christos }
140 1.1 christos
141 1.1 christos
142 1.1 christos void closel4(l4, dead)
143 1.1 christos l4cfg_t *l4;
144 1.1 christos int dead;
145 1.1 christos {
146 1.1 christos close(l4->l4_fd);
147 1.1 christos l4->l4_fd = -1;
148 1.1 christos l4->l4_rw = -1;
149 1.1 christos if (dead && l4->l4_alive) {
150 1.1 christos l4->l4_alive = 0;
151 1.1 christos delnat(l4);
152 1.1 christos }
153 1.1 christos }
154 1.1 christos
155 1.1 christos
156 1.1 christos void connectfd(l4)
157 1.1 christos l4cfg_t *l4;
158 1.1 christos {
159 1.1 christos if (connect(l4->l4_fd, (struct sockaddr *)&l4->l4_sin,
160 1.1 christos sizeof(l4->l4_sin)) == -1) {
161 1.1 christos if (errno == EISCONN) {
162 1.1 christos if (opts & OPT_VERBOSE)
163 1.1 christos fprintf(stderr, "Connected fd %d\n",
164 1.1 christos l4->l4_fd);
165 1.1 christos connectl4(l4);
166 1.1 christos return;
167 1.1 christos }
168 1.1 christos if (opts & OPT_VERBOSE)
169 1.1 christos fprintf(stderr, "Connect failed fd %d: %s\n",
170 1.1 christos l4->l4_fd, strerror(errno));
171 1.1 christos closel4(l4, 1);
172 1.1 christos return;
173 1.1 christos }
174 1.1 christos l4->l4_rw = 1;
175 1.1 christos }
176 1.1 christos
177 1.1 christos
178 1.1 christos void writefd(l4)
179 1.1 christos l4cfg_t *l4;
180 1.1 christos {
181 1.1 christos char buf[80], *ptr;
182 1.1 christos int n, i, fd;
183 1.1 christos
184 1.1 christos fd = l4->l4_fd;
185 1.1 christos
186 1.1 christos if (l4->l4_rw == -2) {
187 1.1 christos connectfd(l4);
188 1.1 christos return;
189 1.1 christos }
190 1.1 christos
191 1.1 christos n = l4->l4_wlen;
192 1.1 christos
193 1.1 christos i = send(fd, l4->l4_wptr, n, 0);
194 1.1 christos if (i == 0 || i == -1) {
195 1.1 christos if (opts & OPT_VERBOSE)
196 1.1 christos fprintf(stderr, "Send on fd %d failed: %s\n",
197 1.1 christos fd, strerror(errno));
198 1.1 christos closel4(l4, 1);
199 1.1 christos } else {
200 1.1 christos l4->l4_wptr += i;
201 1.1 christos l4->l4_wlen -= i;
202 1.1 christos if (l4->l4_wlen == 0)
203 1.1 christos l4->l4_rw = 0;
204 1.1 christos if (opts & OPT_VERBOSE)
205 1.1 christos fprintf(stderr, "Sent %d bytes to fd %d\n", i, fd);
206 1.1 christos }
207 1.1 christos }
208 1.1 christos
209 1.1 christos
210 1.1 christos void readfd(l4)
211 1.1 christos l4cfg_t *l4;
212 1.1 christos {
213 1.1 christos char buf[80], *ptr;
214 1.1 christos int n, i, fd;
215 1.1 christos
216 1.1 christos fd = l4->l4_fd;
217 1.1 christos
218 1.1 christos if (l4->l4_rw == -2) {
219 1.1 christos connectfd(l4);
220 1.1 christos return;
221 1.1 christos }
222 1.1 christos
223 1.1 christos if (l4->l4_rsize) {
224 1.1 christos n = l4->l4_rsize - l4->l4_rlen;
225 1.1 christos ptr = l4->l4_rbuf + l4->l4_rlen;
226 1.1 christos } else {
227 1.1 christos n = sizeof(buf) - 1;
228 1.1 christos ptr = buf;
229 1.1 christos }
230 1.1 christos
231 1.1 christos if (opts & OPT_VERBOSE)
232 1.1 christos fprintf(stderr, "Read %d bytes on fd %d to %p\n",
233 1.1 christos n, fd, ptr);
234 1.1 christos i = recv(fd, ptr, n, 0);
235 1.1 christos if (i == 0 || i == -1) {
236 1.1 christos if (opts & OPT_VERBOSE)
237 1.1 christos fprintf(stderr, "Read error on fd %d: %s\n",
238 1.1 christos fd, (i == 0) ? "EOF" : strerror(errno));
239 1.1 christos closel4(l4, 1);
240 1.1 christos } else {
241 1.1 christos if (ptr == buf)
242 1.1 christos ptr[i] = '\0';
243 1.1 christos if (opts & OPT_VERBOSE)
244 1.1 christos fprintf(stderr, "%d: Read %d bytes [%*.*s]\n",
245 1.1 christos fd, i, i, i, ptr);
246 1.1 christos if (ptr != buf) {
247 1.1 christos l4->l4_rlen += i;
248 1.1 christos if (l4->l4_rlen >= l4->l4_rsize) {
249 1.1 christos if (!strncmp(response, l4->l4_rbuf,
250 1.1 christos l4->l4_rsize)) {
251 1.1 christos printf("%d: Good response\n",
252 1.1 christos fd);
253 1.1 christos if (!l4->l4_alive) {
254 1.1 christos l4->l4_alive = 1;
255 1.1 christos addnat(l4);
256 1.1 christos }
257 1.1 christos closel4(l4, 0);
258 1.1 christos } else {
259 1.1 christos if (opts & OPT_VERBOSE)
260 1.1 christos printf("%d: Bad response\n",
261 1.1 christos fd);
262 1.1 christos closel4(l4, 1);
263 1.1 christos }
264 1.1 christos }
265 1.1 christos } else if (!l4->l4_alive) {
266 1.1 christos l4->l4_alive = 1;
267 1.1 christos addnat(l4);
268 1.1 christos closel4(l4, 0);
269 1.1 christos }
270 1.1 christos }
271 1.1 christos }
272 1.1 christos
273 1.1 christos
274 1.1 christos int runconfig()
275 1.1 christos {
276 1.1 christos int fd, opt, res, mfd, i;
277 1.1 christos struct timeval tv;
278 1.1 christos time_t now, now1;
279 1.1 christos fd_set rfd, wfd;
280 1.1 christos l4cfg_t *l4;
281 1.1 christos
282 1.1 christos mfd = 0;
283 1.1 christos opt = 1;
284 1.1 christos now = time(NULL);
285 1.1 christos
286 1.1 christos /*
287 1.1 christos * First, initiate connections that are closed, as required.
288 1.1 christos */
289 1.1 christos for (l4 = l4list; l4; l4 = l4->l4_next) {
290 1.1 christos if ((l4->l4_last + frequency < now) && (l4->l4_fd == -1)) {
291 1.1 christos l4->l4_last = now;
292 1.1 christos fd = socket(AF_INET, SOCK_STREAM, 0);
293 1.1 christos if (fd == -1)
294 1.1 christos continue;
295 1.1 christos setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &opt,
296 1.1 christos sizeof(opt));
297 1.1 christos #ifdef O_NONBLOCK
298 1.1 christos if ((res = fcntl(fd, F_GETFL, 0)) != -1)
299 1.1 christos fcntl(fd, F_SETFL, res | O_NONBLOCK);
300 1.1 christos #endif
301 1.1 christos if (opts & OPT_VERBOSE)
302 1.1 christos fprintf(stderr,
303 1.1 christos "Connecting to %s,%d (fd %d)...",
304 1.1 christos inet_ntoa(l4->l4_sin.sin_addr),
305 1.1 christos ntohs(l4->l4_sin.sin_port), fd);
306 1.1 christos if (connect(fd, (struct sockaddr *)&l4->l4_sin,
307 1.1 christos sizeof(l4->l4_sin)) == -1) {
308 1.1 christos if (errno != EINPROGRESS) {
309 1.1 christos if (opts & OPT_VERBOSE)
310 1.1 christos fprintf(stderr, "failed\n");
311 1.1 christos perror("connect");
312 1.1 christos close(fd);
313 1.1 christos fd = -1;
314 1.1 christos } else {
315 1.1 christos if (opts & OPT_VERBOSE)
316 1.1 christos fprintf(stderr, "waiting\n");
317 1.1 christos l4->l4_rw = -2;
318 1.1 christos }
319 1.1 christos } else {
320 1.1 christos if (opts & OPT_VERBOSE)
321 1.1 christos fprintf(stderr, "connected\n");
322 1.1 christos connectl4(l4);
323 1.1 christos }
324 1.1 christos l4->l4_fd = fd;
325 1.1 christos }
326 1.1 christos }
327 1.1 christos
328 1.1 christos /*
329 1.1 christos * Now look for fd's which we're expecting to read/write from.
330 1.1 christos */
331 1.1 christos FD_ZERO(&rfd);
332 1.1 christos FD_ZERO(&wfd);
333 1.1 christos tv.tv_sec = MIN(rtimeout, ctimeout);
334 1.1 christos tv.tv_usec = 0;
335 1.1 christos
336 1.1 christos for (l4 = l4list; l4; l4 = l4->l4_next)
337 1.1 christos if (l4->l4_rw == 0) {
338 1.1 christos if (now - l4->l4_last > rtimeout) {
339 1.1 christos if (opts & OPT_VERBOSE)
340 1.1 christos fprintf(stderr, "%d: Read timeout\n",
341 1.1 christos l4->l4_fd);
342 1.1 christos closel4(l4, 1);
343 1.1 christos continue;
344 1.1 christos }
345 1.1 christos if (opts & OPT_VERBOSE)
346 1.1 christos fprintf(stderr, "Wait for read on fd %d\n",
347 1.1 christos l4->l4_fd);
348 1.1 christos FD_SET(l4->l4_fd, &rfd);
349 1.1 christos if (l4->l4_fd > mfd)
350 1.1 christos mfd = l4->l4_fd;
351 1.1 christos } else if ((l4->l4_rw == 1 && l4->l4_wlen) ||
352 1.1 christos l4->l4_rw == -2) {
353 1.1 christos if ((l4->l4_rw == -2) &&
354 1.1 christos (now - l4->l4_last > ctimeout)) {
355 1.1 christos if (opts & OPT_VERBOSE)
356 1.1 christos fprintf(stderr,
357 1.1 christos "%d: connect timeout\n",
358 1.1 christos l4->l4_fd);
359 1.1 christos closel4(l4);
360 1.1 christos continue;
361 1.1 christos }
362 1.1 christos if (opts & OPT_VERBOSE)
363 1.1 christos fprintf(stderr, "Wait for write on fd %d\n",
364 1.1 christos l4->l4_fd);
365 1.1 christos FD_SET(l4->l4_fd, &wfd);
366 1.1 christos if (l4->l4_fd > mfd)
367 1.1 christos mfd = l4->l4_fd;
368 1.1 christos }
369 1.1 christos
370 1.1 christos if (opts & OPT_VERBOSE)
371 1.1 christos fprintf(stderr, "Select: max fd %d wait %d\n", mfd + 1,
372 1.1 christos tv.tv_sec);
373 1.1 christos i = select(mfd + 1, &rfd, &wfd, NULL, &tv);
374 1.1 christos if (i == -1) {
375 1.1 christos perror("select");
376 1.1 christos return -1;
377 1.1 christos }
378 1.1 christos
379 1.1 christos now1 = time(NULL);
380 1.1 christos
381 1.1 christos for (l4 = l4list; (i > 0) && l4; l4 = l4->l4_next) {
382 1.1 christos if (l4->l4_fd < 0)
383 1.1 christos continue;
384 1.1 christos if (FD_ISSET(l4->l4_fd, &rfd)) {
385 1.1 christos if (opts & OPT_VERBOSE)
386 1.1 christos fprintf(stderr, "Ready to read on fd %d\n",
387 1.1 christos l4->l4_fd);
388 1.1 christos readfd(l4);
389 1.1 christos i--;
390 1.1 christos }
391 1.1 christos
392 1.1 christos if ((l4->l4_fd >= 0) && FD_ISSET(l4->l4_fd, &wfd)) {
393 1.1 christos if (opts & OPT_VERBOSE)
394 1.1 christos fprintf(stderr, "Ready to write on fd %d\n",
395 1.1 christos l4->l4_fd);
396 1.1 christos writefd(l4);
397 1.1 christos i--;
398 1.1 christos }
399 1.1 christos }
400 1.1 christos return 0;
401 1.1 christos }
402 1.1 christos
403 1.1 christos
404 1.1 christos int gethostport(str, lnum, ipp, portp)
405 1.1 christos char *str;
406 1.1 christos int lnum;
407 1.1 christos u_32_t *ipp;
408 1.1 christos u_short *portp;
409 1.1 christos {
410 1.1 christos struct servent *sp;
411 1.1 christos struct hostent *hp;
412 1.1 christos char *host, *port;
413 1.1 christos struct in_addr ip;
414 1.1 christos
415 1.1 christos host = str;
416 1.1 christos port = strchr(host, ',');
417 1.1 christos if (port)
418 1.1 christos *port++ = '\0';
419 1.1 christos
420 1.1 christos #ifdef HAVE_INET_ATON
421 1.1 christos if (ISDIGIT(*host) && inet_aton(host, &ip))
422 1.1 christos *ipp = ip.s_addr;
423 1.1 christos #else
424 1.1 christos if (ISDIGIT(*host))
425 1.1 christos *ipp = inet_addr(host);
426 1.1 christos #endif
427 1.1 christos else {
428 1.1 christos if (!(hp = gethostbyname(host))) {
429 1.1 christos fprintf(stderr, "%d: can't resolve hostname: %s\n",
430 1.1 christos lnum, host);
431 1.1 christos return 0;
432 1.1 christos }
433 1.1 christos *ipp = *(u_32_t *)hp->h_addr;
434 1.1 christos }
435 1.1 christos
436 1.1 christos if (port) {
437 1.1 christos if (ISDIGIT(*port))
438 1.1 christos *portp = htons(atoi(port));
439 1.1 christos else {
440 1.1 christos sp = getservbyname(port, "tcp");
441 1.1 christos if (sp)
442 1.1 christos *portp = sp->s_port;
443 1.1 christos else {
444 1.1 christos fprintf(stderr, "%d: unknown service %s\n",
445 1.1 christos lnum, port);
446 1.1 christos return 0;
447 1.1 christos }
448 1.1 christos }
449 1.1 christos } else
450 1.1 christos *portp = 0;
451 1.1 christos return 1;
452 1.1 christos }
453 1.1 christos
454 1.1 christos
455 1.1 christos char *mapfile(file, sizep)
456 1.1 christos char *file;
457 1.1 christos size_t *sizep;
458 1.1 christos {
459 1.1 christos struct stat sb;
460 1.1 christos caddr_t addr;
461 1.1 christos int fd;
462 1.1 christos
463 1.1 christos fd = open(file, O_RDONLY);
464 1.1 christos if (fd == -1) {
465 1.1 christos perror("open(mapfile)");
466 1.1 christos return NULL;
467 1.1 christos }
468 1.1 christos
469 1.1 christos if (fstat(fd, &sb) == -1) {
470 1.1 christos perror("fstat(mapfile)");
471 1.1 christos close(fd);
472 1.1 christos return NULL;
473 1.1 christos }
474 1.1 christos
475 1.1 christos addr = mmap(NULL, sb.st_size, PROT_READ, MAP_SHARED, fd, 0);
476 1.1 christos if (addr == (caddr_t)-1) {
477 1.1 christos perror("mmap(mapfile)");
478 1.1 christos close(fd);
479 1.1 christos return NULL;
480 1.1 christos }
481 1.1 christos close(fd);
482 1.1 christos *sizep = sb.st_size;
483 1.1 christos return (char *)addr;
484 1.1 christos }
485 1.1 christos
486 1.1 christos
487 1.1 christos int readconfig(filename)
488 1.1 christos char *filename;
489 1.1 christos {
490 1.1 christos char c, buf[512], *s, *t, *errtxt = NULL, *line;
491 1.1 christos int num, err = 0;
492 1.1 christos ipnat_t *ipn;
493 1.1 christos l4cfg_t *l4;
494 1.1 christos FILE *fp;
495 1.1 christos
496 1.1 christos fp = fopen(filename, "r");
497 1.1 christos if (!fp) {
498 1.1 christos perror("open(configfile)");
499 1.1 christos return -1;
500 1.1 christos }
501 1.1 christos
502 1.1 christos bzero((char *)&template, sizeof(template));
503 1.1 christos template.l4_fd = -1;
504 1.1 christos template.l4_rw = -1;
505 1.1 christos template.l4_sin.sin_family = AF_INET;
506 1.1 christos ipn = &template.l4_nat;
507 1.1 christos ipn->in_flags = IPN_TCP|IPN_ROUNDR;
508 1.1 christos ipn->in_redir = NAT_REDIRECT;
509 1.1 christos
510 1.1 christos for (num = 1; fgets(buf, sizeof(buf), fp); num++) {
511 1.1 christos s = strchr(buf, '\n');
512 1.1 christos if (!s) {
513 1.1 christos fprintf(stderr, "%d: line too long\n", num);
514 1.1 christos fclose(fp);
515 1.1 christos return -1;
516 1.1 christos }
517 1.1 christos
518 1.1 christos *s = '\0';
519 1.1 christos
520 1.1 christos /*
521 1.1 christos * lines which are comments
522 1.1 christos */
523 1.1 christos s = strchr(buf, '#');
524 1.1 christos if (s)
525 1.1 christos *s = '\0';
526 1.1 christos
527 1.1 christos /*
528 1.1 christos * Skip leading whitespace
529 1.1 christos */
530 1.1 christos for (line = buf; (c = *line) && ISSPACE(c); line++)
531 1.1 christos ;
532 1.1 christos if (!*line)
533 1.1 christos continue;
534 1.1 christos
535 1.1 christos if (opts & OPT_VERBOSE)
536 1.1 christos fprintf(stderr, "Parsing: [%s]\n", line);
537 1.1 christos t = strtok(line, " \t");
538 1.1 christos if (!t)
539 1.1 christos continue;
540 1.1 christos if (!strcasecmp(t, "interface")) {
541 1.1 christos s = strtok(NULL, " \t");
542 1.1 christos if (s)
543 1.1 christos t = strtok(NULL, "\t");
544 1.1 christos if (!s || !t) {
545 1.1 christos errtxt = line;
546 1.1 christos err = -1;
547 1.1 christos break;
548 1.1 christos }
549 1.1 christos
550 1.1 christos if (!strchr(t, ',')) {
551 1.1 christos fprintf(stderr,
552 1.1 christos "%d: local address,port missing\n",
553 1.1 christos num);
554 1.1 christos err = -1;
555 1.1 christos break;
556 1.1 christos }
557 1.1 christos
558 1.1 christos strncpy(ipn->in_ifname, s, sizeof(ipn->in_ifname));
559 1.1 christos if (!gethostport(t, num, &ipn->in_outip,
560 1.1 christos &ipn->in_pmin)) {
561 1.1 christos errtxt = line;
562 1.1 christos err = -1;
563 1.1 christos break;
564 1.1 christos }
565 1.1 christos ipn->in_outmsk = 0xffffffff;
566 1.1 christos ipn->in_pmax = ipn->in_pmin;
567 1.1 christos if (opts & OPT_VERBOSE)
568 1.1 christos fprintf(stderr,
569 1.1 christos "Interface %s %s/%#x port %u\n",
570 1.1 christos ipn->in_ifname,
571 1.1 christos inet_ntoa(ipn->in_out[0]),
572 1.1 christos ipn->in_outmsk, ipn->in_pmin);
573 1.1 christos } else if (!strcasecmp(t, "remote")) {
574 1.1 christos if (!*ipn->in_ifname) {
575 1.1 christos fprintf(stderr,
576 1.1 christos "%d: ifname not set prior to remote\n",
577 1.1 christos num);
578 1.1 christos err = -1;
579 1.1 christos break;
580 1.1 christos }
581 1.1 christos s = strtok(NULL, " \t");
582 1.1 christos if (s)
583 1.1 christos t = strtok(NULL, "");
584 1.1 christos if (!s || !t || strcasecmp(s, "server")) {
585 1.1 christos errtxt = line;
586 1.1 christos err = -1;
587 1.1 christos break;
588 1.1 christos }
589 1.1 christos
590 1.1 christos ipn->in_pnext = 0;
591 1.1 christos if (!gethostport(t, num, &ipn->in_inip,
592 1.1 christos &ipn->in_pnext)) {
593 1.1 christos errtxt = line;
594 1.1 christos err = -1;
595 1.1 christos break;
596 1.1 christos }
597 1.1 christos ipn->in_inmsk = 0xffffffff;
598 1.1 christos if (ipn->in_pnext == 0)
599 1.1 christos ipn->in_pnext = ipn->in_pmin;
600 1.1 christos
601 1.1 christos l4 = (l4cfg_t *)malloc(sizeof(*l4));
602 1.1 christos if (!l4) {
603 1.1 christos fprintf(stderr, "%d: out of memory (%d)\n",
604 1.1 christos num, sizeof(*l4));
605 1.1 christos err = -1;
606 1.1 christos break;
607 1.1 christos }
608 1.1 christos bcopy((char *)&template, (char *)l4, sizeof(*l4));
609 1.1 christos l4->l4_sin.sin_addr = ipn->in_in[0];
610 1.1 christos l4->l4_sin.sin_port = ipn->in_pnext;
611 1.1 christos l4->l4_next = l4list;
612 1.1 christos l4list = l4;
613 1.1 christos } else if (!strcasecmp(t, "connect")) {
614 1.1 christos s = strtok(NULL, " \t");
615 1.1 christos if (s)
616 1.1 christos t = strtok(NULL, "\t");
617 1.1 christos if (!s || !t) {
618 1.1 christos errtxt = line;
619 1.1 christos err = -1;
620 1.1 christos break;
621 1.1 christos } else if (!strcasecmp(s, "timeout")) {
622 1.1 christos ctimeout = atoi(t);
623 1.1 christos if (opts & OPT_VERBOSE)
624 1.1 christos fprintf(stderr, "connect timeout %d\n",
625 1.1 christos ctimeout);
626 1.1 christos } else if (!strcasecmp(s, "frequency")) {
627 1.1 christos frequency = atoi(t);
628 1.1 christos if (opts & OPT_VERBOSE)
629 1.1 christos fprintf(stderr,
630 1.1 christos "connect frequency %d\n",
631 1.1 christos frequency);
632 1.1 christos } else {
633 1.1 christos errtxt = line;
634 1.1 christos err = -1;
635 1.1 christos break;
636 1.1 christos }
637 1.1 christos } else if (!strcasecmp(t, "probe")) {
638 1.1 christos s = strtok(NULL, " \t");
639 1.1 christos if (!s) {
640 1.1 christos errtxt = line;
641 1.1 christos err = -1;
642 1.1 christos break;
643 1.1 christos } else if (!strcasecmp(s, "string")) {
644 1.1 christos if (probe) {
645 1.1 christos fprintf(stderr,
646 1.1 christos "%d: probe already set\n",
647 1.1 christos num);
648 1.1 christos err = -1;
649 1.1 christos break;
650 1.1 christos }
651 1.1 christos t = strtok(NULL, "");
652 1.1 christos if (!t) {
653 1.1 christos fprintf(stderr,
654 1.1 christos "%d: No probe string\n", num);
655 1.1 christos err = -1;
656 1.1 christos break;
657 1.1 christos }
658 1.1 christos
659 1.1 christos probe = malloc(strlen(t));
660 1.1 christos copystr(probe, t);
661 1.1 christos plen = strlen(probe);
662 1.1 christos if (opts & OPT_VERBOSE)
663 1.1 christos fprintf(stderr, "Probe string [%s]\n",
664 1.1 christos probe);
665 1.1 christos } else if (!strcasecmp(s, "file")) {
666 1.1 christos t = strtok(NULL, " \t");
667 1.1 christos if (!t) {
668 1.1 christos errtxt = line;
669 1.1 christos err = -1;
670 1.1 christos break;
671 1.1 christos }
672 1.1 christos if (probe) {
673 1.1 christos fprintf(stderr,
674 1.1 christos "%d: probe already set\n",
675 1.1 christos num);
676 1.1 christos err = -1;
677 1.1 christos break;
678 1.1 christos }
679 1.1 christos probe = mapfile(t, &plen);
680 1.1 christos if (opts & OPT_VERBOSE)
681 1.1 christos fprintf(stderr,
682 1.1 christos "Probe file %s len %u@%p\n",
683 1.1 christos t, plen, probe);
684 1.1 christos }
685 1.1 christos } else if (!strcasecmp(t, "response")) {
686 1.1 christos s = strtok(NULL, " \t");
687 1.1 christos if (!s) {
688 1.1 christos errtxt = line;
689 1.1 christos err = -1;
690 1.1 christos break;
691 1.1 christos } else if (!strcasecmp(s, "timeout")) {
692 1.1 christos t = strtok(NULL, " \t");
693 1.1 christos if (!t) {
694 1.1 christos errtxt = line;
695 1.1 christos err = -1;
696 1.1 christos break;
697 1.1 christos }
698 1.1 christos rtimeout = atoi(t);
699 1.1 christos if (opts & OPT_VERBOSE)
700 1.1 christos fprintf(stderr,
701 1.1 christos "response timeout %d\n",
702 1.1 christos rtimeout);
703 1.1 christos } else if (!strcasecmp(s, "string")) {
704 1.1 christos if (response) {
705 1.1 christos fprintf(stderr,
706 1.1 christos "%d: response already set\n",
707 1.1 christos num);
708 1.1 christos err = -1;
709 1.1 christos break;
710 1.1 christos }
711 1.1 christos response = strdup(strtok(NULL, ""));
712 1.1 christos rlen = strlen(response);
713 1.1 christos template.l4_rsize = rlen;
714 1.1 christos template.l4_rbuf = malloc(rlen);
715 1.1 christos if (opts & OPT_VERBOSE)
716 1.1 christos fprintf(stderr,
717 1.1 christos "Response string [%s]\n",
718 1.1 christos response);
719 1.1 christos } else if (!strcasecmp(s, "file")) {
720 1.1 christos t = strtok(NULL, " \t");
721 1.1 christos if (!t) {
722 1.1 christos errtxt = line;
723 1.1 christos err = -1;
724 1.1 christos break;
725 1.1 christos }
726 1.1 christos if (response) {
727 1.1 christos fprintf(stderr,
728 1.1 christos "%d: response already set\n",
729 1.1 christos num);
730 1.1 christos err = -1;
731 1.1 christos break;
732 1.1 christos }
733 1.1 christos response = mapfile(t, &rlen);
734 1.1 christos template.l4_rsize = rlen;
735 1.1 christos template.l4_rbuf = malloc(rlen);
736 1.1 christos if (opts & OPT_VERBOSE)
737 1.1 christos fprintf(stderr,
738 1.1 christos "Response file %s len %u@%p\n",
739 1.1 christos t, rlen, response);
740 1.1 christos }
741 1.1 christos } else {
742 1.1 christos errtxt = line;
743 1.1 christos err = -1;
744 1.1 christos break;
745 1.1 christos }
746 1.1 christos }
747 1.1 christos
748 1.1 christos if (errtxt)
749 1.1 christos fprintf(stderr, "%d: syntax error at \"%s\"\n", num, errtxt);
750 1.1 christos fclose(fp);
751 1.1 christos return err;
752 1.1 christos }
753 1.1 christos
754 1.1 christos
755 1.1 christos void usage(prog)
756 1.1 christos char *prog;
757 1.1 christos {
758 1.1 christos fprintf(stderr, "Usage: %s -f <configfile>\n", prog);
759 1.1 christos exit(1);
760 1.1 christos }
761 1.1 christos
762 1.1 christos
763 1.1 christos int main(argc, argv)
764 1.1 christos int argc;
765 1.1 christos char *argv[];
766 1.1 christos {
767 1.1 christos char *config = NULL;
768 1.1 christos int c;
769 1.1 christos
770 1.1 christos while ((c = getopt(argc, argv, "f:nv")) != -1)
771 1.1 christos switch (c)
772 1.1 christos {
773 1.1 christos case 'f' :
774 1.1 christos config = optarg;
775 1.1 christos break;
776 1.1 christos case 'n' :
777 1.1 christos opts |= OPT_DONOTHING;
778 1.1 christos break;
779 1.1 christos case 'v' :
780 1.1 christos opts |= OPT_VERBOSE;
781 1.1 christos break;
782 1.1 christos }
783 1.1 christos
784 1.1 christos if (config == NULL)
785 1.1 christos usage(argv[0]);
786 1.1 christos
787 1.1 christos if (readconfig(config))
788 1.1 christos exit(1);
789 1.1 christos
790 1.1 christos if (!l4list) {
791 1.1 christos fprintf(stderr, "No remote servers, exiting.");
792 1.1 christos exit(1);
793 1.1 christos }
794 1.1 christos
795 1.1 christos if (!(opts & OPT_DONOTHING)) {
796 1.1 christos natfd = open(IPL_NAT, O_RDWR);
797 1.1 christos if (natfd == -1) {
798 1.1 christos perror("open(IPL_NAT)");
799 1.1 christos exit(1);
800 1.1 christos }
801 1.1 christos }
802 1.1 christos
803 1.1 christos if (opts & OPT_VERBOSE)
804 1.1 christos fprintf(stderr, "Starting...\n");
805 1.1 christos while (runconfig() == 0)
806 1.1 christos ;
807 1.1 christos }
808