/* -*-c-*-
*
- * $Id: exec.c,v 1.3 2000/07/01 11:28:52 mdw Exp $
+ * $Id: exec.c,v 1.4 2001/02/03 20:30:03 mdw Exp $
*
* Source and target for executable programs
*
/*----- Revision history --------------------------------------------------*
*
* $Log: exec.c,v $
+ * Revision 1.4 2001/02/03 20:30:03 mdw
+ * Support re-reading config files on SIGHUP.
+ *
* Revision 1.3 2000/07/01 11:28:52 mdw
* Use new mLib selbuf features.
*
struct xept *next, *prev;
pid_t kid;
endpt *f;
- const char *desc;
+ char *desc;
int st;
xargs *xa;
xopts *xo;
else
xept_list = xe->next;
+ free(xe->desc);
if (xe->f)
xe->f->ops->close(xe->f);
x_tidy(xe->xa, xe->xo);
xe->xo = x->xo; xe->xo->ref++;
xe->kid = -1;
xe->f = 0;
- xe->desc = desc;
+ xe->desc = xstrdup(desc);
return (&xe->e);
}
static void xsource_destroy(source *s)
{
xsource *xs = (xsource *)s;
+ free(xs->s.desc);
exec_destroy(&xs->x);
DESTROY(xs);
}
static void xtarget_destroy(target *t)
{
xtarget *xt = (xtarget *)t;
+ free(xt->t.desc);
exec_destroy(&xt->x);
DESTROY(xt);
}
/* -*-c-*-
*
- * $Id: file.c,v 1.3 1999/12/22 15:43:47 mdw Exp $
+ * $Id: file.c,v 1.4 2001/02/03 20:30:03 mdw Exp $
*
* File source and target
*
/*----- Revision history --------------------------------------------------*
*
* $Log: file.c,v $
+ * Revision 1.4 2001/02/03 20:30:03 mdw
+ * Support re-reading config files on SIGHUP.
+ *
* Revision 1.3 1999/12/22 15:43:47 mdw
* Fix log messages.
*
static void fsource_destroy(source *s)
{
fsource *fs = (fsource *)s;
-
- /* free(fs->s.desc); */
+ free(fs->s.desc);
file_destroy(&fs->f);
DESTROY(fs);
}
{
ftarget *ft = (ftarget *)t;
file_destroy(&ft->f);
- /* free(ft->t.desc); */
+ free(ft->t.desc);
DESTROY(ft);
}
.\" -*-nroff-*-
.\"
-.\" $Id: fw.1,v 1.9 2000/03/23 00:37:33 mdw Exp $
+.\" $Id: fw.1,v 1.10 2001/02/03 20:30:03 mdw Exp $
.\"
.\" Manual page for fw
.\"
.\" ---- Revision history ---------------------------------------------------
.\"
.\" $Log: fw.1,v $
+.\" Revision 1.10 2001/02/03 20:30:03 mdw
+.\" Support re-reading config files on SIGHUP.
+.\"
.\" Revision 1.9 2000/03/23 00:37:33 mdw
.\" Add option to change user and group after initialization. Naughtily
.\" reassign short equivalents of --grammar and --options.
.RB ` [ '
and
.RB ` ; ',
-require escaping by the shell, they are strictly optional in the grammar
-and can be omitted in quick hacks at the shell prompt.
+require escaping by the shell, they are mostly optional in the grammar
+and can tend to be omitted in quick hacks at the shell prompt.
.TP
.I "whitespace characters"
Whitespace characters separate words but are otherwise ignored. All
Sets the root directory for the program, using the
.BR chroot (2)
system call. You must be the superuser for this option to work. The
-default is not to set a root directory. The synonyms
-.BR cd ,
-.B chdir
-and
-.B cwd
-are accepted in place of
-.B dir .
+default is not to set a root directory. The synonym
+.B chroot
+is accepted in place of
+.BR root .
.OE
.OS "Exec options"
.B exec.user
Sockets are removed if
.B fw
exits normally (which it will do if it runs out of sources or
-connections, or if killed by SIGINT or SIGTERM).
+connections, or if
+.B fw
+shuts down in a clean way).
.SH "EXAMPLES"
To forward the local port 25 to a main mail server:
.VS
.VE
.
.\"--------------------------------------------------------------------------
+.SH "SIGNAL HANDLING"
+.
+The
+.B fw
+program responds to various signals when it's running. If it receives
+.B SIGTERM
+or
+.BR SIGINT ,
+.B fw
+performs a
+.I graceful
+shutdown: it removes all of its sources, and will exit when no more
+connections are running. (Note that if the disposition
+.B SIGINT
+was to ignore it,
+.B fw
+does not re-enable the signal. You'll have to send
+.B SIGTERM
+in that case.) If
+.B fw
+receives
+.BR SIGQUIT ,
+it performs an
+.I abrupt
+shutdown: it removes all sources and extant connections and closes down
+more-or-less immediately.
+.PP
+Finally, if any configuration files (other than standard input) were
+provided to
+.B fw
+on its command line using the
+.B \-f
+option, a
+.B SIGHUP
+signal may be sent to instruct
+.B fw
+to reload its configuration. Any existing connections are allowed to
+run their course. If no such configuration files are available,
+.B fw
+just logs a message about the signal and continues.
+.PP
+.
+.\"--------------------------------------------------------------------------
.SH "GRAMMAR SUMMARY"
.
.SS "Basic syntax"
/* -*-c-*-
*
- * $Id: fw.c,v 1.9 2001/01/20 11:55:17 mdw Exp $
+ * $Id: fw.c,v 1.10 2001/02/03 20:30:03 mdw Exp $
*
* Port forwarding thingy
*
/*----- Revision history --------------------------------------------------*
*
* $Log: fw.c,v $
+ * Revision 1.10 2001/02/03 20:30:03 mdw
+ * Support re-reading config files on SIGHUP.
+ *
* Revision 1.9 2001/01/20 11:55:17 mdw
* Handle select errors more robustly.
*
#include "config.h"
+#include <assert.h>
#include <ctype.h>
#include <errno.h>
#include <signal.h>
/*----- Static variables --------------------------------------------------*/
+typedef struct conffile {
+ struct conffile *next;
+ char *name;
+} conffile;
+
static unsigned flags = 0; /* Global state flags */
static unsigned active = 0; /* Number of active things */
+static conffile *conffiles = 0; /* List of configuration files */
#define FW_SYSLOG 1u
#define FW_QUIET 2u
static void fw_tidy(int n, void *p)
{
- const char *sn = "unexpected signal (bug!)";
- if (n == SIGTERM)
- sn = "SIGTERM";
- else if (n == SIGINT)
- sn = "SIGINT";
-
- fw_log(-1, "closing down on %s", sn);
- fw_exit();
+ const char *sn = 0;
+ switch (n) {
+ case SIGTERM: sn = "SIGTERM"; break;
+ case SIGINT: sn = "SIGINT"; break;
+ default: abort();
+ }
+
+ fw_log(-1, "closing down gracefully on %s", sn);
+ source_killall();
+}
+
+/* --- @fw_die@ --- *
+ *
+ * Arguments: @int n@ = signal number
+ * @void *p@ = an uninteresting argument
+ *
+ * Returns: ---
+ *
+ * Use: Handles various signals and causes an abrupt shutdown.
+ */
+
+static void fw_die(int n, void *p)
+{
+ const char *sn = 0;
+ switch (n) {
+ case SIGQUIT: sn = "SIGQUIT"; break;
+ default: abort();
+ }
+
+ fw_log(-1, "closing down abruptly on %s", sn);
+ source_killall();
+ endpt_killall();
+}
+
+/* --- @fw_reload@ --- *
+ *
+ * Arguments: @int n@ = a signal number
+ * @void *p@ = an uninteresting argument
+ *
+ * Returns: ---
+ *
+ * Use: Handles a hangup signal by re-reading configuration files.
+ */
+
+static void fw_reload(int n, void *p)
+{
+ FILE *fp;
+ scanner sc;
+ conffile *cf;
+
+ assert(n == SIGHUP);
+ if (!conffiles) {
+ fw_log(-1, "no configuration files to reload: ignoring SIGHUP");
+ return;
+ }
+ fw_log(-1, "reloading configuration files...");
+ source_killall();
+ scan_create(&sc);
+ for (cf = conffiles; cf; cf = cf->next) {
+ if ((fp = fopen(cf->name, "r")) == 0)
+ fw_log(-1, "error loading `%s': %s", cf->name, strerror(errno));
+ else
+ scan_add(&sc, scan_file(fp, cf->name, 0));
+ }
+ conf_parse(&sc);
+ fw_log(-1, "... reload completed OK");
}
/* --- Standard GNU help options --- */
{
unsigned f = 0;
sel_state sst;
- sig s_term, s_int;
+ sig s_term, s_quit, s_int, s_hup;
scanner sc;
uid_t drop = -1;
gid_t dropg = -1;
+ conffile *cf, **cff = &conffiles;
- enum {
- f_bogus = 1,
- f_file = 2,
- f_syslog = 4,
- f_fork = 8
- };
+#define f_bogus 1u
+#define f_file 2u
+#define f_syslog 4u
+#define f_fork 8u
/* --- Initialize things --- */
fattr_init(&fattr_global);
scan_create(&sc);
- /* --- Set up some signal handlers --- *
- *
- * Don't enable @SIGINT@ if the caller already disabled it.
- */
-
- {
- struct sigaction sa;
-
- sig_add(&s_term, SIGTERM, fw_tidy, 0);
- sigaction(SIGINT, 0, &sa);
- if (sa.sa_handler != SIG_IGN)
- sig_add(&s_int, SIGINT, fw_tidy, 0);
- }
-
atexit(fw_exit);
/* --- Parse command line options --- */
FILE *fp;
if ((fp = fopen(optarg, "r")) == 0)
die(1, "couldn't open file `%s': %s", optarg, strerror(errno));
+ cf = CREATE(conffile);
+ cf->name = optarg;
+ *cff = cf;
+ cff = &cf->next;
scan_add(&sc, scan_file(fp, optarg, 0));
}
f |= f_file;
usage(stderr);
exit(1);
}
+ *cff = 0;
/* --- Deal with the remaining arguments --- */
conf_parse(&sc);
+ /* --- Set up some signal handlers --- *
+ *
+ * Don't enable @SIGINT@ if the caller already disabled it.
+ */
+
+ {
+ struct sigaction sa;
+
+ sig_add(&s_term, SIGTERM, fw_tidy, 0);
+ sig_add(&s_quit, SIGQUIT, fw_die, 0);
+ sigaction(SIGINT, 0, &sa);
+ if (sa.sa_handler != SIG_IGN)
+ sig_add(&s_int, SIGINT, fw_tidy, 0);
+ sig_add(&s_hup, SIGHUP, fw_reload, 0);
+ }
+
/* --- Drop privileges --- */
#ifdef HAVE_SETGROUPS
while (active) {
if (!sel_select(sel))
selerr = 0;
- else {
+ else if (errno != EINTR && errno != EAGAIN) {
fw_log(-1, "error from select: %s", strerror(errno));
selerr++;
if (selerr > 8) {
/* -*-c-*-
*
- * $Id: scan.c,v 1.3 2000/08/01 17:58:10 mdw Exp $
+ * $Id: scan.c,v 1.4 2001/02/03 20:30:03 mdw Exp $
*
* Character scanners
*
/*----- Revision history --------------------------------------------------*
*
* $Log: scan.c,v $
+ * Revision 1.4 2001/02/03 20:30:03 mdw
+ * Support re-reading config files on SIGHUP.
+ *
* Revision 1.3 2000/08/01 17:58:10 mdw
* Fix subtleties with <ctype.h> functions.
*
scansrc *scan_file(FILE *fp, char *name, unsigned f)
{
- fscan *fs = CREATE(fs);
+ fscan *fs = CREATE(fscan);
fs->ss.ops = &fscan_ops;
fs->ss.src = name;
fs->ss.line = 1;
/* -*-c-*-
*
- * $Id: socket.c,v 1.5 2000/03/23 23:20:42 mdw Exp $
+ * $Id: socket.c,v 1.6 2001/02/03 20:30:03 mdw Exp $
*
* Socket source and target definitions
*
/*----- Revision history --------------------------------------------------*
*
* $Log: socket.c,v $
+ * Revision 1.6 2001/02/03 20:30:03 mdw
+ * Support re-reading config files on SIGHUP.
+ *
* Revision 1.5 2000/03/23 23:20:42 mdw
* Remove listener even if connection option isn't SOCKOPT_LIMITED.
*
typedef struct stept {
endpt e;
conn c;
- const char *desc;
+ char *desc;
} stept;
/* --- Socket source endpoint --- */
REFFD_DEC(ee->e.out);
}
+ free(ee->desc);
fw_dec();
DESTROY(ee);
}
ss->a->ops->freeopts(ss->ao);
else
DESTROY(ss->ao);
- /* free(ss->s.desc); */
+ free(ss->s.desc);
ss->a->ops->destroy(ss->a);
ss->t->ops->destroy(ss->t);
source_remove(&ss->s);
e->e.other = 0;
e->e.f = EPF_FILE | SKF_CONN;
e->e.t = 0;
- e->desc = desc;
+ e->desc = xstrdup(desc);
/* --- Pay attention --- *
*
{
starget *st = (starget *)t;
st->a->ops->destroy(st->a);
- /* free(st->t.desc); */
+ free(st->t.desc);
DESTROY(st);
}