Initial revision
authormdw <mdw>
Thu, 1 Jul 1999 08:56:23 +0000 (08:56 +0000)
committermdw <mdw>
Thu, 1 Jul 1999 08:56:23 +0000 (08:56 +0000)
27 files changed:
.cvsignore [new file with mode: 0644]
.links [new file with mode: 0644]
.skelrc [new file with mode: 0644]
Makefile.am [new file with mode: 0644]
acconfig.h [new file with mode: 0644]
acl.c [new file with mode: 0644]
acl.h [new file with mode: 0644]
bres.c [new file with mode: 0644]
bres.h [new file with mode: 0644]
chan.c [new file with mode: 0644]
chan.h [new file with mode: 0644]
conf.c [new file with mode: 0644]
conf.h [new file with mode: 0644]
configure.in [new file with mode: 0644]
forward.c [new file with mode: 0644]
forward.h [new file with mode: 0644]
fw.c [new file with mode: 0644]
fw.h [new file with mode: 0644]
ident.c [new file with mode: 0644]
ident.h [new file with mode: 0644]
identify.c [new file with mode: 0644]
identify.h [new file with mode: 0644]
listener.c [new file with mode: 0644]
listener.h [new file with mode: 0644]
scan.c [new file with mode: 0644]
scan.h [new file with mode: 0644]
setup [new file with mode: 0755]

