"Fossies" - the Fresh Open Source Software Archive 
Member "portfwd-0.29/src/portfwd.cc" (30 May 2005, 7258 Bytes) of package /linux/privat/old/portfwd-0.29.tar.gz:
As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style:
standard) with prefixed line numbers and
code folding option.
Alternatively you can here
view or
download the uninterpreted source code file.
1 /*
2 portfwd.c
3
4 $Id: portfwd.cc,v 1.8 2005/05/30 02:13:28 evertonm Exp $
5 */
6
7 #include <stdio.h>
8 #include <string.h>
9 #include <sys/types.h>
10 #include <sys/wait.h>
11 #include <unistd.h>
12 #include <errno.h>
13 #include <signal.h>
14 #include <syslog.h>
15 #include <stdlib.h>
16
17 #include "getopt.h"
18 #include "portfwd.h"
19 #include "util.h"
20 #include "vector.hpp"
21 #include "iterator.hpp"
22 #include "entry.hpp"
23 #include "config.h"
24 #include "fd_set.h"
25
26 extern FILE *yyin;
27 extern int yyparse();
28 extern int conf_syntax_errors;
29 extern vector<entry*> *entry_vector;
30
31 const int BUF_SZ = 8192;
32 const char * const portfwd_version = VERSION;
33
34 #ifdef HAVE_MSG_PROXY
35 int transparent_proxy = 0;
36 #endif
37
38 int on_the_fly_dns = 0;
39 int foreground = 0;
40
41 void usage(FILE *out)
42 {
43 const char *prog = get_prog_name();
44 fprintf(out, "Usage: %s [<options>]\n"
45 " -h | --help\n"
46 " -v | --version\n"
47 " -d | --debug\n"
48
49 #ifdef HAVE_MSG_PROXY
50 " -t | --transparent-proxy\n"
51 #endif
52
53 " -f | --on-the-fly-dns\n"
54 " -g | --foreground\n"
55 " -c <config-file> | --config <config-file>\n",
56 prog);
57 }
58
59 void show_version(FILE *out)
60 {
61 fprintf(out, "%s %s\n", get_prog_name(), portfwd_version);
62 }
63
64 #
65 void parse_cmdline(int argc, const char *argv[], const char **config)
66 {
67 const char * me = argv[0];
68 const char * const DEFAULT_CONFIG = PORTFWD_CONF;
69
70 int opt;
71 int option_index = 0;
72 struct option long_options[] =
73 {
74 {"help", 0, 0, 'h'},
75 {"version", 0, 0, 'v'},
76 {"debug", 0, 0, 'd'},
77
78 #ifdef HAVE_MSG_PROXY
79 {"transparent-proxy", 0, 0, 't'},
80 #endif
81
82 {"on-the-fly-dns", 0, 0, 'f'},
83 {"foreground", 0, 0, 'g'},
84 {"config", 1, 0, 'c'},
85 {0, 0, 0, 0}
86 };
87
88 *config = 0;
89
90 for (;;) {
91
92 opt = getopt_long(argc, (char ** const) argv, "hvdtfgc:", long_options, &option_index);
93 if (opt == -1)
94 break;
95
96 switch (opt) {
97 case 'h':
98 usage(stdout);
99 exit(0);
100 break;
101 case 'v':
102 show_version(stdout);
103 exit(0);
104 break;
105 case 'd':
106 ++verbose_mode;
107 break;
108
109 #ifdef HAVE_MSG_PROXY
110 case 't':
111 ++transparent_proxy;
112 break;
113 #endif
114
115 case 'f':
116 ++on_the_fly_dns;
117 break;
118 case 'g':
119 ++foreground;
120 break;
121 case 'c':
122 if (*config) {
123 fprintf(stderr, "%s: Configuration file redefinition: %s", me, optarg);
124 exit(1);
125 }
126 *config = optarg;
127 break;
128 case '?':
129 usage(stderr);
130 exit(1);
131 break;
132 default:
133 fprintf(stderr, "%s: getopt() returned unknown option: %c (%d)", me, opt, opt);
134 exit(1);
135 }
136 }
137
138 if (optind < argc) {
139 fprintf(stderr, "%s: Invalid argument: %s", me, argv[optind]);
140 exit(1);
141 }
142
143 if (!*config)
144 *config = DEFAULT_CONFIG;
145 }
146
147 void read_config(const char *cfg)
148 {
149 ONVERBOSE(syslog(LOG_INFO, "Configuration file: '%s'", cfg));
150
151 yyin = fopen(cfg, "r");
152 if (!yyin) {
153 syslog(LOG_ERR, "Can't open configuration file: '%s': %m", cfg);
154 exit(1);
155 }
156
157 yyparse();
158
159 if (conf_syntax_errors) {
160 syslog(LOG_ERR, "Syntax errors: %d", conf_syntax_errors);
161 exit(1);
162 }
163
164 if (fclose(yyin)) {
165 syslog(LOG_ERR, "Can't close configuration file: '%s'", cfg);
166 exit(1);
167 }
168 }
169
170 void do_show(vector<entry*>* entries)
171 {
172 if (!entries) {
173 syslog(LOG_ERR, "Internal error: Null entry vector (!)");
174 return;
175 }
176
177 if (!entries->get_size()) {
178 syslog(LOG_INFO, "/* Empty */");
179 return;
180 }
181
182 iterator<vector<entry*>,entry*> it(*entries);
183 for (it.start(); it.cont(); it.next())
184 it.get()->show();
185 }
186
187
188 void do_forward(vector<entry*>* entries)
189 {
190 if (!entries) {
191 syslog(LOG_ERR, "Internal error: Null entry vector (!)");
192 return;
193 }
194
195 if (!entries->get_size()) {
196 syslog(LOG_NOTICE, "Nothing to do: empty configuration file");
197 return;
198 }
199
200 iterator<vector<entry*>,entry*> it(*entries);
201 for (it.start(); it.cont(); it.next())
202 it.get()->serve();
203 }
204
205 void child_reaper(int sig)
206 {
207 int status;
208 void (*prev_handler)(int);
209
210 /* pid_t child_pid = waitpid(-1, &status, WNOHANG); */
211 pid_t child_pid = wait(&status);
212 prev_handler = signal(SIGCHLD, child_reaper);
213 if (prev_handler == SIG_ERR) {
214 syslog(LOG_ERR, "signal() failed on child_reaper re-install: %m");
215 return;
216 }
217
218 if (child_pid == -1) {
219 syslog(LOG_ERR, "Error waiting pid of child: %m");
220 return;
221 }
222
223 if (WIFEXITED(status)) {
224 syslog(LOG_WARNING, "Child with PID %d exited normally with exit status: %d", child_pid, WEXITSTATUS(status));
225 return;
226 }
227
228 if (WIFSIGNALED(status))
229 syslog(LOG_NOTICE, "Child received signal: %d", WTERMSIG(status));
230
231 syslog(LOG_ERR, "Child with PID %d exited abnormally", child_pid);
232 }
233
234 void term_handler(int sig)
235 {
236 void (*prev_handler)(int);
237
238 prev_handler = signal(SIGTERM, SIG_IGN);
239 if (prev_handler == SIG_ERR)
240 syslog(LOG_ERR, "signal() failed on term_handler de-install: %m");
241
242 if (kill(0, SIGTERM))
243 syslog(LOG_ERR, "Can't terminate children");
244
245 syslog(LOG_INFO, "SIGTERM - Program terminated");
246
247 closelog();
248
249 exit(0);
250 }
251
252 int main(int argc, const char *argv[])
253 {
254 set_prog_name("portfwd");
255
256 /*
257 * Read arguments from command line.
258 */
259 const char *config;
260 parse_cmdline(argc, argv, &config);
261
262 /*
263 * Close file descriptors.
264 */
265 close_fds(0);
266
267 /*
268 * Connect standard IO to /dev/null.
269 */
270 std_to_null();
271
272 /*
273 * Open interface to syslog.
274 */
275 openlog(get_prog_name(), LOG_CONS | LOG_PID, LOG_DAEMON);
276 syslog(LOG_INFO, "%s %s started", get_prog_name(), portfwd_version);
277
278 ONVERBOSE(syslog(LOG_DEBUG, "Verbose mode: %d", verbose_mode));
279
280 #ifdef HAVE_MSG_PROXY
281 ONVERBOSE(syslog(LOG_INFO, "Transparent proxy mode: %s (%d)", transparent_proxy ? "on" : "off", transparent_proxy));
282 #else
283 ONVERBOSE(syslog(LOG_INFO, "Transparent proxy mode: disabled on compile time"));
284 #endif
285
286 ONVERBOSE(syslog(LOG_INFO, "On the fly DNS mode: %s (%d)", on_the_fly_dns ? "on" : "off", on_the_fly_dns));
287
288 ONVERBOSE(syslog(LOG_INFO, "Foreground: %s (%d)", foreground ? "on" : "off", foreground));
289
290 /*
291 * Go to background.
292 */
293 if (!foreground) {
294 int dmz = daemonize();
295 if (dmz) {
296 syslog(LOG_ERR, "daemonize() failed: %d", dmz);
297 exit(1);
298 }
299 }
300
301 /*
302 * Connect standard IO to /dev/null.
303 */
304 /* std_to_null(); */
305
306 solve_protonumbers();
307
308 /*
309 * Load configuration.
310 */
311 read_config(config);
312 ONVERBOSE(do_show(entry_vector));
313
314 /*
315 * Go to root (/) directory to prevent disturbing umount.
316 */
317 cd_root();
318
319 /*
320 * Install handler to take care of children.
321 */
322 void (*prev_handler)(int);
323 prev_handler = signal(SIGCHLD, child_reaper);
324 if (prev_handler == SIG_ERR) {
325 syslog(LOG_ERR, "signal() failed on child_reaper install: %m");
326 exit(1);
327 }
328
329 /*
330 * Spawn forwarders.
331 */
332 do_forward(entry_vector);
333
334 /*
335 * Install handler for TERM signal.
336 */
337 prev_handler = signal(SIGTERM, term_handler);
338 if (prev_handler == SIG_ERR) {
339 syslog(LOG_ERR, "signal() failed on term_handler install: %m");
340 exit(1);
341 }
342
343 /*
344 * Wait forever.
345 */
346 for (;;)
347 sleep(3600);
348
349 return 0;
350 }