chiark / gitweb /
Initial revision
[fwd] / fw.c
1 /* -*-c-*-
2  *
3  * $Id: fw.c,v 1.1 1999/07/01 08:56:23 mdw Exp $
4  *
5  * Port forwarding thingy
6  *
7  * (c) 1999 Mark Wooding
8  */
9
10 /*----- Licensing notice --------------------------------------------------* 
11  *
12  * This file is part of the `fw' port forwarder.
13  *
14  * `fw' is free software; you can redistribute it and/or modify
15  * it under the terms of the GNU General Public License as published by
16  * the Free Software Foundation; either version 2 of the License, or
17  * (at your option) any later version.
18  * 
19  * `fw' is distributed in the hope that it will be useful,
20  * but WITHOUT ANY WARRANTY; without even the implied warranty of
21  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22  * GNU General Public License for more details.
23  * 
24  * You should have received a copy of the GNU General Public License
25  * along with `fw'; if not, write to the Free Software Foundation,
26  * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
27  */
28
29 /*----- Revision history --------------------------------------------------* 
30  *
31  * $Log: fw.c,v $
32  * Revision 1.1  1999/07/01 08:56:23  mdw
33  * Initial revision
34  *
35  */
36
37 /*----- Header files ------------------------------------------------------*/
38
39 #include "config.h"
40
41 #include <ctype.h>
42 #include <errno.h>
43 #include <stdio.h>
44 #include <stdlib.h>
45 #include <string.h>
46
47 #include <unistd.h>
48 #include <syslog.h>
49
50 #include <mLib/mdwopt.h>
51 #include <mLib/quis.h>
52 #include <mLib/report.h>
53 #include <mLib/sel.h>
54 #include <mLib/sub.h>
55
56 #include "acl.h"
57 #include "bres.h"
58 #include "conf.h"
59 #include "listener.h"
60 #include "scan.h"
61
62 /*----- Static variables --------------------------------------------------*/
63
64 sel_state *sel;                         /* Multiplexor for nonblocking I/O */
65
66 /*----- Main code ---------------------------------------------------------*/
67
68 /* --- Standard GNU help options --- */
69
70 static void version(FILE *fp)
71 {
72   fprintf(fp, "%s version " VERSION "\n", QUIS);
73 }
74
75 static void usage(FILE *fp)
76 {
77   fprintf(stderr, "Usage: %s [-d] [-f file] [config statements...]\n",
78           QUIS);
79 }
80
81 static void help(FILE *fp)
82 {
83   version(fp);
84   fputc('\n', fp);
85   usage(fp);
86   fputs("\n\
87 A fairly full-featured port-forwarder.  Options available are:\n\
88 \n\
89 -h, --help              Display this help message.\n\
90 -v, --version           Display the program's version number.\n\
91 -u, --usage             Display a terse usage summary.\n\
92 \n\
93 -f, --file=FILE         Read configuration from a file.\n\
94 -d, --dump              Dump the configuration to standard output.\n\
95 \n\
96 Configuration may be supplied in one or more configuration files, or on\n\
97 the command line (or both).  If no `-f' option is present, and no\n\
98 configuration is given on the command line, the standard input stream is\n\
99 read.\n\
100 \n\
101 Configuration is free-form.  Comments begin with a `#' character and\n\
102 continue to the end of the line.  When reading from the command line,\n\
103 each argument is considered a separate line.  See the manual page for the\n\
104 complete syntax.\n\
105 ", fp);
106 }
107
108 /* --- @main@ --- *
109  *
110  * Arguments:   @int argc@ = number of command line arguments
111  *              @char *argv[]@ = vector of argument strings
112  *
113  * Returns:     ---
114  *
115  * Use:         Simple port-forwarding server.
116  */
117
118 int main(int argc, char *argv[])
119 {
120   unsigned f = 0;
121   sel_state sst;
122
123   enum {
124     f_bogus = 1,
125     f_file = 2,
126     f_dump = 4,
127     f_fork = 8
128   };
129
130   /* --- Initialize things --- */
131
132   ego(argv[0]);
133   sel = &sst;
134   sel_init(sel);
135   sub_init();
136   bres_init(sel);
137
138   /* --- Parse command line options --- */
139
140   for (;;) {
141     static struct option opts[] = {
142
143       /* --- Standard GNU help options --- */
144
145       { "help",         0,              0,      'h' },
146       { "version",      0,              0,      'v' },
147       { "usage",        0,              0,      'u' },
148
149       /* --- Other useful arguments --- */
150
151       { "file",         OPTF_ARGREQ,    0,      'f' },
152       { "dump",         0,              0,      'd' },
153       { "fork",         0,              0,      'b' },
154       { "background",   0,              0,      'b' },
155
156       /* --- Magic terminator --- */
157
158       { 0,              0,              0,      0 }
159     };
160     int i = mdwopt(argc, argv, "hvu f:db", opts, 0, 0, 0);
161
162     if (i < 0)
163       break;
164     switch (i) {
165       case 'h':
166         help(stdout);
167         exit(0);
168         break;
169       case 'v':
170         version(stdout);
171         exit(0);
172         break;
173       case 'u':
174         usage(stdout);
175         exit(0);
176         break;
177       case 'f': {
178         scan_filectx ctx;
179         FILE *fp;
180         if ((fp = fopen(optarg, "r")) == 0)
181           die(1, "couldn't open file `%s': %s", optarg, strerror(errno));
182         scan_fileinit(&ctx, fp, optarg);
183         conf_parse(&ctx);
184         fclose(fp);
185         f |= f_file;
186       } break;
187       case 'd':
188         f |= f_dump;
189         break;
190       case 'b':
191         f |= f_fork;
192         break;
193       default:
194         f |= f_bogus;
195         break;
196     }
197   }
198
199   if (f & f_bogus) {
200     usage(stderr);
201     exit(1);
202   }
203
204   /* --- Deal with the remaining arguments --- */
205
206   if (optind == argc) {
207     if (f & f_file)
208       /* Cool */;
209     else if (isatty(STDIN_FILENO)) {
210       moan("no configuration given and stdin is a terminal.");
211       moan("type `%s --help' for usage information.", QUIS);
212       exit(1);
213     } else {
214       scan_filectx ctx;
215       scan_fileinit(&ctx, stdin, "<stdin>");
216       conf_parse(&ctx);
217     }
218   } else {
219     scan_argvctx ctx;
220     scan_argvinit(&ctx, argv + optind);
221     conf_parse(&ctx);
222   }
223
224   /* --- Dump out the state --- */
225
226   if (f & f_dump) {
227     sel_file *s;
228     fputs("global acl:\n", stdout);
229     acl_dump(0, stdout);
230     for (s = sel->files; s; s = s->next)
231       listener_dump((listener *)s, stdout);
232     exit(0);
233   }
234
235   /* --- Fork into the background --- */
236
237   if (f & f_fork) {
238     pid_t kid;
239
240     kid = fork();
241     if (kid == -1)
242       die(1, "couldn't fork: %s", strerror(errno));
243     if (kid != 0)
244       _exit(0);
245
246     close(0); close(1); close(2);
247     setsid();
248
249     kid = fork();
250     if (kid != 0)
251       _exit(0);
252   }
253
254   /* --- Let rip --- */
255
256   openlog(QUIS, 0, LOG_DAEMON);
257   for (;;)
258     sel_select(sel);
259   return (0);
260 }
261
262 /*----- That's all, folks -------------------------------------------------*/