diff --git a/.cvsignore b/.cvsignore
new file mode 100644 (file)
index 0000000..19a3c54
--- /dev/null
@@ -0,0 +1,7 @@
+Makefile.in
+Makefile
+aclocal.m4
+build
+config.h.in
+configure
+stamp-h.in
diff --git a/.links b/.links
new file mode 100644 (file)
index 0000000..b3f8cad
--- /dev/null
+++ b/.links
@@ -0,0 +1,4 @@
+COPYING
+install-sh
+mkinstalldirs
+missing
diff --git a/.skelrc b/.skelrc
new file mode 100644 (file)
index 0000000..225a897
--- /dev/null
+++ b/.skelrc
@@ -0,0 +1,8 @@
+;;; -*-emacs-lisp-*-
+
+(setq skel-alist
+      (append
+       '((author . "Mark Wooding")
+        (program . "`fw'")
+        (full-title . "the `fw' port forwarder"))
+       skel-alist))
diff --git a/Makefile.am b/Makefile.am
new file mode 100644 (file)
index 0000000..b41ffe7
--- /dev/null
@@ -0,0 +1,49 @@
+## -*-makefile-*-
+##
+## $Id: Makefile.am,v 1.1 1999/07/01 08:56:23 mdw Exp $
+##
+## Makefile for fw
+##
+## (c) 1999 Mark Wooding
+##
+
+##----- Licensing notice ----------------------------------------------------
+##
+## This file is part of the `fw' port forwarder.
+##
+## `fw' is free software; you can redistribute it and/or modify
+## it under the terms of the GNU General Public License as published by
+## the Free Software Foundation; either version 2 of the License, or
+## (at your option) any later version.
+## 
+## `fw' is distributed in the hope that it will be useful,
+## but WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+## GNU General Public License for more details.
+## 
+## You should have received a copy of the GNU General Public License
+## along with `fw'; if not, write to the Free Software Foundation,
+## Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+##----- Revision history ----------------------------------------------------
+##
+## $Log: Makefile.am,v $
+## Revision 1.1  1999/07/01 08:56:23  mdw
+## Initial revision
+##
+
+AUTOMAKE_OPTIONS = foreign
+
+SUBDIRS = mLib
+
+bin_PROGRAMS = fw
+LDADD = mLib/libmLib.a
+INCLUDES = -I$(srcdir)/mLib
+
+fw_SOURCES = \
+       acl.c bres.c chan.c conf.c forward.c fw.c \
+       ident.c identify.c listener.c scan.c \
+       acl.h bres.h chan.h conf.h forward.h fw.h \
+       ident.h identify.h listener.h scan.h
+
+##----- That's all, folks ---------------------------------------------------
diff --git a/acconfig.h b/acconfig.h
new file mode 100644 (file)
index 0000000..7146729
--- /dev/null
@@ -0,0 +1,61 @@
+/* -*-c-*-
+ *
+ * $Id: acconfig.h,v 1.1 1999/07/01 08:56:23 mdw Exp $
+ *
+ * Configuration header for fw
+ *
+ * (c) 1999 Mark Wooding
+ */
+
+/*----- Licensing notice --------------------------------------------------* 
+ *
+ * This file is part of the `fw' port forwarder.
+ *
+ * `fw' is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * `fw' is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with `fw'; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*----- Revision history --------------------------------------------------* 
+ *
+ * $Log: acconfig.h,v $
+ * Revision 1.1  1999/07/01 08:56:23  mdw
+ * Initial revision
+ *
+ */
+
+#ifndef ACCONFIG_H
+#define ACCONFIG_H
+
+#ifdef __cplusplus
+  extern "C" {
+#endif
+
+/*----- Configuration macros ----------------------------------------------*/
+@TOP@
+
+/* Package name.  */
+#define PACKAGE "fw"
+
+/* Package version number.  */
+#define VERSION "1.0.0"
+
+@BOTTOM@
+
+/*----- That's all, folks -------------------------------------------------*/
+
+#ifdef __cplusplus
+  }
+#endif
+
+#endif
diff --git a/acl.c b/acl.c
new file mode 100644 (file)
index 0000000..4dadc24
--- /dev/null
+++ b/acl.c
@@ -0,0 +1,138 @@
+/* -*-c-*-
+ *
+ * $Id: acl.c,v 1.1 1999/07/01 08:56:23 mdw Exp $
+ *
+ * Access control list handling
+ *
+ * (c) 1999 Mark Wooding
+ */
+
+/*----- Licensing notice --------------------------------------------------* 
+ *
+ * This file is part of the `fw' port forwarder.
+ *
+ * `fw' is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * `fw' is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with `fw'; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*----- Revision history --------------------------------------------------* 
+ *
+ * $Log: acl.c,v $
+ * Revision 1.1  1999/07/01 08:56:23  mdw
+ * Initial revision
+ *
+ */
+
+/*----- Header files ------------------------------------------------------*/
+
+#include "config.h"
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+
+#include <mLib/sub.h>
+
+#include "acl.h"
+
+/*----- Static variables --------------------------------------------------*/
+
+static acl_entry *global = 0;
+static acl_entry **gtail = &global;
+
+/*----- Main code ---------------------------------------------------------*/
+
+/* --- @acl_check@ --- *
+ *
+ * Arguments:  @acl_entry *a@ = pointer to ACL to check against
+ *             @struct in_addr addr@ = address to check
+ *
+ * Returns:    Nonzero if allowed.
+ *
+ * Use:                Checks an address against an ACL.
+ */
+
+int acl_check(acl_entry *a, struct in_addr addr)
+{
+  int act = ACL_ALLOW;
+  int i;
+
+  for (i = 0; i < 2; i++) {
+    for (; a; a = a->next) {
+      if ((addr.s_addr & a->mask.s_addr) == a->addr.s_addr)
+       return (a->act & ACL_PERM);
+      act = (a->act & ACL_PERM) ^ 1;
+    }
+    a = global;
+  }
+
+  return (act);
+}
+
+/* --- @acl_dump@ --- *
+ *
+ * Arguments:  @acl_entry *a@ = pointer to ACL to dump
+ *             @FILE *fp@ = pointer to stream to dump on
+ *
+ * Returns:    ---
+ *
+ * Use:                Dumps an access control list to an output stream.
+ */
+
+void acl_dump(acl_entry *a, FILE *fp)
+{
+  if (!a)
+    a = global;
+  for (; a; a = a->next) {
+    fprintf(fp, "  %s from ",
+           (a->act & ACL_PERM) == ACL_ALLOW ? "allow" : "deny");
+    fputs(inet_ntoa(a->addr), fp);
+    fputc('/', fp);
+    fputs(inet_ntoa(a->mask), fp);
+    fputc('\n', fp);
+  }
+}
+
+/* --- @acl_add@ --- *
+ *
+ * Arguments:  @acl_entry ***a@ = address of pointer to list tail
+ *             @unsigned act@ = what to do with matching addresses
+ *             @struct in_addr addr, mask@ = address and mask to match
+ *
+ * Returns:    ---
+ *
+ * Use:                Adds an entry to the end of an access control list.
+ */
+
+void acl_add(acl_entry ***a, unsigned act,
+            struct in_addr addr, struct in_addr mask)
+{
+  acl_entry *aa = CREATE(acl_entry);
+  aa->act = act;
+  aa->addr.s_addr = addr.s_addr & mask.s_addr;
+  aa->mask = mask;
+  aa->next = 0;
+  if (!a)
+    a = &gtail;
+  **a = aa;
+  *a = &aa->next;
+}
+
+/*----- That's all, folks -------------------------------------------------*/
diff --git a/acl.h b/acl.h
new file mode 100644 (file)
index 0000000..8b8588c
--- /dev/null
+++ b/acl.h
@@ -0,0 +1,111 @@
+/* -*-c-*-
+ *
+ * $Id: acl.h,v 1.1 1999/07/01 08:56:23 mdw Exp $
+ *
+ * Access control list handling
+ *
+ * (c) 1999 Mark Wooding
+ */
+
+/*----- Licensing notice --------------------------------------------------* 
+ *
+ * This file is part of the `fw' port forwarder.
+ *
+ * `fw' is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * `fw' is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with `fw'; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*----- Revision history --------------------------------------------------* 
+ *
+ * $Log: acl.h,v $
+ * Revision 1.1  1999/07/01 08:56:23  mdw
+ * Initial revision
+ *
+ */
+
+#ifndef ACL_H
+#define ACL_H
+
+#ifdef __cplusplus
+  extern "C" {
+#endif
+
+/*----- Header files ------------------------------------------------------*/
+
+#include <stdio.h>
+
+#include <sys/socket.h>
+#include <netinet/in.h>
+
+/*----- Data structures ---------------------------------------------------*/
+
+/* --- An access control entry --- */
+
+typedef struct acl_entry {
+  struct acl_entry *next;              /* Next entry in the list */
+  unsigned act;                                /* What to do with matching hosts */
+  struct in_addr addr, mask;           /* Address and netmask */
+} acl_entry;
+
+#define ACL_DENY 0                     /* Deny access to matching hosts */
+#define ACL_ALLOW 1                    /* Allow access to matching hosts */
+#define ACL_PERM 1u                    /* Bit mask for permission bit */
+
+/*----- Functions provided ------------------------------------------------*/
+
+/* --- @acl_check@ --- *
+ *
+ * Arguments:  @acl_entry *a@ = pointer to ACL to check against
+ *             @struct in_addr addr@ = address to check
+ *
+ * Returns:    Nonzero if allowed.
+ *
+ * Use:                Checks an address against an ACL.
+ */
+
+extern int acl_check(acl_entry */*a*/, struct in_addr /*addr*/);
+
+/* --- @acl_dump@ --- *
+ *
+ * Arguments:  @acl_entry *a@ = pointer to ACL to dump
+ *             @FILE *fp@ = pointer to stream to dump on
+ *
+ * Returns:    ---
+ *
+ * Use:                Dumps an access control list to an output stream.
+ */
+
+extern void acl_dump(acl_entry */*a*/, FILE */*fp*/);
+
+/* --- @acl_add@ --- *
+ *
+ * Arguments:  @acl_entry ***a@ = address of pointer to list tail
+ *             @unsigned act@ = what to do with matching addresses
+ *             @struct in_addr addr, mask@ = address and mask to match
+ *
+ * Returns:    ---
+ *
+ * Use:                Adds an entry to the end of an access control list.
+ */
+
+extern void acl_add(acl_entry ***/*a*/, unsigned /*act*/,
+                   struct in_addr /*addr*/, struct in_addr /*mask*/);
+
+/*----- That's all, folks -------------------------------------------------*/
+
+#ifdef __cplusplus
+  }
+#endif
+
+#endif
diff --git a/bres.c b/bres.c
new file mode 100644 (file)
index 0000000..d04d15f
--- /dev/null
+++ b/bres.c
@@ -0,0 +1,439 @@
+/* -*-c-*-
+ *
+ * $Id: bres.c,v 1.1 1999/07/01 08:56:23 mdw Exp $
+ *
+ * Background reverse name resolution
+ *
+ * (c) 1999 Mark Wooding
+ */
+
+/*----- Licensing notice --------------------------------------------------* 
+ *
+ * This file is part of the `fw' port forwarder.
+ *
+ * `fw' is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * `fw' is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with `fw'; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*----- Revision history --------------------------------------------------* 
+ *
+ * $Log: bres.c,v $
+ * Revision 1.1  1999/07/01 08:56:23  mdw
+ * Initial revision
+ *
+ */
+
+/*----- Header files ------------------------------------------------------*/
+
+#include <errno.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <sys/types.h>
+#include <sys/time.h>
+#include <unistd.h>
+#include <sys/wait.h>
+
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+
+#include <mLib/report.h>
+#include <mLib/sel.h>
+#include <mLib/selbuf.h>
+
+#include "bres.h"
+
+/*----- Magic numbers -----------------------------------------------------*/
+
+#define BRES_MAX 5                     /* Maximum number of resolvers */
+#define BRES_IDLE 60                   /* Lifetime of an idle resolver */
+
+/*----- Static variables --------------------------------------------------*/
+
+static bres_server servers[BRES_MAX];  /* Statically allocated servers */
+
+#define FREE ((bres_server *)&freelist)
+static struct { bres_server *next, *prev; } freelist = { FREE, FREE };
+
+#define QUEUE ((bres_client *)&queue)
+static struct { bres_client *next, *prev; } queue = { QUEUE, QUEUE };
+
+static sel_state *sel;
+
+/*----- Main code ---------------------------------------------------------*/
+
+/* --- @zap@ --- *
+ *
+ * Arguments:  @bres_server *rs@ = pointer to server block
+ *
+ * Returns:    ---
+ *
+ * Use:                Kills a server process, reaps the losing child and makes
+ *             things generally clean again.
+ */
+
+static void zap(bres_server *rs)
+{
+  /* --- Close the pipes, kill the child, and reap it --- */
+
+  if (rs->kid != -1) {
+    selbuf_disable(&rs->b);
+    close(rs->fd);
+    close(rs->b.reader.fd);
+    kill(rs->kid, SIGTERM);
+    waitpid(rs->kid, 0, 0);
+    rs->kid = -1;
+  }
+
+  /* --- Move the server to the back of the list --- */
+
+  rs->next->prev = rs->prev;
+  rs->prev->next = rs->next;
+  rs->next = FREE;
+  rs->prev = FREE->prev;
+  FREE->prev->next = rs;
+  FREE->prev = rs;
+}
+
+/* --- @bres_abort@ --- *
+ *
+ * Arguments:  @bres_client *rc@ = pointer to client block
+ *
+ * Returns:    ---
+ *
+ * Use:                Removes a queued job.
+ */
+
+void bres_abort(bres_client *rc)
+{
+  if (rc->rs) {
+    zap(rc->rs);
+    rc->rs = 0;
+  } else {
+    rc->next->prev = rc->prev;
+    rc->prev->next = rc->next;
+  }
+}
+
+/* --- @child@ --- *
+ *
+ * Arguments:  @int rfd@ = output file descriptor for resolved hostnames
+ *             @int cfd@ = input file descriptor for raw addresses
+ *
+ * Returns:    Never.
+ *
+ * Use:                Asynchronous name resolving process.
+ */
+
+static void child(int rfd, int cfd)
+{
+  struct in_addr addr;
+  FILE *fp = fdopen(rfd, "w");
+
+  {
+    int i;
+    int maxfd = sysconf(_SC_OPEN_MAX);
+
+    for (i = 0; i < maxfd; i++) {
+      if (i != rfd && i != cfd)
+       close(i);
+    }
+  }
+
+  for (;;) {
+    int r = read(cfd, &addr, sizeof(addr));
+    struct hostent *h;
+    char *p;
+
+    if (r <= 0)
+      break;
+    else if (r != sizeof(addr))
+      continue;
+
+    h = gethostbyaddr((char *)&addr, sizeof(addr), AF_INET);
+    if (h)
+      p = h->h_name;
+    else
+      p = inet_ntoa(addr);
+    fprintf(fp, "%s\n", p);
+    fflush(fp);
+  }
+  _exit(0);
+}
+
+/* --- @idle@ --- *
+ *
+ * Arguments:  @struct timeval *tv@ = pointer to the current time
+ *             @void *vp@ = pointer to a server block
+ *
+ * Returns:    ---
+ *
+ * Use:                Kills off a child which has been idle for too long.
+ */
+
+static void idle(struct timeval *tv, void *vp)
+{
+  bres_server *rs = vp;
+  zap(rs);
+}
+
+/* --- @answer@ --- *
+ *
+ * Arguments:  @char *p@ = pointer to string read
+ *             @void *vp@ = pointer to server block
+ *
+ * Returns:    ---
+ *
+ * Use:                Retrieves an answer from a name resolver process.
+ */
+
+static void attach(bres_client */*rc*/);
+
+static void answer(char *p, void *vp)
+{
+  bres_server *rs = vp;
+  bres_client *rc = rs->rc;
+
+  /* --- Report the result to my client --- */
+
+  if (rc)
+    rc->func(p, rc->p);
+  if (!p)
+    zap(rs);
+  if (!rc)
+    return;
+
+  /* --- Wrap up the various structures --- */
+
+  rs->rc = 0;
+  rc->rs = 0;
+  rs->next = FREE->next;
+  rs->prev = FREE;
+  FREE->next->prev = rs;
+  FREE->next = rs;
+
+  /* --- Tie a timer onto the server block --- */
+
+  {
+    struct timeval tv;
+
+    gettimeofday(&tv, 0);
+    tv.tv_sec += BRES_IDLE;
+    sel_addtimer(sel, &rs->t, &tv, idle, rs);
+  }
+
+  /* --- If there are any clients waiting, attach one --- */
+
+  if (QUEUE->next != QUEUE) {
+    rc = QUEUE->next;
+    QUEUE->next = rc->next;
+    rc->next->prev = QUEUE;
+    attach(rc);
+  }
+}
+
+/* --- @start@ --- *
+ *
+ * Arguments:  @bres_server *rs@ = pointer to a server block
+ *
+ * Returns:    Zero if OK, nonzero if something failed.
+ *
+ * Use:                Starts up a child resolver process.
+ */
+
+static int start(bres_server *rs)
+{
+  int rfd[2], cfd[2];
+  pid_t kid;
+
+  /* --- Make the pipes --- */
+
+  if (pipe(rfd))
+    goto fail_0;
+  if (pipe(cfd))
+    goto fail_1;
+
+  /* --- Start up the child process --- */
+
+  if ((kid = fork()) < 0)
+    goto fail_2;
+  if (kid == 0) {
+    close(cfd[1]);
+    close(rfd[0]);
+    child(rfd[1], cfd[0]);
+    _exit(1);
+  }
+
+  /* --- Fix up everything in the server block --- */
+
+  close(cfd[0]);
+  close(rfd[1]);
+  rs->fd = cfd[1];
+  selbuf_init(&rs->b, sel, rfd[0], answer, rs);
+  rs->kid = kid;
+  return (0);
+
+  /* --- Fix up after errors --- */
+
+fail_2:
+  close(cfd[0]);
+  close(cfd[1]);
+fail_1:
+  close(rfd[0]);
+  close(rfd[1]);
+fail_0:
+  return (-1);
+}
+
+/* --- @attach@ --- *
+ *
+ * Arguments:  @bres_client *rc@ = pointer to a client block
+ *
+ * Returns:    ---
+ *
+ * Use:                Attaches a client to a spare server (which is assumed to
+ *             exist).
+ */
+
+static void attach(bres_client *rc)
+{
+  bres_server *rs;
+  int lose = 0;
+
+  /* --- Fix up the server ready for the job --- *
+   *
+   * If the server has a process, remove its timer.  Otherwise, fork off a
+   * new resolver process.  This is also where I go if I find that the child
+   * resolver process has lost while I wasn't looking.  Only one attempt at
+   * forking is performed.
+   */
+
+again:
+  rs = FREE->next;
+  if (rs->kid != -1)
+    sel_rmtimer(&rs->t);
+  else {
+    if (lose || start(rs))
+      goto lost;
+    lose = 1;
+  }
+
+  /* --- Submit the job to the resolver --- */
+
+  {
+    struct sigaction sa, osa;
+    int e;
+
+    /* --- Ignore @SIGPIPE@ for now --- *
+     *
+     * This way I can trap @EPIPE@ and reap a losing child, if there was one.
+     */
+
+    sa.sa_handler = SIG_IGN;
+    sa.sa_flags = 0;
+    sigemptyset(&sa.sa_mask);
+    sigaction(SIGPIPE, &sa, &osa);
+
+    /* --- Write the new job to the child --- */
+
+    e = 0;
+    if (write(rs->fd, &rc->addr, sizeof(rc->addr)) < 0)
+      e = errno;
+    sigaction(SIGPIPE, &osa, 0);
+
+    /* --- Sort out various errors --- */
+
+    if (e == EPIPE) {
+      zap(rs);
+      goto again;
+    } else if (e)
+      goto lost;
+  }
+
+  /* --- Fiddle with lists so that everything's OK --- */
+
+  rs->next->prev = FREE;
+  FREE->next = rs->next;
+  rs->next = rs->prev = rs;
+  rs->rc = rc;
+  rc->rs = rs;
+  return;
+
+lost:
+  rc->func(0, rc->p);
+}
+
+/* --- @bres_resolve@ --- *
+ *
+ * Arguments:  @bres_client *rc@ = pointer to client block
+ *             @struct in_addr addr@ = address to resolve
+ *             @void (*func)(const char *host, void *p)@ = handler function
+ *             @void *p@ = argument for handler function
+ *
+ * Returns:    ---
+ *
+ * Use:                Adds a resolver job to the queue.  The job will be processed
+ *             when there's a spare resolver process to deal with it.
+ */
+
+void bres_resolve(bres_client *rc, struct in_addr addr,
+                 void (*func)(const char */*host*/, void */*p*/), void *p)
+{
+  /* --- Fill in the structure --- */
+
+  rc->addr = addr;
+  rc->func = func;
+  rc->p = p;
+  rc->rs = 0;
+
+  /* --- If there's a free server, plug it in --- */
+
+  if (FREE->next == FREE) {
+    rc->next = QUEUE;
+    rc->prev = QUEUE->prev;
+    QUEUE->prev->next = rc;
+    QUEUE->prev = rc;
+  } else
+    attach(rc);
+}
+
+/* --- @bres_init@ --- *
+ *
+ * Arguments:  @sel_state *s@ = pointer to select multiplexor
+ *
+ * Returns:    ---
+ *
+ * Use:                Initializes the background resolver for use.
+ */
+
+void bres_init(sel_state *s)
+{
+  int i;
+
+  sel = s;
+  for (i = 0; i < BRES_MAX; i++) {
+    servers[i].next = FREE;
+    servers[i].prev = FREE->prev;
+    servers[i].kid = -1;
+    servers[i].rc = 0;
+    FREE->prev->next = &servers[i];
+    FREE->prev = &servers[i];
+  }
+}
+
+/*----- That's all, folks -------------------------------------------------*/
diff --git a/bres.h b/bres.h
new file mode 100644 (file)
index 0000000..f75f0bf
--- /dev/null
+++ b/bres.h
@@ -0,0 +1,125 @@
+/* -*-c-*-
+ *
+ * $Id: bres.h,v 1.1 1999/07/01 08:56:23 mdw Exp $
+ *
+ * Background reverse name resolution
+ *
+ * (c) 1999 Mark Wooding
+ */
+
+/*----- Licensing notice --------------------------------------------------* 
+ *
+ * This file is part of the `fw' port forwarder.
+ *
+ * `fw' is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * `fw' is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with `fw'; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*----- Revision history --------------------------------------------------* 
+ *
+ * $Log: bres.h,v $
+ * Revision 1.1  1999/07/01 08:56:23  mdw
+ * Initial revision
+ *
+ */
+
+#ifndef RES_H
+#define RES_H
+
+#ifdef __cplusplus
+  extern "C" {
+#endif
+
+/*----- Header files ------------------------------------------------------*/
+
+#include <sys/types.h>
+
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include <mLib/sel.h>
+#include <mLib/selbuf.h>
+
+/*----- Data structures ---------------------------------------------------*/
+
+/* --- Client allocated request block --- */
+
+typedef struct bres_client {
+  struct bres_client *next, *prev;     /* Queue of waiting resolve jobs */
+  struct bres_server *rs;              /* Pointer to attached server */
+  struct in_addr addr;                 /* Address to be resolved */
+  void (*func)(const char */*host*/, void */*p*/); /* Handler function */
+  void *p;                             /* Argument for handler function */
+} bres_client;
+
+/* --- Server maintained resolver blocks --- */
+
+typedef struct bres_server {
+  struct bres_server *next, *prev;     /* Doubly-linked list of servers */
+  pid_t kid;                           /* Process id of server process */
+  selbuf b;                            /* Input line-buffer selector */
+  sel_timer t;                         /* Timeout for idle servers */
+  int fd;                              /* File descriptor for writing */
+  struct bres_client *rc;              /* Pointer to attached client */
+} bres_server;
+
+/*----- Functions provided ------------------------------------------------*/
+
+/* --- @bres_abort@ --- *
+ *
+ * Arguments:  @bres_client *rc@ = pointer to client block
+ *
+ * Returns:    ---
+ *
+ * Use:                Removes a queued job.
+ */
+
+extern void bres_abort(bres_client */*rc*/);
+
+/* --- @bres_resolve@ --- *
+ *
+ * Arguments:  @bres_client *rc@ = pointer to client block
+ *             @struct in_addr addr@ = address to resolve
+ *             @void (*func)(const char *host, void *p)@ = handler function
+ *             @void *p@ = argument for handler function
+ *
+ * Returns:    ---
+ *
+ * Use:                Adds a resolver job to the queue.  The job will be processed
+ *             when there's a spare resolver process to deal with it.
+ */
+
+extern void bres_resolve(bres_client */*rc*/, struct in_addr /*addr*/,
+                       void (*/*func*/)(const char */*host*/, void */*p*/),
+                       void */*p*/);
+
+/* --- @bres_init@ --- *
+ *
+ * Arguments:  @sel_state *s@ = pointer to select multiplexor
+ *
+ * Returns:    ---
+ *
+ * Use:                Initializes the background resolver for use.
+ */
+
+extern void bres_init(sel_state */*s*/);
+
+/*----- That's all, folks -------------------------------------------------*/
+
+#ifdef __cplusplus
+  }
+#endif
+
+#endif
diff --git a/chan.c b/chan.c
new file mode 100644 (file)
index 0000000..55e6a75
--- /dev/null
+++ b/chan.c
@@ -0,0 +1,254 @@
+/* -*-c-*-
+ *
+ * $Id: chan.c,v 1.1 1999/07/01 08:56:23 mdw Exp $
+ *
+ * Channel management
+ *
+ * (c) 1999 Mark Wooding
+ */
+
+/*----- Licensing notice --------------------------------------------------* 
+ *
+ * This file is part of the `fw' port forwarder.
+ *
+ * `fw' is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * `fw' is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with `fw'; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*----- Revision history --------------------------------------------------* 
+ *
+ * $Log: chan.c,v $
+ * Revision 1.1  1999/07/01 08:56:23  mdw
+ * Initial revision
+ *
+ */
+
+/*----- Header files ------------------------------------------------------*/
+
+#include "config.h"
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <sys/types.h>
+#include <sys/time.h>
+#include <unistd.h>
+#include <sys/uio.h>
+
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include <mLib/alloc.h>
+#include <mLib/conn.h>
+#include <mLib/sel.h>
+
+#include "chan.h"
+#include "fw.h"
+
+/*----- Main code ---------------------------------------------------------*/
+
+/* --- @writechan@ --- *
+ *
+ * Arguments:  @int fd@ = file descriptor to write to
+ *             @unsigned mode@ = what the descriptor is ready for
+ *             @void *vp@ = pointer to channel block
+ *
+ * Returns:    ---
+ *
+ * Use:                Writes to a channel.
+ */
+
+static void writechan(int fd, unsigned mode, void *vp)
+{
+  chan *c = vp;
+  int w;
+  unsigned base = c->base;
+  unsigned len = c->len;
+
+  /* --- Write data from my buffer --- */
+
+  if (len) {
+
+    /* --- Do the write --- */
+
+    if (base + len <= CHAN_BUFSZ)
+      w = write(fd, c->buf + base, len);
+    else {
+      struct iovec iov[2];
+      iov[0].iov_base = c->buf + base;
+      iov[0].iov_len = CHAN_BUFSZ - base;
+      iov[1].iov_base = c->buf;
+      iov[1].iov_len = len - iov[0].iov_len;
+      w = writev(fd, iov, 2);
+    }
+
+    /* --- Sift through the results --- */
+
+    if (w < 0) {
+      if (errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK)
+       return;
+      goto close;
+    }
+    else if (w == 0)
+      goto close;
+    else if (c->len == CHAN_BUFSZ && !(c->f & CHANF_CLOSE))
+      sel_addfile(&c->r);
+    c->len -= w;
+  }
+  if (c->len == 0)
+    sel_rmfile(&c->w);
+
+  /* --- Close the output end if necessary --- */
+
+  if (c->len == 0 && (c->f & CHANF_CLOSE)) {
+    shutdown(fd, 1);
+    c->func(c->p);
+  }
+  return;
+
+  /* --- Force a close if an error occurred --- */
+
+close:
+  chan_close(c);
+  c->func(c->p);
+}
+
+/* --- @readchan@ --- *
+ *
+ * Arguments:  @int fd@ = file descriptor to read from
+ *             @unsigned mode@ = what the descriptor is ready for
+ *             @void *vp@ = pointer to channel block
+ *
+ * Returns:    ---
+ *
+ * Use:                Reads from a channel.
+ */
+
+static void readchan(int fd, unsigned mode, void *vp)
+{
+  chan *c = vp;
+  int r;
+  unsigned base = (c->base + c->len) & (CHAN_BUFSZ - 1);
+  unsigned len = CHAN_BUFSZ - c->len;
+
+  /* --- Do the read --- */
+
+  if (base + len <= CHAN_BUFSZ)
+    r = read(fd, c->buf + base, len);
+  else {
+    struct iovec iov[2];
+    iov[0].iov_base = c->buf + base;
+    iov[0].iov_len = CHAN_BUFSZ - base;
+    iov[1].iov_base = c->buf;
+    iov[1].iov_len = len - iov[0].iov_len;
+    r = readv(fd, iov, 2);
+  }
+
+  /* --- Sift through the results --- */
+
+  if (r < 0) {
+    if (errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK)
+      return;
+    goto close;
+  }
+  else if (r == 0)
+    goto close;
+  else if (c->len == 0 && !(c->f & CHANF_READY))
+    sel_addfile(&c->w);
+  c->len += r;
+  if (c->len == CHAN_BUFSZ)
+    sel_rmfile(&c->r);
+  return;
+
+  /* --- Close the read end of the channel --- */
+
+close:
+  c->f |= CHANF_CLOSE;
+  if (!c->len)
+    sel_addfile(&c->w);
+  sel_rmfile(&c->r);
+}
+
+/* --- @chan_close@ --- *
+ *
+ * Arguments:  @chan *c@ = pointer to channel
+ *
+ * Returns:    ---
+ *
+ * Use:                Closes down a channel prematurely.
+ */
+
+void chan_close(chan *c)
+{
+  if (!(c->f & CHANF_CLOSE) && c->len != CHAN_BUFSZ)
+    sel_rmfile(&c->r);
+  if ((c->f & CHANF_READY) && c->len != 0)
+    sel_rmfile(&c->w);
+}
+
+/* --- @chan_dest@ --- *
+ *
+ * Arguments:  @chan *c@ = pointer to channel
+ *             @int fd@ = destination file descriptor for channel
+ *
+ * Returns:    ---
+ *
+ * Use:                Sets the channel's destination so it knows where to put
+ *             data.
+ */
+
+void chan_dest(chan *c, int fd)
+{
+  if (c->f & CHANF_READY)
+    return;
+  sel_initfile(sel, &c->w, fd, SEL_WRITE, writechan, c);
+  if (c->len)
+    sel_addfile(&c->w);
+}
+
+/* --- @chan_open@ --- *
+ *
+ * Arguments:  @chan *c@ = pointer to channel to open
+ *             @int from, to@ = source and destination file descriptors
+ *             @void (*func)(void *p)@ = function to call on closure
+ *             @void *p@ = argument to pass to function
+ *
+ * Returns:    ---
+ *
+ * Use:                Opens a channel.  Data is copied from the source to the
+ *             destination.  The @to@ argument may be @-1@ if the file
+ *             descriptor isn't known yet.
+ */
+
+void chan_open(chan *c, int from, int to,
+              void (*func)(void */*p*/), void *p)
+{
+  c->func = func;
+  c->p = p;
+
+  c->base = 0;
+  c->len = 0;
+  c->f = 0;
+
+  sel_initfile(sel, &c->r, from, SEL_READ, readchan, c);
+  sel_addfile(&c->r);
+
+  if (to != -1)
+    chan_dest(c, to);
+}
+
+/*----- That's all, folks -------------------------------------------------*/
diff --git a/chan.h b/chan.h
new file mode 100644 (file)
index 0000000..f8a9638
--- /dev/null
+++ b/chan.h
@@ -0,0 +1,115 @@
+/* -*-c-*-
+ *
+ * $Id: chan.h,v 1.1 1999/07/01 08:56:23 mdw Exp $
+ *
+ * Channel management
+ *
+ * (c) 1999 Mark Wooding
+ */
+
+/*----- Licensing notice --------------------------------------------------* 
+ *
+ * This file is part of the `fw' port forwarder.
+ *
+ * `fw' is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * `fw' is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with `fw'; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*----- Revision history --------------------------------------------------* 
+ *
+ * $Log: chan.h,v $
+ * Revision 1.1  1999/07/01 08:56:23  mdw
+ * Initial revision
+ *
+ */
+
+#ifndef CHAN_H
+#define CHAN_H
+
+#ifdef __cplusplus
+  extern "C" {
+#endif
+
+/*----- Header files ------------------------------------------------------*/
+
+#include <mLib/sel.h>
+
+/*----- Magic numbers -----------------------------------------------------*/
+
+#define CHAN_BUFSZ 4096
+
+/*----- Data structures ---------------------------------------------------*/
+
+typedef struct chan {
+  unsigned base, len;                  /* Base and length of data */
+  unsigned f;                          /* Various interesting flags */
+  void (*func)(void */*p*/);           /* Function to call on closure */
+  void *p;                             /* Argument to pass function */
+  sel_file r, w;                       /* Reader and writer selectors */
+  char buf[CHAN_BUFSZ];                        /* The actual data buffer */
+} chan;
+
+#define CHANF_CLOSE 1u                 /* Close channel when buffer empty */
+#define CHANF_READY 2u                 /* The channel destination exists */
+
+/*----- Functions provided ------------------------------------------------*/
+
+/* --- @chan_close@ --- *
+ *
+ * Arguments:  @chan *c@ = pointer to channel
+ *
+ * Returns:    ---
+ *
+ * Use:                Closes down a channel prematurely.
+ */
+
+extern void chan_close(chan */*c*/);
+
+/* --- @chan_dest@ --- *
+ *
+ * Arguments:  @chan *c@ = pointer to channel
+ *             @int fd@ = destination file descriptor for channel
+ *
+ * Returns:    ---
+ *
+ * Use:                Sets the channel's destination so it knows where to put
+ *             data.
+ */
+
+extern void chan_dest(chan */*c*/, int /*fd*/);
+
+/* --- @chan_open@ --- *
+ *
+ * Arguments:  @chan *c@ = pointer to channel to open
+ *             @int from, to@ = source and destination file descriptors
+ *             @void (*func)(void *p)@ = function to call on closure
+ *             @void *p@ = argument to pass to function
+ *
+ * Returns:    ---
+ *
+ * Use:                Opens a channel.  Data is copied from the source to the
+ *             destination.  The @to@ argument may be @-1@ if the file
+ *             descriptor isn't known yet.
+ */
+
+extern void chan_open(chan */*c*/, int /*from*/, int /*to*/,
+                     void (*/*func*/)(void */*p*/), void */*p*/);
+
+/*----- That's all, folks -------------------------------------------------*/
+
+#ifdef __cplusplus
+  }
+#endif
+
+#endif
diff --git a/conf.c b/conf.c
new file mode 100644 (file)
index 0000000..049af46
--- /dev/null
+++ b/conf.c
@@ -0,0 +1,351 @@
+/* -*-c-*-
+ *
+ * $Id: conf.c,v 1.1 1999/07/01 08:56:23 mdw Exp $
+ *
+ * Configuration parsing
+ *
+ * (c) 1999 Mark Wooding
+ */
+
+/*----- Licensing notice --------------------------------------------------* 
+ *
+ * This file is part of the `fw' port forwarder.
+ *
+ * `fw' is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * `fw' is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with `fw'; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*----- Revision history --------------------------------------------------* 
+ *
+ * $Log: conf.c,v $
+ * Revision 1.1  1999/07/01 08:56:23  mdw
+ * Initial revision
+ *
+ */
+
+/*----- Header files ------------------------------------------------------*/
+
+#include "config.h"
+
+#include <ctype.h>
+#include <errno.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+
+#include <mLib/dstr.h>
+#include <mLib/quis.h>
+#include <mLib/report.h>
+
+#include "acl.h"
+#include "listener.h"
+#include "scan.h"
+
+/*----- Magic numbers -----------------------------------------------------*/
+
+#define CTOK_EOF (-1)
+#define CTOK_WORD 256
+
+/*----- Main code ---------------------------------------------------------*/
+
+/* --- @token@ --- *
+ *
+ * Arguments:  @scanner *sc@ = pointer to scanner definition
+ *
+ * Returns:    Type of token scanned.
+ *
+ * Use:                Reads the next token from the character scanner.
+ */
+
+static int token(scanner *sc)
+{
+#define SCAN(sc) (sc)->ops->scan((sc))
+#define UNSCAN(sc, x) (sc)->ops->unscan((x), (sc))
+
+  int ch;
+
+  for (;;) {
+    ch = SCAN(sc);
+    if (ch == '\n')
+      sc->line++;
+    else if (isspace((unsigned char)ch))
+      ;
+    else switch (ch) {
+      case EOF:
+       return (sc->t = CTOK_EOF);
+      case '#':
+       do ch = SCAN(sc); while (ch != EOF && ch != '\n');
+       if (ch == '\n')
+         sc->line++;
+       break;
+      case '{':
+      case '}':
+      case ':':
+      case '/':
+      case ';':
+       return (sc->t = ch);
+      default:
+       DRESET(&sc->d);
+       do {
+         DPUTC(&sc->d, ch);
+         ch = SCAN(sc);
+       } while (ch != EOF && ch != '{' && ch != ';' &&
+                ch != '}' && ch != ':' && ch != '/' &&
+                !isspace((unsigned char)(ch)));
+       UNSCAN(sc, ch);
+       DPUTZ(&sc->d);
+       return (sc->t = CTOK_WORD);
+    }
+  }
+
+#undef SCAN
+#undef UNSCAN
+}
+
+/* --- @error@ --- *
+ *
+ * Arguments:  @scanner *sc@ = pointer to scanner definition
+ *             @const char *msg@ = message skeleton string
+ *             @...@ = extra arguments for the skeleton
+ *
+ * Returns:    Doesn't
+ *
+ * Use:                Reports an error at the current scanner location.
+ */
+
+static void error(scanner *sc, const char *msg, ...)
+{
+  va_list ap;
+  va_start(ap, msg);
+  fprintf(stderr, "%s: %s:%i: ", QUIS, sc->src, sc->line);
+  vfprintf(stderr, msg, ap);
+  fputc('\n', stderr);
+  exit(1);
+}
+
+/* --- @portnum@ --- *
+ *
+ * Arguments:  @scanner *sc@ = pointer to scanner (for error reporting)
+ *             @const char *p@ = pointer to port name
+ *
+ * Returns:    Port number (network byte order)
+ *
+ * Use:                Converts a textual port name or number into a usable thing.
+ */
+
+static unsigned short portnum(scanner *sc, const char *p)
+{
+  struct servent *s;
+  if (isdigit((unsigned char)*p))
+    return (htons(atoi(p)));
+  if ((s = getservbyname(p, "tcp")) == 0)
+    error(sc, "unknown tcp service `%s'", p);
+  return (s->s_port);
+}
+
+/* --- @getconf@ --- *
+ *
+ * Arguments:  @scanner *sc@ = pointer to scanner to read from
+ *             @listener *l@ = listener to configure (or zero)
+ *             @acl_entry ***a@ = pointer to tail of ACL (or zero)
+ *
+ * Returns:    ---
+ *
+ * Use:                Reads a local or global configuration statement.
+ */
+
+static void getconf(scanner *sc, listener *l, acl_entry ***a)
+{
+  unsigned act;
+
+  /* --- Access control limitations --- */
+
+  if ((strcmp(sc->d.buf, "allow") == 0 && (act = ACL_ALLOW, 1)) ||
+      (strcmp(sc->d.buf, "deny") == 0 && (act = ACL_DENY, 1))) {
+    struct hostent *h;
+    struct netent *n;
+    struct in_addr addr, mask;
+
+    /* --- Find the host or network address --- */
+
+    token(sc);
+    if (sc->t == CTOK_WORD && strcmp(sc->d.buf, "from") == 0)
+      token(sc);
+    if (sc->t != CTOK_WORD)
+      error(sc, "parse error, address expected");
+    if ((n = getnetbyname(sc->d.buf)) != 0)
+      addr.s_addr = htonl(n->n_net);
+    else if ((h = gethostbyname(sc->d.buf)) == 0)
+      error(sc, "couldn't resolve address `%s'", sc->d.buf);
+    else
+      memcpy(&addr, h->h_addr, sizeof(struct in_addr));
+    token(sc);
+
+    /* --- Find the netmask, if any --- */
+
+    if (sc->t != '/')
+      mask.s_addr = ~0ul;
+    else {
+      token(sc);
+      if (sc->t != CTOK_WORD)
+       error(sc, "parse error, netmask expected");
+      if (strchr(sc->d.buf, '.') == 0)
+       mask.s_addr = htonl((~0ul << (32 - atoi(sc->d.buf))) & 0xffffffff);
+      else {
+#ifdef HAVE_INET_ATON
+       if (!inet_aton(sc->d.buf, &mask))
+         error(sc, "bad netmask `%s'", sc->d.buf);
+#else
+       mask.s_addr = inet_addr(sc->d.buf);
+#endif
+      }
+      token(sc);
+    }
+
+    /* --- Add the access control entry --- */
+
+    acl_add(a, act, addr, mask);
+  }
+
+  /* --- Anything unrecognized --- */
+
+  else
+    error(sc, "parse error, unknown configuration keyword `%s'", sc->d.buf);
+}
+
+/* --- @conf_parse@ --- *
+ *
+ * Arguments:  @void *scp@ = pointer to scanner definition
+ *
+ * Returns:    ---
+ *
+ * Use:                Parses a configuration file from the scanner.
+ */
+
+void conf_parse(void *scp)
+{
+  scanner *sc = scp;
+
+  token(sc);
+
+  for (;;) {
+    if (sc->t == CTOK_EOF)
+      break;
+    if (sc->t != CTOK_WORD)
+      error(sc, "parse error, keyword expected");
+
+    /* --- Handle a forwarding request --- */
+
+    if (strcmp(sc->d.buf, "forward") == 0 ||
+       strcmp(sc->d.buf, "fw") == 0) {
+      unsigned short sp, dp;
+      struct sockaddr_in sin;
+      struct hostent *h;
+      int fd;
+      listener *l;
+
+      /* --- Read the source port --- */
+
+      token(sc);
+      if (sc->t == CTOK_WORD && strcmp(sc->d.buf, "port") == 0)
+       token(sc);
+      if (sc->t != CTOK_WORD)
+       error(sc, "parse error, source port expected");
+      sp = portnum(sc, sc->d.buf);
+
+      /* --- Read the destination address --- */
+
+      token(sc);
+      if (sc->t == CTOK_WORD && strcmp(sc->d.buf, "to") == 0)
+       token(sc);
+      if (sc->t != CTOK_WORD)
+       error(sc, "parse error, destination address expected");
+      if ((h = gethostbyname(sc->d.buf)) == 0)
+       error(sc, "couldn't resolve address `%s'", sc->d.buf);
+
+      token(sc);
+      if (sc->t == ':')
+       token(sc);
+      if (sc->t != CTOK_WORD)
+       error(sc, "parse error, destination port expected");
+      dp = portnum(sc, sc->d.buf);
+
+      /* --- Make the socket --- */
+
+      if ((fd = socket(PF_INET, SOCK_STREAM, 0)) < 0)
+       error(sc, "couldn't create socket: %s", strerror(errno));
+
+      /* --- Set it to allow address reuse --- */
+
+      {
+       int opt = 1;
+       setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
+      }
+
+      /* --- Bind it to the right port --- */
+
+      sin.sin_family = AF_INET;
+      sin.sin_addr.s_addr = htonl(INADDR_ANY);
+      sin.sin_port = sp;
+      if (bind(fd, (struct sockaddr *)&sin, sizeof(sin))) {
+       error(sc, "couldn't bind to port %i: %s",
+             ntohs(sp), strerror(errno));
+      }
+
+      /* --- Set it to listen for connections --- */
+
+      if (listen(fd, 5))
+       error(sc, "couldn't listen on socket: %s", strerror(errno));
+
+      /* --- Fill in a new listener --- */
+
+      memcpy(&sin.sin_addr, h->h_addr, sizeof(struct in_addr));
+      sin.sin_port = dp;
+      l = listener_add(fd, sp, &sin);
+
+      /* --- Snarf access controls and other attributes --- */
+
+      token(sc);
+      if (sc->t == '{') {
+       acl_entry **a = &l->acl;
+       token(sc);
+       while (sc->t != '}') {
+         if (sc->t != CTOK_WORD)
+           error(sc, "parse error, keyword or `}' expected");
+         getconf(sc, l, &a);
+         if (sc->t == ';')
+           token(sc);
+       }
+       *a = 0;
+       token(sc);
+      }
+    }
+
+    /* --- Other configuration is handled elsewhere --- */
+
+    else
+      getconf(sc, 0, 0);
+
+    if (sc->t == ';')
+      token(sc);
+  }
+}
+
+/*----- That's all, folks -------------------------------------------------*/
diff --git a/conf.h b/conf.h
new file mode 100644 (file)
index 0000000..e1713ee
--- /dev/null
+++ b/conf.h
@@ -0,0 +1,69 @@
+/* -*-c-*-
+ *
+ * $Id: conf.h,v 1.1 1999/07/01 08:56:23 mdw Exp $
+ *
+ * Configuration parsing
+ *
+ * (c) 1999 Mark Wooding
+ */
+
+/*----- Licensing notice --------------------------------------------------* 
+ *
+ * This file is part of the `fw' port forwarder.
+ *
+ * `fw' is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * `fw' is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with `fw'; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*----- Revision history --------------------------------------------------* 
+ *
+ * $Log: conf.h,v $
+ * Revision 1.1  1999/07/01 08:56:23  mdw
+ * Initial revision
+ *
+ */
+
+#ifndef CONF_H
+#define CONF_H
+
+#ifdef __cplusplus
+  extern "C" {
+#endif
+
+/*----- Header files ------------------------------------------------------*/
+
+#ifndef SCAN_H
+#  include "scan.h"
+#endif
+
+/*----- Functions provided ------------------------------------------------*/
+
+/* --- @conf_parse@ --- *
+ *
+ * Arguments:  @void *scp@ = pointer to a scanner structure
+ *
+ * Returns:    ---
+ *
+ * Use:                Parses a configuration file fragment from the scanner
+ */
+
+extern void conf_parse(void */*scp*/);
+
+/*----- That's all, folks -------------------------------------------------*/
+
+#ifdef __cplusplus
+  }
+#endif
+
+#endif
diff --git a/configure.in b/configure.in
new file mode 100644 (file)
index 0000000..e1341af
--- /dev/null
@@ -0,0 +1,47 @@
+dnl -*-fundamental-*-
+dnl
+dnl $Id: configure.in,v 1.1 1999/07/01 08:56:23 mdw Exp $
+dnl
+dnl Configuration script for fw
+dnl
+dnl (c) 1999 Mark Wooding
+dnl
+
+dnl ----- Licensing notice --------------------------------------------------
+dnl
+dnl This file is part of the `fw' port forwarder.
+dnl
+dnl `fw' is free software; you can redistribute it and/or modify
+dnl it under the terms of the GNU General Public License as published by
+dnl the Free Software Foundation; either version 2 of the License, or
+dnl (at your option) any later version.
+dnl 
+dnl `fw' is distributed in the hope that it will be useful,
+dnl but WITHOUT ANY WARRANTY; without even the implied warranty of
+dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+dnl GNU General Public License for more details.
+dnl 
+dnl You should have received a copy of the GNU General Public License
+dnl along with `fw'; if not, write to the Free Software Foundation,
+dnl Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+dnl ----- Revision history --------------------------------------------------
+dnl
+dnl $Log: configure.in,v $
+dnl Revision 1.1  1999/07/01 08:56:23  mdw
+dnl Initial revision
+dnl
+
+AC_INIT(fw.c)
+AM_INIT_AUTOMAKE(fw, 1.0.0)
+AM_CONFIG_HEADER(config.h)
+
+AC_PROG_CC
+mdw_GCC_FLAGS
+
+AC_CHECK_FUNCS(inet_aton)
+
+AC_CONFIG_SUBDIRS(mLib)
+AC_OUTPUT(Makefile)
+
+dnl ----- That's all, folks -------------------------------------------------
diff --git a/forward.c b/forward.c
new file mode 100644 (file)
index 0000000..1d3118a
--- /dev/null
+++ b/forward.c
@@ -0,0 +1,223 @@
+/* -*-c-*-
+ *
+ * $Id: forward.c,v 1.1 1999/07/01 08:56:23 mdw Exp $
+ *
+ * Port forwarding
+ *
+ * (c) 1999 Mark Wooding
+ */
+
+/*----- Licensing notice --------------------------------------------------* 
+ *
+ * This file is part of the `fw' port forwarder.
+ *
+ * `fw' is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * `fw' is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with `fw'; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*----- Revision history --------------------------------------------------* 
+ *
+ * $Log: forward.c,v $
+ * Revision 1.1  1999/07/01 08:56:23  mdw
+ * Initial revision
+ *
+ */
+
+/*----- Header files ------------------------------------------------------*/
+
+#include "config.h"
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <sys/types.h>
+#include <sys/time.h>
+#include <unistd.h>
+
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include <mLib/alloc.h>
+#include <mLib/conn.h>
+#include <mLib/sel.h>
+
+#include "chan.h"
+#include "forward.h"
+#include "fw.h"
+
+/*----- Data structures ---------------------------------------------------*/
+
+/* --- Port forwarding data --- */
+
+typedef struct fw {
+  int fd_a;                            /* Client's file descriptor */
+  int fd_b;                            /* Server's file descriptor */
+  unsigned state;                      /* Current state of the world */
+  conn c;                              /* Nonblocking connect to server */
+  chan ab;                             /* Channel from @a@ to @b@ */
+  chan ba;                             /* Channel from @b@ to @a@ */
+} fw;
+
+#define S_AB 1u                                /* Channel from @a@ to @b@ open */
+#define S_BA 2u                                /* Channel from @b@ to @a@ open */
+#define S_NOTCONN 4u                   /* Not connected to @b@ yet */
+#define S_NOTID 8u                     /* Not finished identification */
+
+/*----- Main code ---------------------------------------------------------*/
+
+/* --- @done@ --- *
+ *
+ * Arguments:  @fw *f@ = pointer to forwarder
+ *
+ * Returns:    ---
+ *
+ * Use:                Tidies up a forwarder that nobody wants any more.
+ */
+
+static void done(fw *f)
+{
+  close(f->fd_a);
+  close(f->fd_b);
+  free(f);
+}
+
+/* --- @ident@ --- *
+ *
+ * Arguments:  @void *vp@ = pointer to forwarder
+ *
+ * Returns:    ---
+ *
+ * Use:                Handles completion of client identification.
+ */
+
+static void ident(void *vp)
+{
+  fw *f = vp;
+  f->state &= ~S_NOTID;
+  if (!f->state)
+    done(f);
+}
+  
+/* --- @closeba@ --- *
+ *
+ * Arguments:  @void *vp@ = pointer to forwarder
+ *
+ * Returns:    ---
+ *
+ * Use:                Handles the closing of the %$b \rightarrow a$% channel.
+ */
+
+static void closeba(void *vp)
+{
+  fw *f = vp;
+  f->state &= ~S_BA;
+  if (!f->state)
+    done(f);
+}
+
+/* --- @closeab@ --- *
+ *
+ * Arguments:  @void *vp@ = pointer to forwarder
+ *
+ * Returns:    ---
+ *
+ * Use:                Handles the closing of the %$a \rightarrow b$% channel.
+ */
+
+static void closeab(void *vp)
+{
+  fw *f = vp;
+  f->state &= ~S_AB;
+  if (!f->state)
+    done(f);
+}
+
+/* --- @go@ --- *
+ *
+ * Arguments:  @int fd@ = newly connected socket
+ *             @void *vp@ = pointer to forwarder
+ *
+ * Returns:    ---
+ *
+ * Use:                Completes the forwarder once the outbound connection is set
+ *             up.
+ */
+
+static void go(int fd, void *vp)
+{
+  fw *f = vp;
+
+  /* --- If it all went tits-up, deal with that --- */
+
+  if (fd == -1) {
+    chan_close(&f->ab);
+    close(f->fd_a);
+    free(f);
+    return;
+  }
+
+  /* --- OK, finish configuring the forwarder --- */
+
+  f->fd_b = fd;
+  chan_dest(&f->ab, fd);
+  chan_open(&f->ba, fd, f->fd_a, closeba, f);
+  f->state |= S_BA;
+  f->state &= ~S_NOTCONN;
+}
+
+/* --- @forward@ --- *
+ *
+ * Arguments:  @int fd@ = file descriptor attached to client
+ *             @struct sockaddr_in *sin@ = pointer to destination address
+ *             @const id_req *q@ = pointer to identification request block
+ *
+ * Returns:    ---
+ *
+ * Use:                Start a port forwarding job.
+ */
+
+void forward(int fd, struct sockaddr_in *sin, const id_req *q)
+{
+  fw *f;
+  int nfd;
+
+  /* --- Set up the new socket --- */
+
+  if ((nfd = socket(PF_INET, SOCK_STREAM, 0)) < 0)
+    return;
+
+  {
+    int opt = 1;
+    setsockopt(fd, SOL_SOCKET, SO_OOBINLINE, &opt, sizeof(opt));
+    setsockopt(nfd, SOL_SOCKET, SO_OOBINLINE, &opt, sizeof(opt));
+  }
+
+  /* --- Initialize the easy bits --- */
+
+  f = xmalloc(sizeof(*f));
+  f->fd_a = fd;
+  f->fd_b = -1;
+  f->state = S_NOTCONN | S_AB | S_NOTID;
+
+  /* --- Open the %$a \rightarrow b$% channel --- */
+
+  chan_open(&f->ab, fd, -1, closeab, f);
+  conn_init(&f->c, sel, nfd, (struct sockaddr *)sin, sizeof(*sin), go, f);
+  identify(q, ident, f);
+}
+
+/*----- That's all, folks -------------------------------------------------*/
diff --git a/forward.h b/forward.h
new file mode 100644 (file)
index 0000000..b73eff7
--- /dev/null
+++ b/forward.h
@@ -0,0 +1,75 @@
+/* -*-c-*-
+ *
+ * $Id: forward.h,v 1.1 1999/07/01 08:56:23 mdw Exp $
+ *
+ * Port forwarding
+ *
+ * (c) 1999 Mark Wooding
+ */
+
+/*----- Licensing notice --------------------------------------------------* 
+ *
+ * This file is part of the `fw' port forwarder.
+ *
+ * `fw' is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * `fw' is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with `fw'; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*----- Revision history --------------------------------------------------* 
+ *
+ * $Log: forward.h,v $
+ * Revision 1.1  1999/07/01 08:56:23  mdw
+ * Initial revision
+ *
+ */
+
+#ifndef FORWARD_H
+#define FORWARD_H
+
+#ifdef __cplusplus
+  extern "C" {
+#endif
+
+/*----- Header files ------------------------------------------------------*/
+
+#include <sys/socket.h>
+#include <netinet/in.h>
+
+#ifndef IDENTIFY_H
+#  include "identify.h"
+#endif
+
+/*----- Functions provided ------------------------------------------------*/
+
+/* --- @forward@ --- *
+ *
+ * Arguments:  @int fd@ = file descriptor attached to client
+ *             @struct sockaddr_in *sin@ = pointer to destination address
+ *             @const id_req *q@ = pointer to identification request block
+ *
+ * Returns:    ---
+ *
+ * Use:                Start a port forwarding job.
+ */
+
+extern void forward(int /*fd*/, struct sockaddr_in */*sin*/,
+                   const id_req */*q*/);
+
+/*----- That's all, folks -------------------------------------------------*/
+
+#ifdef __cplusplus
+  }
+#endif
+
+#endif
diff --git a/fw.c b/fw.c
new file mode 100644 (file)
index 0000000..ba4b565
--- /dev/null
+++ b/fw.c
@@ -0,0 +1,262 @@
+/* -*-c-*-
+ *
+ * $Id: fw.c,v 1.1 1999/07/01 08:56:23 mdw Exp $
+ *
+ * Port forwarding thingy
+ *
+ * (c) 1999 Mark Wooding
+ */
+
+/*----- Licensing notice --------------------------------------------------* 
+ *
+ * This file is part of the `fw' port forwarder.
+ *
+ * `fw' is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * `fw' is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with `fw'; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*----- Revision history --------------------------------------------------* 
+ *
+ * $Log: fw.c,v $
+ * Revision 1.1  1999/07/01 08:56:23  mdw
+ * Initial revision
+ *
+ */
+
+/*----- Header files ------------------------------------------------------*/
+
+#include "config.h"
+
+#include <ctype.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <unistd.h>
+#include <syslog.h>
+
+#include <mLib/mdwopt.h>
+#include <mLib/quis.h>
+#include <mLib/report.h>
+#include <mLib/sel.h>
+#include <mLib/sub.h>
+
+#include "acl.h"
+#include "bres.h"
+#include "conf.h"
+#include "listener.h"
+#include "scan.h"
+
+/*----- Static variables --------------------------------------------------*/
+
+sel_state *sel;                                /* Multiplexor for nonblocking I/O */
+
+/*----- Main code ---------------------------------------------------------*/
+
+/* --- Standard GNU help options --- */
+
+static void version(FILE *fp)
+{
+  fprintf(fp, "%s version " VERSION "\n", QUIS);
+}
+
+static void usage(FILE *fp)
+{
+  fprintf(stderr, "Usage: %s [-d] [-f file] [config statements...]\n",
+         QUIS);
+}
+
+static void help(FILE *fp)
+{
+  version(fp);
+  fputc('\n', fp);
+  usage(fp);
+  fputs("\n\
+A fairly full-featured port-forwarder.  Options available are:\n\
+\n\
+-h, --help             Display this help message.\n\
+-v, --version          Display the program's version number.\n\
+-u, --usage            Display a terse usage summary.\n\
+\n\
+-f, --file=FILE                Read configuration from a file.\n\
+-d, --dump             Dump the configuration to standard output.\n\
+\n\
+Configuration may be supplied in one or more configuration files, or on\n\
+the command line (or both).  If no `-f' option is present, and no\n\
+configuration is given on the command line, the standard input stream is\n\
+read.\n\
+\n\
+Configuration is free-form.  Comments begin with a `#' character and\n\
+continue to the end of the line.  When reading from the command line,\n\
+each argument is considered a separate line.  See the manual page for the\n\
+complete syntax.\n\
+", fp);
+}
+
+/* --- @main@ --- *
+ *
+ * Arguments:  @int argc@ = number of command line arguments
+ *             @char *argv[]@ = vector of argument strings
+ *
+ * Returns:    ---
+ *
+ * Use:                Simple port-forwarding server.
+ */
+
+int main(int argc, char *argv[])
+{
+  unsigned f = 0;
+  sel_state sst;
+
+  enum {
+    f_bogus = 1,
+    f_file = 2,
+    f_dump = 4,
+    f_fork = 8
+  };
+
+  /* --- Initialize things --- */
+
+  ego(argv[0]);
+  sel = &sst;
+  sel_init(sel);
+  sub_init();
+  bres_init(sel);
+
+  /* --- Parse command line options --- */
+
+  for (;;) {
+    static struct option opts[] = {
+
+      /* --- Standard GNU help options --- */
+
+      { "help",        0,              0,      'h' },
+      { "version",     0,              0,      'v' },
+      { "usage",       0,              0,      'u' },
+
+      /* --- Other useful arguments --- */
+
+      { "file",                OPTF_ARGREQ,    0,      'f' },
+      { "dump",                0,              0,      'd' },
+      { "fork",                0,              0,      'b' },
+      { "background",  0,              0,      'b' },
+
+      /* --- Magic terminator --- */
+
+      { 0,             0,              0,      0 }
+    };
+    int i = mdwopt(argc, argv, "hvu f:db", opts, 0, 0, 0);
+
+    if (i < 0)
+      break;
+    switch (i) {
+      case 'h':
+       help(stdout);
+       exit(0);
+       break;
+      case 'v':
+       version(stdout);
+       exit(0);
+       break;
+      case 'u':
+       usage(stdout);
+       exit(0);
+       break;
+      case 'f': {
+       scan_filectx ctx;
+       FILE *fp;
+       if ((fp = fopen(optarg, "r")) == 0)
+         die(1, "couldn't open file `%s': %s", optarg, strerror(errno));
+       scan_fileinit(&ctx, fp, optarg);
+       conf_parse(&ctx);
+       fclose(fp);
+       f |= f_file;
+      } break;
+      case 'd':
+       f |= f_dump;
+       break;
+      case 'b':
+       f |= f_fork;
+       break;
+      default:
+       f |= f_bogus;
+       break;
+    }
+  }
+
+  if (f & f_bogus) {
+    usage(stderr);
+    exit(1);
+  }
+
+  /* --- Deal with the remaining arguments --- */
+
+  if (optind == argc) {
+    if (f & f_file)
+      /* Cool */;
+    else if (isatty(STDIN_FILENO)) {
+      moan("no configuration given and stdin is a terminal.");
+      moan("type `%s --help' for usage information.", QUIS);
+      exit(1);
+    } else {
+      scan_filectx ctx;
+      scan_fileinit(&ctx, stdin, "<stdin>");
+      conf_parse(&ctx);
+    }
+  } else {
+    scan_argvctx ctx;
+    scan_argvinit(&ctx, argv + optind);
+    conf_parse(&ctx);
+  }
+
+  /* --- Dump out the state --- */
+
+  if (f & f_dump) {
+    sel_file *s;
+    fputs("global acl:\n", stdout);
+    acl_dump(0, stdout);
+    for (s = sel->files; s; s = s->next)
+      listener_dump((listener *)s, stdout);
+    exit(0);
+  }
+
+  /* --- Fork into the background --- */
+
+  if (f & f_fork) {
+    pid_t kid;
+
+    kid = fork();
+    if (kid == -1)
+      die(1, "couldn't fork: %s", strerror(errno));
+    if (kid != 0)
+      _exit(0);
+
+    close(0); close(1); close(2);
+    setsid();
+
+    kid = fork();
+    if (kid != 0)
+      _exit(0);
+  }
+
+  /* --- Let rip --- */
+
+  openlog(QUIS, 0, LOG_DAEMON);
+  for (;;)
+    sel_select(sel);
+  return (0);
+}
+
+/*----- That's all, folks -------------------------------------------------*/
diff --git a/fw.h b/fw.h
new file mode 100644 (file)
index 0000000..8c87832
--- /dev/null
+++ b/fw.h
@@ -0,0 +1,58 @@
+/* -*-c-*-
+ *
+ * $Id: fw.h,v 1.1 1999/07/01 08:56:23 mdw Exp $
+ *
+ * Main header file for port forwarder
+ *
+ * (c) 1999 Mark Wooding
+ */
+
+/*----- Licensing notice --------------------------------------------------* 
+ *
+ * This file is part of the `fw' port forwarder.
+ *
+ * `fw' is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * `fw' is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with `fw'; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*----- Revision history --------------------------------------------------* 
+ *
+ * $Log: fw.h,v $
+ * Revision 1.1  1999/07/01 08:56:23  mdw
+ * Initial revision
+ *
+ */
+
+#ifndef FW_H
+#define FW_H
+
+#ifdef __cplusplus
+  extern "C" {
+#endif
+
+/*----- Header files ------------------------------------------------------*/
+
+#include <mLib/sel.h>
+
+/*----- Global variables --------------------------------------------------*/
+
+extern sel_state *sel;
+
+/*----- That's all, folks -------------------------------------------------*/
+
+#ifdef __cplusplus
+  }
+#endif
+
+#endif
diff --git a/ident.c b/ident.c
new file mode 100644 (file)
index 0000000..ef1bb5c
--- /dev/null
+++ b/ident.c
@@ -0,0 +1,146 @@
+/* -*-c-*-
+ *
+ * $Id: ident.c,v 1.1 1999/07/01 08:56:23 mdw Exp $
+ *
+ * Parse replies from RFC931 servers
+ *
+ * (c) 1999 Mark Wooding
+ */
+
+/*----- Licensing notice --------------------------------------------------* 
+ *
+ * This file is part of the `fw' port forwarder.
+ *
+ * `fw' is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * `fw' is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with `fw'; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*----- Revision history --------------------------------------------------* 
+ *
+ * $Log: ident.c,v $
+ * Revision 1.1  1999/07/01 08:56:23  mdw
+ * Initial revision
+ *
+ * Revision 1.1.1.1  1999/05/21 22:22:27  mdw
+ * Initial import.  Code not really finished yet.
+ *
+ */
+
+/*----- Header files ------------------------------------------------------*/
+
+#include <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "ident.h"
+
+/*----- Main code ---------------------------------------------------------*/
+
+/* --- @next@ --- *
+ *
+ * Arguments:  @char **pp@ = address of string pointer
+ *
+ * Returns:    Address of next token.
+ *
+ * Use:                Reads the next token from the result string.  Tokens are
+ *             terminated by whitespace, or `:' or `,' characters.  The
+ *             result string has had `\' escapes removed; it's stored in
+ *             the same memory as the input string.  The actual content
+ *             of the delimiter doesn't seem to be interesting, so it
+ *             gets thrown away.
+ */
+
+static char *next(char **pp)
+{
+  char *p, *q, *r;
+
+  /* --- Deal with reads past the end of the string --- */
+
+  if (!*pp)
+    return ("");
+
+  /* --- Initialize various pointers into the string --- */
+
+  p = q = r = *pp;
+
+  /* --- Skip past any leading whitespace --- */
+
+  while (isspace((unsigned char)*p))
+    p++;
+
+  /* --- Now start work on the string itself --- */
+
+  for (;;) {
+    if (*p == 0 || *p == ':' || *p == ',' || isspace((unsigned char)*p))
+      break;
+    else if (*p == '\\') {
+      p++;
+      if (!*p) {
+       *q++ = '\\';
+       break;
+      }
+    }
+    *q++ = *p++;
+  }
+
+  /* --- Tidy up afterwards --- */
+
+  while (isspace((unsigned char)*p))
+    p++;
+  if (*p == 0)
+    *pp = 0;
+  else if (*p == ':' || *p == ',')
+    *pp = p + 1;
+  else
+    *pp = p;
+  *q = 0;
+
+  return (r);
+}
+
+/* --- @ident_parse@ --- *
+ *
+ * Arguments:  @char *p@ = pointer to input string from identd
+ *             @ident *i@ = pointer to output block
+ *
+ * Returns:    ---
+ *
+ * Use:                Parses a result string from an RFC931 (identd) server.
+ */
+
+void ident_parse(char *p, ident *i)
+{
+  char *q;
+
+  /* --- Read the source and destination port numbers --- */
+
+  i->sport = atoi(next(&p));
+  i->dport = atoi(next(&p));
+
+  /* --- Find out what sort of a reply this is --- */
+
+  q = next(&p);
+  if (strcmp(q, "USERID") == 0) {
+    i->type = ident_userid;
+    i->u.userid.os = next(&p);
+    i->u.userid.user = next(&p);
+  } else if (strcmp(q, "ERROR") == 0) {
+    i->type = ident_error;
+    i->u.error = next(&p);
+  } else
+    i->type = ident_bad;
+}
+
+/*----- That's all, folks -------------------------------------------------*/
diff --git a/ident.h b/ident.h
new file mode 100644 (file)
index 0000000..deda7e7
--- /dev/null
+++ b/ident.h
@@ -0,0 +1,87 @@
+/* -*-c-*-
+ *
+ * $Id: ident.h,v 1.1 1999/07/01 08:56:23 mdw Exp $
+ *
+ * Parse replies from RFC931 servers
+ *
+ * (c) 1999 Mark Wooding
+ */
+
+/*----- Licensing notice --------------------------------------------------* 
+ *
+ * This file is part of the `fw' port forwarder.
+ *
+ * `fw' is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * `fw' is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with `fw'; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*----- Revision history --------------------------------------------------* 
+ *
+ * $Log: ident.h,v $
+ * Revision 1.1  1999/07/01 08:56:23  mdw
+ * Initial revision
+ *
+ * Revision 1.1.1.1  1999/05/21 22:22:27  mdw
+ * Initial import.  Code not really finished yet.
+ *
+ */
+
+#ifndef IDENT_H
+#define IDENT_H
+
+#ifdef __cplusplus
+  extern "C" {
+#endif
+
+/*----- Data structures ---------------------------------------------------*/
+
+typedef struct ident {
+  unsigned short sport, dport;         /* Source and destination ports */
+  unsigned type;                       /* Type of reply from server */
+  union {
+    struct {
+      char *os;                                /* Operating system name */
+      char *user;                      /* User name */
+    } userid;
+    char *error;                       /* Error message from server */
+  } u;
+} ident;
+
+enum {
+  ident_userid,
+  ident_error,
+  ident_bad
+};
+
+/*----- Functions provided ------------------------------------------------*/
+
+/* --- @ident_parse@ --- *
+ *
+ * Arguments:  @char *p@ = pointer to input string from identd
+ *             @ident *i@ = pointer to output block
+ *
+ * Returns:    ---
+ *
+ * Use:                Parses a result string from an RFC931 (identd) server.
+ */
+
+extern void ident_parse(char */*p*/, ident */*i*/);
+
+/*----- That's all, folks -------------------------------------------------*/
+
+#ifdef __cplusplus
+  }
+#endif
+
+#endif
diff --git a/identify.c b/identify.c
new file mode 100644 (file)
index 0000000..db6df93
--- /dev/null
@@ -0,0 +1,306 @@
+/* -*-c-*-
+ *
+ * $Id: identify.c,v 1.1 1999/07/01 08:56:23 mdw Exp $
+ *
+ * Identifies and logs the client of a connection
+ *
+ * (c) 1999 Mark Wooding
+ */
+
+/*----- Licensing notice --------------------------------------------------* 
+ *
+ * This file is part of the `fw' port forwarder.
+ *
+ * `fw' is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * `fw' is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with `fw'; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*----- Revision history --------------------------------------------------* 
+ *
+ * $Log: identify.c,v $
+ * Revision 1.1  1999/07/01 08:56:23  mdw
+ * Initial revision
+ *
+ */
+
+/*----- Header files ------------------------------------------------------*/
+
+#include "config.h"
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+#include <sys/types.h>
+#include <sys/time.h>
+#include <unistd.h>
+#include <syslog.h>
+
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+
+#include <mLib/alloc.h>
+#include <mLib/conn.h>
+#include <mLib/dstr.h>
+#include <mLib/report.h>
+#include <mLib/sel.h>
+#include <mLib/selbuf.h>
+#include <mLib/str.h>
+
+#include "bres.h"
+#include "fw.h"
+#include "ident.h"
+#include "identify.h"
+
+/*----- Magic numbers -----------------------------------------------------*/
+
+#define TIMEOUT 15                     /* Seconds to wait for answers */
+
+/*----- Data structures ---------------------------------------------------*/
+
+/* --- Structure to track the progress of an identification --- */
+
+typedef struct id {
+  id_req q;                            /* Copy of client's request block */
+  void (*func)(void */*p*/);           /* Function to call when done */
+  void *p;                             /* Argument to pass to function */
+  time_t when;                         /* When the connection occurred */
+  conn c;                              /* Connection selector */
+  unsigned state;                      /* Current state of the world */
+  bres_client r;                       /* Backgd resolver client block */
+  char host[64];                       /* Resolved hostname */
+  char user[32];                       /* Authenticated client user */
+  sel_timer t;                         /* Timeout selector */
+  selbuf id;                           /* Reader for the RFC931 client */
+} id;
+
+#define S_HOST 1u                      /* Read the hostname from resolver */
+#define S_USER 2u                      /* Read the username from RFC931 */
+#define S_UCONN 4u                     /* Connected to remote RFC931 */
+#define S_TIMER 8u                     /* Timeout has completed */
+
+/*----- Main code ---------------------------------------------------------*/
+
+/* --- @id_done@ --- *
+ *
+ * Arguments:  @id *i@ = pointer to identification block
+ *
+ * Returns:    ---
+ *
+ * Use:                Finishes with an identification block.
+ */
+
+static void id_done(id *i)
+{
+  char buf[64];
+  struct tm *tm;
+
+  /* --- Close down the various dependent bits --- */
+
+  if (!(i->state & S_HOST))
+    bres_abort(&i->r);
+  if (!(i->state & S_UCONN))
+    conn_kill(&i->c);
+  else if (!(i->state & S_USER))
+    selbuf_disable(&i->id);
+  if (!(i->state & S_TIMER))
+    sel_rmtimer(&i->t);
+
+  /* --- Report the final result --- */
+
+  tm = localtime(&i->when);
+  strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", tm);
+  syslog(LOG_NOTICE, "%s %s %s from %s@%s\n",
+        buf, i->q.desc, i->q.act, i->user, i->host);
+
+  /* --- Dispose of the block --- */
+
+  i->func(i->p);
+  free(i);
+}
+
+/* --- @id_res@ --- *
+ *
+ * Arguments:  @const char *host@ = name of the resolved host
+ *             @void *vp@ = pointer to identification block
+ *
+ * Returns:    ---
+ *
+ * Use:                Responds to a completed reverse name resolution.
+ */
+
+static void id_res(const char *host, void *vp)
+{
+  id *i = vp;
+  str_sanitize(i->host, host, sizeof(i->host));
+  i->state |= S_HOST;
+  if (i->state & S_USER)
+    id_done(i);
+}
+
+/* --- @id_ident@ --- *
+ *
+ * Arguments:  @char *p@ = pointer to string read from server
+ *             @void *vp@ = pointer to identification block
+ *
+ * Returns:    ---
+ *
+ * Use:                Responds to a line read from the remote RFC931 server.
+ */
+
+static void id_ident(char *p, void *vp)
+{
+  id *i = vp;
+
+  /* --- Get rid of the connection --- */
+
+  i->state |= S_USER;
+  selbuf_disable(&i->id);
+  close(i->id.reader.fd);
+
+  /* --- Read the information from the returned line --- */
+
+  if (p) {
+    ident idbuf;
+    ident_parse(p, &idbuf);
+    if (idbuf.type == ident_userid)
+      str_sanitize(i->user, idbuf.u.userid.user, sizeof(i->user));
+  }
+
+  /* --- Maybe finish off this identification --- */
+
+  if (i->state & S_HOST)
+    id_done(i);
+}
+
+/* --- @id_conn@ --- *
+ *
+ * Arguments:  @int fd@ = file descriptor connected
+ *             @void *vp@ = pointer to identification block
+ *
+ * Returns:    ---
+ *
+ * Use:                Responds to a completed connection to the remote RFC931
+ *             server.
+ */
+
+static void id_conn(int fd, void *vp)
+{
+  id *i = vp;
+
+  if (fd == -1) {
+    i->state |= S_USER | S_UCONN;
+    if (i->state & S_HOST)
+      id_done(i);
+  } else {
+    dstr d = DSTR_INIT;
+    dstr_putf(&d, "%u, %u\n",
+             ntohs(i->q.rsin.sin_port), ntohs(i->q.lsin.sin_port));
+    write(fd, d.buf, d.len);
+    dstr_destroy(&d);
+    i->state |= S_UCONN;
+    selbuf_init(&i->id, sel, fd, id_ident, i);
+  }
+}
+
+/* --- @id_timer@ --- *
+ *
+ * Arguments:  @struct timeval *tv@ = pointer to the current time
+ *             @void *vp@ = pointer to identification block
+ *
+ * Returns:    ---
+ *
+ * Use:                Times an identification job out.
+ */
+
+static void id_timer(struct timeval *tv, void *vp)
+{
+  id *i = vp;
+  id_done(i);
+}
+
+/* --- @identify@ --- *
+ *
+ * Arguments:  @const id_req *q@ = pointer to request block
+ *             @void (*func)(void *p)@ = function to call when done
+ *             @void *p@ = argument to pass to function
+ *
+ * Returns:    ---
+ *
+ * Use:                Starts a background ident lookup and reverse-resolve job
+ *             which will, eventually, report a message to the system log.
+ */
+
+void identify(const id_req *q,
+             void (*func)(void */*p*/), void *p)
+{
+  id *i;
+
+  /* --- Initialize the block with stuff --- */
+
+  i = xmalloc(sizeof(*i));
+  i->q = *q;
+  i->func = func;
+  i->p = p;
+
+  str_sanitize(i->host, inet_ntoa(q->rsin.sin_addr), sizeof(i->host));
+  strcpy(i->user, "<ANONYMOUS>");
+  i->state = 0;
+  i->when = time(0);
+
+  /* --- Set up the connection to the identity server --- */
+
+  {
+    int fd;
+    struct sockaddr_in sin;
+
+    if ((fd = socket(PF_INET, SOCK_STREAM, 0)) < 0)
+      id_conn(-1, i);
+    else {
+      sin.sin_family = AF_INET;
+      sin.sin_addr = q->lsin.sin_addr;
+      sin.sin_port = 0;
+      if (bind(fd, (struct sockaddr *)&sin, sizeof(sin))) {
+       close(fd);
+       id_conn(-1, i);
+      } else {
+       sin.sin_family = AF_INET;
+       sin.sin_addr = q->rsin.sin_addr;
+       sin.sin_port = htons(113);
+       conn_init(&i->c, sel, fd,
+                 (struct sockaddr *)&sin, sizeof(sin),
+                 id_conn, i);
+      }
+    }
+  }
+
+  /* --- Set up the name resolver --- */
+
+  bres_resolve(&i->r, q->rsin.sin_addr, id_res, i);
+
+  /* --- Set up the time limiter --- */
+
+  {
+    struct timeval tv;
+    gettimeofday(&tv, 0);
+    tv.tv_sec += TIMEOUT;
+    sel_addtimer(sel, &i->t, &tv, id_timer, i);
+  }
+}
+
+/*----- That's all, folks -------------------------------------------------*/
diff --git a/identify.h b/identify.h
new file mode 100644 (file)
index 0000000..c4019b6
--- /dev/null
@@ -0,0 +1,81 @@
+/* -*-c-*-
+ *
+ * $Id: identify.h,v 1.1 1999/07/01 08:56:23 mdw Exp $
+ *
+ * Identifies and logs the client of a connection
+ *
+ * (c) 1999 Mark Wooding
+ */
+
+/*----- Licensing notice --------------------------------------------------* 
+ *
+ * This file is part of the `fw' port forwarder.
+ *
+ * `fw' is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * `fw' is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with `fw'; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*----- Revision history --------------------------------------------------* 
+ *
+ * $Log: identify.h,v $
+ * Revision 1.1  1999/07/01 08:56:23  mdw
+ * Initial revision
+ *
+ */
+
+#ifndef IDENTIFY_H
+#define IDENTIFY_H
+
+#ifdef __cplusplus
+  extern "C" {
+#endif
+
+/*----- Header files ------------------------------------------------------*/
+
+#include <sys/socket.h>
+#include <netinet/in.h>
+
+/*----- Data structures ---------------------------------------------------*/
+
+typedef struct id_req {
+  struct sockaddr_in lsin;             /* Local address of connection */
+  struct sockaddr_in rsin;             /* Remote address of connection */
+  const char *desc;                    /* Description of connection */
+  const char *act;                     /* Action taken by server */
+} id_req;
+
+/*----- Functions provided ------------------------------------------------*/
+
+/* --- @identify@ --- *
+ *
+ * Arguments:  @const id_req *q@ = pointer to request block
+ *             @void (*func)(void *p)@ = function to call when done
+ *             @void *p@ = argument to pass to function
+ *
+ * Returns:    ---
+ *
+ * Use:                Starts a background ident lookup and reverse-resolve job
+ *             which will, eventually, report a message to the system log.
+ */
+
+extern void identify(const id_req */*q*/,
+                    void (*/*func*/)(void */*p*/), void */*p*/);
+
+/*----- That's all, folks -------------------------------------------------*/
+
+#ifdef __cplusplus
+  }
+#endif
+
+#endif
diff --git a/listener.c b/listener.c
new file mode 100644 (file)
index 0000000..aa1b6c8
--- /dev/null
@@ -0,0 +1,189 @@
+/* -*-c-*-
+ *
+ * $Id: listener.c,v 1.1 1999/07/01 08:56:23 mdw Exp $
+ *
+ * A port forwarding listener
+ *
+ * (c) 1999 Mark Wooding
+ */
+
+/*----- Licensing notice --------------------------------------------------* 
+ *
+ * This file is part of the `fw' port forwarder.
+ *
+ * `fw' is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * `fw' is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with `fw'; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*----- Revision history --------------------------------------------------* 
+ *
+ * $Log: listener.c,v $
+ * Revision 1.1  1999/07/01 08:56:23  mdw
+ * Initial revision
+ *
+ */
+
+/*----- Header files ------------------------------------------------------*/
+
+#include "config.h"
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <sys/types.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+
+#include <mLib/alloc.h>
+#include <mLib/dstr.h>
+#include <mLib/report.h>
+#include <mLib/sel.h>
+#include <mLib/sub.h>
+
+#include "acl.h"
+#include "forward.h"
+#include "fw.h"
+#include "identify.h"
+#include "listener.h"
+
+/*----- Main code ---------------------------------------------------------*/
+
+/* --- @doclose@ --- *
+ *
+ * Arguments:  @void *vp@ = pointer to file descriptor to close
+ *
+ * Returns:    ---
+ *
+ * Use:                Closes a file descriptor once it's no longer useful.
+ */
+
+static void doclose(void *vp)
+{
+  int *fd = vp;
+  close(*fd);
+  DESTROY(fd);
+}
+
+/* --- @newconn@ --- *
+ *
+ * Arguments:  @int fd@ = file descriptor which is ready
+ *             @unsigned state@ = state in which file descriptor is
+ *             @void *vp@ = pointer to listener block
+ *
+ * Returns:    ---
+ *
+ * Use:                Responds to a new connection.
+ */
+
+static void newconn(int fd, unsigned state, void *vp)
+{
+  int nfd;
+  id_req q;
+  int lsinsz = sizeof(q.lsin), rsinsz = sizeof(q.rsin);
+  int f;
+  listener *l = vp;
+
+  /* --- Accept the new connection --- */
+
+  if ((nfd = accept(fd, (struct sockaddr *)&q.rsin, &rsinsz)) < 0)
+    return;
+  if (getsockname(nfd, (struct sockaddr *)&q.lsin, &lsinsz)) {
+    close(nfd);
+    return;
+  }
+  q.desc = l->desc;
+
+  /* --- Find out whether this connection is allowed --- */
+
+  if (!acl_check(l->acl, q.rsin.sin_addr)) {
+    int *fdp = CREATE(int);
+    *fdp = nfd;
+    q.act = "refused";
+    identify(&q, doclose, fdp);
+    return;
+  }
+
+  /* --- Set the socket nonblocking --- */
+
+  if ((f = fcntl(nfd, F_GETFL)) >= 0)
+    fcntl(nfd, F_SETFL, f | O_NONBLOCK);
+
+  /* --- Open a new forwarding context for the connection --- */
+
+  q.act = "accepted";
+  forward(nfd, &l->sin, &q);
+}
+
+/* --- @listener_dump@ --- *
+ *
+ * Arguments:  @listener *l@ = pointer to listener block
+ *             @FILE *fp@ = stream to dump on
+ *
+ * Returns:    ---
+ *
+ * Use:                Dumps a listener to an output stream.
+ */
+
+void listener_dump(listener *l, FILE *fp)
+{
+  struct sockaddr_in sin;
+  int sinsz = sizeof(sin);
+
+  getsockname(l->rd.fd, (struct sockaddr *)&sin, &sinsz);
+  fprintf(fp, "forward port %u to ", ntohs(sin.sin_port));
+  fputs(inet_ntoa(l->sin.sin_addr), fp);
+  fprintf(fp, ":%u; acl:\n", ntohs(l->sin.sin_port));
+  if (l->acl)
+    acl_dump(l->acl, fp);
+}
+
+/* --- @listener_add@ --- *
+ *
+ * Arguments:  @int fd@ = created listening socket
+ *             @unsigned sp@ = source port number
+ *             @struct sockaddr_in *sin@ = pointer to destination address
+ *
+ * Returns:    The address of the new listener.
+ *
+ * Use:                Adds a forwarding listener.
+ */
+
+listener *listener_add(int fd, unsigned sp, struct sockaddr_in *sin)
+{
+  int f;
+  listener *l = CREATE(listener);
+  dstr d = DSTR_INIT;
+
+  l->sin = *sin;
+  l->acl = 0;
+  f = fcntl(fd, F_GETFL);
+  if (f != -1)
+    fcntl(fd, F_SETFL, f | O_NONBLOCK);
+  sel_initfile(sel, &l->rd, fd, SEL_READ, newconn, l);
+  sel_addfile(&l->rd);
+  dstr_putf(&d, "fw %u -> %s:%u",
+           ntohs(sp), inet_ntoa(sin->sin_addr), ntohs(sin->sin_port));
+  l->desc = xstrdup(d.buf);
+  dstr_destroy(&d);
+  return (l);
+}
+
+/*----- That's all, folks -------------------------------------------------*/
diff --git a/listener.h b/listener.h
new file mode 100644 (file)
index 0000000..40d27ef
--- /dev/null
@@ -0,0 +1,102 @@
+/* -*-c-*-
+ *
+ * $Id: listener.h,v 1.1 1999/07/01 08:56:23 mdw Exp $
+ *
+ * A port forwarding listener
+ *
+ * (c) 1999 Mark Wooding
+ */
+
+/*----- Licensing notice --------------------------------------------------* 
+ *
+ * This file is part of the `fw' port forwarder.
+ *
+ * `fw' is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * `fw' is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with `fw'; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*----- Revision history --------------------------------------------------* 
+ *
+ * $Log: listener.h,v $
+ * Revision 1.1  1999/07/01 08:56:23  mdw
+ * Initial revision
+ *
+ */
+
+#ifndef LISTENER_H
+#define LISTENER_H
+
+#ifdef __cplusplus
+  extern "C" {
+#endif
+
+/*----- Header files ------------------------------------------------------*/
+
+#include <stdio.h>
+
+#include <sys/socket.h>
+#include <netinet/in.h>
+
+#include <mLib/sel.h>
+
+#ifndef ACL_H
+#  include "acl.h"
+#endif
+
+/*----- Data structures ---------------------------------------------------*/
+
+/* --- A listener object --- */
+
+typedef struct listener {
+  sel_file rd;                         /* Read selector for new connects */
+  struct sockaddr_in sin;              /* Destination address */
+  const char *desc;                    /* Description of forwarder */
+  acl_entry *acl;                      /* Access controls */
+} listener;
+
+/*----- Functions provided ------------------------------------------------*/
+
+/* --- @listener_dump@ --- *
+ *
+ * Arguments:  @listener *l@ = pointer to listener block
+ *             @FILE *fp@ = stream to dump on
+ *
+ * Returns:    ---
+ *
+ * Use:                Dumps a listener to an output stream.
+ */
+
+extern void listener_dump(listener */*l*/, FILE */*fp*/);
+
+/* --- @listener_add@ --- *
+ *
+ * Arguments:  @int fd@ = created listening socket
+ *             @unsigned sp@ = source port number
+ *             @struct sockaddr_in *sin@ = pointer to destination address
+ *
+ * Returns:    The address of the new listener.
+ *
+ * Use:                Adds a forwarding listener.
+ */
+
+extern listener *listener_add(int /*fd*/,
+                             unsigned /*sp*/, struct sockaddr_in */*sin*/);
+
+/*----- That's all, folks -------------------------------------------------*/
+
+#ifdef __cplusplus
+  }
+#endif
+
+#endif
diff --git a/scan.c b/scan.c
new file mode 100644 (file)
index 0000000..808ef8f
--- /dev/null
+++ b/scan.c
@@ -0,0 +1,126 @@
+/* -*-c-*-
+ *
+ * $Id: scan.c,v 1.1 1999/07/01 08:56:23 mdw Exp $
+ *
+ * Character scanners
+ *
+ * (c) 1999 Mark Wooding
+ */
+
+/*----- Licensing notice --------------------------------------------------* 
+ *
+ * This file is part of the `fw' port forwarder.
+ *
+ * `fw' is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * `fw' is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with `fw'; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*----- Revision history --------------------------------------------------* 
+ *
+ * $Log: scan.c,v $
+ * Revision 1.1  1999/07/01 08:56:23  mdw
+ * Initial revision
+ *
+ */
+
+/*----- Header files ------------------------------------------------------*/
+
+#include "config.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <mLib/dstr.h>
+
+#include "scan.h"
+
+/*----- Main code ---------------------------------------------------------*/
+
+/* --- Generic scanner setup --- */
+
+static void scan_init(scanner *sc, scan_ops *ops, const char *src)
+{
+  sc->ops = ops;
+  sc->line = 1;
+  sc->src = src;
+  dstr_create(&sc->d);
+}
+
+/* --- @argv@ scanner --- */
+
+static int argv_scan(void *p)
+{
+  scan_argvctx *c = p;
+  int ch;
+
+  if (c->ch != EOF) {
+    ch = c->ch;
+    c->ch = EOF;
+  } else if (*c->p)
+    ch = *c->p++;
+  else if (*c->pp) {
+    c->p = *c->pp++;
+    ch = '\n';
+  } else
+    ch = EOF;
+
+  return (ch);
+}
+
+static void argv_unscan(int ch, void *p)
+{
+  scan_argvctx *c = p;
+  c->ch = ch;
+}
+
+void scan_argvinit(scan_argvctx *c, char **pp)
+{
+  static struct scan_ops ops = { argv_scan, argv_unscan };
+  c->p = *pp++;
+  c->pp = pp;
+  c->ch = EOF;
+  scan_init(&c->sc, &ops, "<args>");
+}
+
+/* --- File scanner --- */
+
+static int file_scan(void *p)
+{
+  scan_filectx *c = p;
+  return (getc(c->fp));
+}
+
+static void file_unscan(int ch, void *p)
+{
+  scan_filectx *c = p;
+  ungetc(ch, c->fp);
+}
+
+void scan_fileinit(scan_filectx *c, FILE *fp, const char *file)
+{
+  static struct scan_ops ops = { file_scan, file_unscan };
+  c->fp = fp;
+  scan_init(&c->sc, &ops, file);
+}
+
+/* --- Miscellaneous functions --- */
+
+void scan_destroy(void *p)
+{
+  scanner *sc = p;
+  dstr_destroy(&sc->d);
+}
+
+/*----- That's all, folks -------------------------------------------------*/
diff --git a/scan.h b/scan.h
new file mode 100644 (file)
index 0000000..f08fe01
--- /dev/null
+++ b/scan.h
@@ -0,0 +1,96 @@
+/* -*-c-*-
+ *
+ * $Id: scan.h,v 1.1 1999/07/01 08:56:23 mdw Exp $
+ *
+ * Character scanners
+ *
+ * (c) 1999 Mark Wooding
+ */
+
+/*----- Licensing notice --------------------------------------------------* 
+ *
+ * This file is part of the `fw' port forwarder.
+ *
+ * `fw' is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * `fw' is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with `fw'; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*----- Revision history --------------------------------------------------* 
+ *
+ * $Log: scan.h,v $
+ * Revision 1.1  1999/07/01 08:56:23  mdw
+ * Initial revision
+ *
+ */
+
+#ifndef SCAN_H
+#define SCAN_H
+
+#ifdef __cplusplus
+  extern "C" {
+#endif
+
+/*----- Header files ------------------------------------------------------*/
+
+#include <stdio.h>
+
+#include <mLib/dstr.h>
+
+/*----- Data structures ---------------------------------------------------*/
+
+/* --- A configuration scanner --- */
+
+typedef struct scan_ops {
+  int (*scan)(void */*p*/);            /* Character scan function */
+  void (*unscan)(int /*ch*/, void */*p*/); /* Character pushback function */
+} scan_ops;
+
+typedef struct scanner {
+  scan_ops *ops;                       /* Pointer to scanner operations */
+  const char *src;                     /* Name of this source */
+  int line;                            /* Current line number */
+  int t;                               /* Token type */
+  dstr d;                              /* Current token value */
+} scanner;
+
+/*----- Scanners provided -------------------------------------------------*/
+
+/* --- The @argv@ scanner --- */
+
+typedef struct scan_argvctx {
+  scanner sc;                          /* Scanner base structure */
+  char *p;                             /* Pointer to next character */
+  char **pp;                           /* Pointer to next string */
+  int ch;                              /* Pushback character */
+} scan_argvctx;
+
+extern void scan_argvinit(scan_argvctx */*c*/, char **/*pp*/);
+
+/* --- The file scanner --- */
+
+typedef struct scan_filectx {
+  scanner sc;                          /* Scanner base structure */
+  FILE *fp;                            /* Stream pointer */
+} scan_filectx;
+
+extern void scan_fileinit(scan_filectx */*c*/,
+                         FILE */*fp*/, const char */*file*/);
+
+/*----- That's all, folks -------------------------------------------------*/
+
+#ifdef __cplusplus
+  }
+#endif
+
+#endif
diff --git a/setup b/setup
new file mode 100755 (executable)
index 0000000..048c599
--- /dev/null
+++ b/setup
@@ -0,0 +1,10 @@
+#! /bin/sh
+
+set -e
+mklinks
+ln -s ../mLib .
+mkaclocal
+autoconf
+autoheader
+automake
+mkdir build