config.h.in
configure
stamp-h.in
+deb-build
## -*-makefile-*-
##
-## $Id: Makefile.am,v 1.5 1999/11/11 19:08:27 mdw Exp $
+## $Id: Makefile.am,v 1.6 2003/11/25 14:08:23 mdw Exp $
##
## Makefile for fw
##
##----- Revision history ----------------------------------------------------
##
## $Log: Makefile.am,v $
+## Revision 1.6 2003/11/25 14:08:23 mdw
+## Debianization. Socket target options. Internet binding.
+##
## Revision 1.5 1999/11/11 19:08:27 mdw
## Build separately from mLib.
##
bin_PROGRAMS = fw
man_MANS = fw.1
-EXTRA_DIST = $(man_MANS)
+EXTRA_DIST = \
+ $(man_MANS) \
+ debian/changelog debian/copyright debian/control debian/rules
fw_SOURCES = \
chan.c conf.c endpt.c fw.c reffd.c scan.c \
/* -*-c-*-
*
- * $Id: acl.c,v 1.3 1999/07/27 18:30:53 mdw Exp $
+ * $Id: acl.c,v 1.4 2003/11/25 14:08:23 mdw Exp $
*
* Access control list handling
*
/*----- Revision history --------------------------------------------------*
*
* $Log: acl.c,v $
+ * Revision 1.4 2003/11/25 14:08:23 mdw
+ * Debianization. Socket target options. Internet binding.
+ *
* Revision 1.3 1999/07/27 18:30:53 mdw
* Various minor portability fixes.
*
#include "acl.h"
-/*----- Static variables --------------------------------------------------*/
+/*----- Main code ---------------------------------------------------------*/
+
+/* --- @acl_addhost@ --- *
+ *
+ * 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 a host-authentication entry to the end of an access
+ * control list.
+ */
+
+static int acl_checkhost(void *aa, struct in_addr addr, unsigned port)
+{
+ acl_host *a = aa;
+ return ((addr.s_addr & a->mask.s_addr) == a->addr.s_addr);
+}
-static acl_entry *global = 0;
-static acl_entry **gtail = &global;
+static void acl_dumphost(void *aa, FILE *fp)
+{
+ acl_host *a = aa;
+
+ fputs("from ", fp);
+ fputs(inet_ntoa(a->addr), fp);
+ fputc('/', fp);
+ fputs(inet_ntoa(a->mask), fp);
+}
-/*----- Main code ---------------------------------------------------------*/
+static void acl_freehost(void *aa)
+{
+ acl_host *a = aa;
+ DESTROY(a);
+}
+
+static const acl_ops acl_hostops = {
+ acl_checkhost, acl_dumphost, acl_freehost
+};
+
+void acl_addhost(acl_entry ***a, unsigned act,
+ struct in_addr addr, struct in_addr mask)
+{
+ acl_host *aa = CREATE(acl_host);
+ aa->a.next = 0;
+ aa->a.ops = &acl_hostops;
+ aa->a.act = act;
+ aa->addr.s_addr = addr.s_addr & mask.s_addr;
+ aa->mask = mask;
+ **a = &aa->a;
+ *a = &aa->a.next;
+}
+
+/* --- @acl_addpriv@ --- *
+ *
+ * Arguments: @acl_entry ***a@ = address of pointer to list tail
+ * @unsigned act@ = what to do with matching addresses
+ *
+ * Returns: ---
+ *
+ * Use: Adds a privileged-port check to the end of an access control
+ * list.
+ */
+
+static int acl_checkpriv(void *aa, struct in_addr addr, unsigned port)
+{
+ return (port < 1024);
+}
+
+static void acl_dumppriv(void *aa, FILE *fp)
+{
+ fputs("from privileged ports", fp);
+}
+
+static void acl_freepriv(void *aa)
+{
+ acl_entry *a = aa;
+ DESTROY(a);
+}
+
+static const acl_ops acl_privops = {
+ acl_checkpriv, acl_dumppriv, acl_freepriv
+};
+
+void acl_addpriv(acl_entry ***a, unsigned act)
+{
+ acl_entry *aa = CREATE(acl_entry);
+ aa->next = 0;
+ aa->ops = &acl_privops;
+ aa->act = act;
+ **a = aa;
+ *a = &aa->next;
+}
/* --- @acl_check@ --- *
*
* Arguments: @acl_entry *a@ = pointer to ACL to check against
* @struct in_addr addr@ = address to check
+ * @unsigned port@ = port number to check
+ * @int *act@ = verdict (should initially be @ACT_ALLOW@)
*
- * Returns: Nonzero if allowed.
+ * Returns: Zero if undecided, nonzero if a rule matched.
*
* Use: Checks an address against an ACL.
*/
-int acl_check(acl_entry *a, struct in_addr addr)
+int acl_check(acl_entry *a, struct in_addr addr, unsigned port, int *act)
{
- 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;
+ for (; a; a = a->next) {
+ if (a->ops->check(a, addr, port)) {
+ *act = a->act & ACL_PERM;
+ return (1);
}
- a = global;
+ *act = (a->act & ACL_PERM) ^ 1;
}
-
- return (act);
+ return (0);
}
/* --- @acl_dump@ --- *
void acl_dump(acl_entry *a, FILE *fp)
{
- if (!a)
- a = global;
for (; a; a = a->next) {
- fprintf(fp, " %s from ",
+ fprintf(fp, " %s ",
(a->act & ACL_PERM) == ACL_ALLOW ? "allow" : "deny");
- fputs(inet_ntoa(a->addr), fp);
- fputc('/', fp);
- fputs(inet_ntoa(a->mask), fp);
+ a->ops->dump(a, fp);
fputc('\n', fp);
}
}
while (a) {
acl_entry *aa = a;
a = a->next;
- DESTROY(aa);
+ aa->ops->free(aa);
}
}
-/* --- @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 = >ail;
- **a = aa;
- *a = &aa->next;
-}
-
/*----- That's all, folks -------------------------------------------------*/
/* -*-c-*-
*
- * $Id: acl.h,v 1.3 1999/07/27 18:30:53 mdw Exp $
+ * $Id: acl.h,v 1.4 2003/11/25 14:08:23 mdw Exp $
*
* Access control list handling
*
/*----- Revision history --------------------------------------------------*
*
* $Log: acl.h,v $
+ * Revision 1.4 2003/11/25 14:08:23 mdw
+ * Debianization. Socket target options. Internet binding.
+ *
* Revision 1.3 1999/07/27 18:30:53 mdw
* Various minor portability fixes.
*
typedef struct acl_entry {
struct acl_entry *next; /* Next entry in the list */
+ const struct acl_ops *ops; /* Operations for the ACL entry */
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_DENY 0 /* Deny access to matching conns */
+#define ACL_ALLOW 1 /* Allow access to matching conns */
#define ACL_PERM 1u /* Bit mask for permission bit */
+/* --- Host-based access control --- */
+
+typedef struct acl_host {
+ acl_entry a; /* Base structure */
+ struct in_addr addr, mask; /* Address and netmask */
+} acl_host;
+
+/* --- ACL methods --- */
+
+typedef struct acl_ops {
+ int (*check)(void */*a*/, struct in_addr /*addr*/, unsigned /*port*/);
+ void (*dump)(void */*a*/, FILE */*fp*/);
+ void (*free)(void */*a*/);
+} acl_ops;
+
/*----- Functions provided ------------------------------------------------*/
/* --- @acl_check@ --- *
*
* Arguments: @acl_entry *a@ = pointer to ACL to check against
* @struct in_addr addr@ = address to check
+ * @unsigned port@ = port number to check
+ * @int *act@ = verdict (should initially be @ACT_ALLOW@)
*
- * Returns: Nonzero if allowed.
+ * Returns: Zero if undecided, nonzero if a rule matched.
*
* Use: Checks an address against an ACL.
*/
-extern int acl_check(acl_entry */*a*/, struct in_addr /*addr*/);
+extern int acl_check(acl_entry */*a*/,
+ struct in_addr /*addr*/, unsigned /*port*/,
+ int */*act*/);
/* --- @acl_dump@ --- *
*
extern void acl_free(acl_entry */*a*/);
-/* --- @acl_add@ --- *
+/* --- @acl_addhost@ --- *
*
* Arguments: @acl_entry ***a@ = address of pointer to list tail
* @unsigned act@ = what to do with matching addresses
*
* Returns: ---
*
- * Use: Adds an entry to the end of an access control list.
+ * Use: Adds a host-authentication entry to the end of an access
+ * control list.
+ */
+
+extern void acl_addhost(acl_entry ***/*a*/, unsigned /*act*/,
+ struct in_addr /*addr*/, struct in_addr /*mask*/);
+
+/* --- @acl_addpriv@ --- *
+ *
+ * Arguments: @acl_entry ***a@ = address of pointer to list tail
+ * @unsigned act@ = what to do with matching addresses
+ *
+ * Returns: ---
+ *
+ * Use: Adds a privileged-port check 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*/);
+extern void acl_addpriv(acl_entry ***/*a*/, unsigned /*act*/);
/*----- That's all, folks -------------------------------------------------*/
/* -*-c-*-
*
- * $Id: addr.h,v 1.2 1999/07/27 18:30:53 mdw Exp $
+ * $Id: addr.h,v 1.3 2003/11/25 14:08:23 mdw Exp $
*
* Generic interface to network address handlers
*
/*----- Revision history --------------------------------------------------*
*
* $Log: addr.h,v $
+ * Revision 1.3 2003/11/25 14:08:23 mdw
+ * Debianization. Socket target options. Internet binding.
+ *
* Revision 1.2 1999/07/27 18:30:53 mdw
* Various minor portability fixes.
*
#include <sys/socket.h>
#include <mLib/dstr.h>
+#include <mLib/conn.h>
#ifndef REFFD_H
# include "reffd.h"
#endif
+#ifndef ENDPT_H
+# include "endpt.h"
+#endif
+
#ifndef SCAN_H
# include "scan.h"
#endif
size_t sz;
} addr;
-typedef struct gen_addr {
- addr a;
- struct sockaddr sa;
-} gen_addr;
-
#define ADDRSZ(sz) (sizeof(addr) + (sz))
/* --- Address configuration --- *
enum {
ADDR_SRC,
- ADDR_DEST
+ ADDR_DEST,
+ ADDR_GLOBAL
};
/* --- Description of an address type handler --- */
typedef struct addr_ops {
const char *name; /* Protocol's internal name */
- int pf; /* Protocol family number */
/* --- @read@ --- *
*
void (*print)(addr */*a*/, unsigned /*type*/, dstr */*d*/);
- /* --- @initopts@ --- *
+ /* --- @initsrcopts@ --- *
*
* Arguments: ---
*
* are added to the block when necessary.
*/
- addr_opts *(*initopts)(void);
+ addr_opts *(*initsrcopts)(void);
/* --- @option@ --- *
*
* Arguments: @scanner *sc@ = pointer to a scanner to read from
+ * @unsigned type@ = kind of option this is
* @addr_opts *ao@ = data block to modify (from @init@), or null
*
* Returns: Nonzero to claim the option.
*
- * Use: Parses an option, either global or listener-specific.
+ * Use: Parses a source option, either global or listener-specific.
+ */
+
+ int (*option)(scanner */*sc*/, addr_opts */*ao*/, unsigned /*type*/);
+
+ /* --- @freesrcopts@ --- *
+ *
+ * Arguments: @addr_opts *ao@ = data block to remove
+ *
+ * Returns: ---
+ *
+ * Use: Throws away all the configuration data for an address type.
+ */
+
+ void (*freesrcopts)(addr_opts */*ao*/);
+
+ /* --- @bind@ --- *
+ *
+ * Arguments: @addr *a@ = the address to bind to
+ * @addr_opts *ao@ = the address options
+ *
+ * Returns: File descriptor of bound socket if OK, or @-1@ on error.
+ *
+ * Use: Binds a listening socket. The tedious stuff with @listen@
+ * isn't necessary.
+ */
+
+ int (*bind)(addr */*a*/, addr_opts */*ao*/);
+
+ /* --- @unbind@ --- *
+ *
+ * Arguments: @addr *a@ = pointer to an address
+ *
+ * Returns: ---
+ *
+ * Use: Unbinds an address. This is used when tidying up. The main
+ * purpose is to let the Unix-domain handler remove its socket
+ * node from the filesystem.
*/
- int (*option)(scanner */*sc*/, addr_opts */*ao*/);
+ void (*unbind)(addr */*a*/);
/* --- @accept@ --- *
*
reffd *(*accept)(int /*fd*/, addr_opts */*ao*/, const char */*desc*/);
- /* --- @freeopts@ --- *
+ /* --- @inittargopts@ --- *
*
- * Arguments: @addr_opts *ao@ = data block to remove
+ * Arguments: ---
*
- * Returns: ---
+ * Returns: A pointer to a protocol-specific data block for a connecter
*
- * Use: Throws away all the configuration data for an address type.
+ * Use: Creates a data block for a target. This is attached to the
+ * target data structure. Options can then be requested, and
+ * are added to the block when necessary.
*/
- void (*freeopts)(addr_opts */*ao*/);
+ addr_opts *(*inittargopts)(void);
- /* --- @bound@ --- *
+ /* --- @freetargopts@ --- *
*
- * Arguments: @addr *a@ = pointer to an address
- * @addr_opts *ao@ = pointer to attributes block
+ * Arguments: @addr_opts *ao@ = data block to remove
*
* Returns: ---
*
- * Use: Reports that a file descriptor has been (successfully) bound
- * to an address.
+ * Use: Throws away all the configuration data for an address type.
*/
- void (*bound)(addr */*a*/, addr_opts */*ao*/);
+ void (*freetargopts)(addr_opts */*ao*/);
- /* --- @unbind@ --- *
+ /* --- @connect@ --- *
*
- * Arguments: @addr *a@ = pointer to an address
+ * Arguments: @addr *a@ = destination address
+ * @addr_opts *ao@ = target address options
+ * @conn *c@ = connection structure
+ * @endpt *e@ = endpoint structure
*
- * Returns: ---
+ * Returns: Zero if OK, @-1@ on some error.
*
- * Use: Unbinds an address. This is used when tidying up. The main
- * purpose is to let the Unix-domain handler remove its socket
- * node from the filesystem.
+ * Use: Requests that a connection be made, or at least set in
+ * motion. An address may do one of these things:
+ *
+ * * Return @-1@.
+ *
+ * * Call @starget_connected@ with @-1@ or a connected file
+ * descriptor and the pointer @e@.
+ *
+ * * Call @conn_init@ or @conn_fd@, giving @starget_connected@
+ * and @e@ as the function to call.
*/
- void (*unbind)(addr */*a*/);
+ int (*connect)(addr */*a*/, addr_opts */*ao*/, conn */*c*/, endpt */*e*/);
} addr_ops;
/* -*-c-*-
*
- * $Id: conf.h,v 1.7 2002/02/22 23:42:56 mdw Exp $
+ * $Id: conf.h,v 1.8 2003/11/25 14:08:23 mdw Exp $
*
* Configuration parsing
*
/*----- Revision history --------------------------------------------------*
*
* $Log: conf.h,v $
+ * Revision 1.8 2003/11/25 14:08:23 mdw
+ * Debianization. Socket target options. Internet binding.
+ *
* Revision 1.7 2002/02/22 23:42:56 mdw
* `fw'-specific configuration code moved out. This file might become part
* of a library some day.
* because the option wasn't accepted. \
*/ \
\
- goto _conf_reject; \
+ goto _conf_reject; \
_conf_reject: \
if (_conf_state == CS_PLAIN) \
_conf_state = CS_UNKNOWN; \
-dnl -*-fundamental-*-
+dnl -*-m4-*-
dnl
-dnl $Id: configure.in,v 1.14 2003/05/17 12:33:55 mdw Exp $
+dnl $Id: configure.in,v 1.15 2003/11/25 14:08:23 mdw Exp $
dnl
dnl Configuration script for fw
dnl
dnl ----- Revision history --------------------------------------------------
dnl
dnl $Log: configure.in,v $
+dnl Revision 1.15 2003/11/25 14:08:23 mdw
+dnl Debianization. Socket target options. Internet binding.
+dnl
dnl Revision 1.14 2003/05/17 12:33:55 mdw
dnl Version bump.
dnl
mdw_CHECK_MANYLIBS(socket, socket)
mdw_CHECK_MANYLIBS(gethostbyname, nsl resolv)
-mdw_MLIB(1.7.0)
+mdw_MLIB(2.0.2)
AC_CHECK_FUNCS(inet_aton)
AC_CHECK_FUNCS(setrlimit)
--- /dev/null
+files tmp substvars *.substvars *.debhelper
+fw
--- /dev/null
+fw (1.2.7) experimental; urgency=low
+
+ * Debianization!
+
+ * Fix data corruption in chan.c.
+
+ * Socket target option support. Currently there's just bind address.
+
+ * Support binding to specific addresses for inet sources and targets.
+
+ -- Mark Wooding <mdw@nsict.org> Tue, 25 Nov 2003 14:07:42 +0000
--- /dev/null
+Source: fw
+Section: net
+Priority: extra
+Build-Depends: mlib-dev (>= 2.0.2), debhelper (>= 4.0.2)
+Maintainer: Mark Wooding <mdw@nsict.org>
+Standards-Version: 3.1.1
+
+Package: fw
+Architecture: any
+Depends: ${shlibs:Depends}
+Description: Excessive port forwarder
+ fw can forward connections to and from: TCP sockets, Unix-domain sockets,
+ locally-executed programs, and file descriptors. It can do host-based
+ access control. It will log incoming TCP connections by hostname and
+ username (as reported by identd on the connecting host). It subsumes the
+ basic functionality of inetd, cat, netcat and others. It runs as a
+ single nonblocking process.
--- /dev/null
+fw is copyright (c) 2003 Straylight/Edgeware.
+
+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 a copy of the GNU General Public License in
+/usr/share/common-licenses/GPL; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+USA.
--- /dev/null
+#! /usr/bin/make -f
+
+export DH_COMPAT = 4
+
+build:
+ rm -rf build deb-build
+ mkdir deb-build
+ cd deb-build; ../configure --prefix=/usr --mandir=/usr/share/man
+ make -C deb-build
+ touch build
+
+clean:
+ dh_clean
+ rm -rf deb-build build
+
+install: build
+ dh_clean
+ make -C deb-build install DESTDIR=`pwd`/debian/fw
+
+binary-indep:
+
+binary-arch: install
+ dh_testdir -a
+ dh_testroot -a
+ dh_compress -a
+ dh_installdocs -a
+ dh_strip -a
+ dh_shlibdeps -a
+ dh_gencontrol -a
+ dh_fixperms -a
+ dh_installdeb -a
+ dh_md5sums -a
+ dh_builddeb -a
+
+binary: binary-indep binary-arch
+
+source:
+ rm -rf deb-build/*.tar.gz deb-build/=deb=
+ make -C deb-build dist
+ mkdir deb-build/=deb=
+ cd deb-build/=deb=; tar xvfz ../*.tar.gz
+ d=`pwd`; cd ..; dpkg-source -i -b $$d/deb-build/=deb=/*
+ rm -rf deb-build/=deb=
+
+.PHONY: binary binary-arch binary-indep clean install source
/* -*-c-*-
*
- * $Id: inet.c,v 1.4 2002/01/13 14:49:56 mdw Exp $
+ * $Id: inet.c,v 1.5 2003/11/25 14:08:23 mdw Exp $
*
* Protocol specific definitions for IPv4 sockets
*
/*----- Revision history --------------------------------------------------*
*
* $Log: inet.c,v $
+ * Revision 1.5 2003/11/25 14:08:23 mdw
+ * Debianization. Socket target options. Internet binding.
+ *
* Revision 1.4 2002/01/13 14:49:56 mdw
* Conditional compilation for @getnetbyname@, since Cygwin doesn't have
* it.
#include <mLib/alloc.h>
#include <mLib/dstr.h>
+#include <mLib/fdflags.h>
#include <mLib/report.h>
#include <mLib/sub.h>
#include "acl.h"
#include "addr.h"
#include "conf.h"
+#include "fw.h"
#include "identify.h"
#include "inet.h"
#include "reffd.h"
#include "scan.h"
+#include "socket.h"
/*----- Data structures ---------------------------------------------------*/
typedef struct inet_opts {
addr_opts ao;
+ struct in_addr bind;
+} inet_opts;
+
+typedef struct inet_srcopts {
+ inet_opts io;
acl_entry *acl;
acl_entry **acltail;
-} inet_opts;
+} inet_srcopts;
+
+typedef struct inet_targopts {
+ inet_opts io;
+} inet_targopts;
+
+static inet_srcopts inet_globalsrc =
+ { { { 0 }, { INADDR_ANY } }, 0, &inet_globalsrc.acl };
+static inet_targopts inet_globaltarg =
+ { { { 0 }, { INADDR_ANY } } };
/*----- Protocol operations -----------------------------------------------*/
/* --- @initopts@ --- */
-static addr_opts *inet_initopts(void)
+static addr_opts *inet_initsrcopts(void)
{
- inet_opts *io = CREATE(inet_opts);
+ inet_srcopts *io = CREATE(inet_srcopts);
+ *io = inet_globalsrc;
io->acl = 0;
io->acltail = &io->acl;
- return (&io->ao);
+ return (&io->io.ao);
+}
+
+static addr_opts *inet_inittargopts(void)
+{
+ inet_targopts *io = CREATE(inet_targopts);
+ *io = inet_globaltarg;
+ return (&io->io.ao);
}
/* --- @option@ --- */
-static int inet_option(scanner *sc, addr_opts *ao)
+static void addropt(scanner *sc, inet_opts *io)
{
- inet_opts *io = (inet_opts *)ao;
+ dstr d = DSTR_INIT;
+ struct hostent *h;
- CONF_BEGIN(sc, "inet", "Internet socket")
+ token(sc);
+ if (sc->t == '=')
+ token(sc);
+ if (sc->t == CTOK_WORD && strcmp(sc->d.buf, "any") == 0)
+ io->bind.s_addr = INADDR_ANY;
+ else {
+ conf_name(sc, '.', &d);
+ if ((h = gethostbyname(d.buf)) == 0)
+ error(sc, "couldn't resolve address `%s'", d.buf);
+ memcpy(&io->bind, h->h_addr, sizeof(struct in_addr));
+ }
+}
+static int srcopt(scanner *sc, addr_opts *ao)
+{
+ inet_srcopts *io = (inet_srcopts *)ao;
unsigned act;
+ CONF_BEGIN(sc, "source", "Internet socket source")
+
+ /* --- Initialization --- */
+
+ if (!io) {
+ if (!inet_globalsrc.acltail)
+ inet_globalsrc.acltail = &inet_globalsrc.acl;
+ io = &inet_globalsrc;
+ }
+
+ /* --- Source address configuration --- */
+
+ if (strcmp(sc->d.buf, "addr") == 0) {
+ addropt(sc, &io->io);
+ CONF_ACCEPT;
+ }
+
/* --- Access control limitations --- */
if ((strcmp(sc->d.buf, "allow") == 0 && (act = ACL_ALLOW, 1)) ||
struct in_addr a, m;
dstr d = DSTR_INIT;
- /* --- Find the host or network address --- */
+ /* --- Find out what's going on --- */
token(sc);
if (sc->t == CTOK_WORD && strcmp(sc->d.buf, "from") == 0)
token(sc);
- conf_name(sc, '.', &d);
-#ifdef HAVE_GETNETBYNAME
- if ((n = getnetbyname(d.buf)) != 0)
- a.s_addr = htonl(n->n_net);
- else
-#endif
- if ((h = gethostbyname(d.buf)) == 0)
- error(sc, "couldn't resolve address `%s'", d.buf);
- else
- memcpy(&a, h->h_addr, sizeof(struct in_addr));
-
- /* --- Find the netmask, if any --- */
- if (sc->t != '/')
- m.s_addr = ~0ul;
- else {
+ if (sc->t == CTOK_WORD && strcmp(sc->d.buf, "priv-port") == 0) {
+ acl_addpriv(&io->acltail, act);
token(sc);
- DRESET(&d);
+ } else {
+ if (sc->t == CTOK_WORD && strcmp(sc->d.buf, "host") == 0)
+ token(sc);
+
+ /* --- Find the host or network address --- */
+
conf_name(sc, '.', &d);
- if (strchr(d.buf, '.') == 0) {
- int n = atoi(d.buf);
- if (n == 0)
- m.s_addr = 0;
+#ifdef HAVE_GETNETBYNAME
+ if ((n = getnetbyname(d.buf)) != 0)
+ a.s_addr = htonl(n->n_net);
+ else
+#endif
+ if ((h = gethostbyname(d.buf)) == 0)
+ error(sc, "couldn't resolve address `%s'", d.buf);
else
- m.s_addr = htonl((~0ul << (32 - n)) & 0xffffffff);
- } else {
+ memcpy(&a, h->h_addr, sizeof(struct in_addr));
+
+ /* --- Find the netmask, if any --- */
+
+ if (sc->t != '/')
+ m.s_addr = ~0ul;
+ else {
+ token(sc);
+ DRESET(&d);
+ conf_name(sc, '.', &d);
+ if (strchr(d.buf, '.') == 0) {
+ int n = atoi(d.buf);
+ if (n == 0)
+ m.s_addr = 0;
+ else
+ m.s_addr = htonl((~0ul << (32 - n)) & 0xffffffff);
+ } else {
#ifdef HAVE_INET_ATON
- if (!inet_aton(d.buf, &m))
- error(sc, "bad netmask `%s'", d.buf);
+ if (!inet_aton(d.buf, &m))
+ error(sc, "bad netmask `%s'", d.buf);
#else
- m.s_addr = inet_addr(d.buf);
+ m.s_addr = inet_addr(d.buf);
#endif
+ }
}
- }
- dstr_destroy(&d);
+ dstr_destroy(&d);
- /* --- Add the access control entry --- */
+ /* --- Add the access control entry --- */
- acl_add(io ? &io->acltail : 0, act, a, m);
+ acl_addhost(&io->acltail, act, a, m);
+ }
CONF_ACCEPT;
}
CONF_END;
}
+static int targopt(scanner *sc, addr_opts *ao)
+{
+ inet_targopts *io = (inet_targopts *)ao;
+
+ CONF_BEGIN(sc, "dest", "Internet socket target");
+ if (strcmp(sc->d.buf, "addr") == 0) {
+ addropt(sc, &io->io);
+ CONF_ACCEPT;
+ }
+ CONF_END;
+}
+
+static int inet_option(scanner *sc, addr_opts *ao, unsigned type)
+{
+ CONF_BEGIN(sc, "inet", "Internet socket");
+ if (type != ADDR_DEST && srcopt(sc, ao))
+ CONF_ACCEPT;
+ if (type != ADDR_SRC && targopt(sc, ao))
+ CONF_ACCEPT;
+ CONF_END;
+}
+
+/* --- @freeopts@ --- */
+
+static void inet_freesrcopts(addr_opts *ao)
+{
+ inet_srcopts *io = (inet_srcopts *)ao;
+ acl_free(io->acl);
+ DESTROY(io);
+}
+
+static void inet_freetargopts(addr_opts *ao)
+{
+ inet_targopts *io = (inet_targopts *)ao;
+ DESTROY(io);
+}
+
+/* --- @bind@ --- */
+
+static int inet_bind(addr *a, addr_opts *ao)
+{
+ inet_addrx *ia = (inet_addrx *)a;
+ inet_srcopts *io = (inet_srcopts *)ao;
+ struct sockaddr_in sin;
+ int opt = 1;
+ int fd;
+
+ if ((fd = socket(PF_INET, SOCK_STREAM, 0)) < 0)
+ goto fail_0;
+ setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
+ fdflags(fd, O_NONBLOCK, O_NONBLOCK, FD_CLOEXEC, FD_CLOEXEC);
+ sin = ia->sin;
+ sin.sin_addr = io->io.bind;
+ if (bind(fd, (struct sockaddr *)&sin, sizeof(ia->sin)))
+ goto fail_1;
+ return (fd);
+
+fail_1:
+ close(fd);
+fail_0:
+ return (-1);
+}
+
/* --- @accept@ --- */
static reffd *inet_accept(int fd, addr_opts *ao, const char *desc)
{
- inet_opts *io = (inet_opts *)ao;
+ inet_srcopts *io = (inet_srcopts *)ao;
int nfd;
id_req q;
size_t lsinsz = sizeof(q.lsin), rsinsz = sizeof(q.rsin);
+ int act = ACL_ALLOW;
/* --- Accept the new connection --- */
/* --- Find out whether this connection is allowed --- */
- if (!acl_check(io->acl, q.rsin.sin_addr)) {
+ if (!acl_check(io->acl, q.rsin.sin_addr, ntohs(q.rsin.sin_port), &act))
+ acl_check(inet_globalsrc.acl, q.rsin.sin_addr,
+ ntohs(q.rsin.sin_port), &act);
+ if (act != ACL_ALLOW) {
q.act = "refused";
- if (!(io->ao.f & ADDRF_NOLOG))
+ if (!(io->io.ao.f & ADDRF_NOLOG))
identify(&q);
REFFD_DEC(q.r);
return (0);
/* --- Everything seems to be OK --- */
q.act = "accepted";
- if (!(io->ao.f & ADDRF_NOLOG))
+ if (!(io->io.ao.f & ADDRF_NOLOG))
identify(&q);
return (q.r);
}
-/* --- @freeopts@ --- */
+/* --- @connect@ --- */
-static void inet_freeopts(addr_opts *ao)
+static int inet_connect(addr *a, addr_opts *ao, conn *c, endpt *e)
{
- inet_opts *io = (inet_opts *)ao;
- acl_free(io->acl);
- DESTROY(ao);
+ inet_addrx *ia = (inet_addrx *)a;
+ inet_targopts *io = (inet_targopts *)ao;
+ int fd;
+
+ if ((fd = socket(PF_INET, SOCK_STREAM, 0)) < 0)
+ goto fail_0;
+ if (io->io.bind.s_addr != INADDR_ANY) {
+ struct sockaddr_in sin;
+ memset(&sin, 0, sizeof(sin));
+ sin.sin_family = AF_INET;
+ sin.sin_addr = io->io.bind;
+ sin.sin_port = 0;
+ if (bind(fd, (struct sockaddr *)&sin, sizeof(sin)))
+ goto fail_1;
+ }
+ fdflags(fd, O_NONBLOCK, O_NONBLOCK, FD_CLOEXEC, FD_CLOEXEC);
+ return (conn_init(c, sel, fd, (struct sockaddr *)&ia->sin, sizeof(ia->sin),
+ starget_connected, e));
+fail_1:
+ close(fd);
+fail_0:
+ return (-1);
}
/* --- Ops table --- */
addr_ops inet_ops = {
- "inet", PF_INET,
+ "inet",
inet_read, inet_destroy, inet_print,
- inet_initopts, inet_option, inet_accept, inet_freeopts, 0, 0
+ inet_initsrcopts, inet_option, inet_freesrcopts,
+ inet_bind, 0, inet_accept,
+ inet_inittargopts, inet_freetargopts,
+ inet_connect
};
/*----- That's all, folks -------------------------------------------------*/
/* -*-c-*-
*
- * $Id: socket.c,v 1.9 2002/02/23 00:08:00 mdw Exp $
+ * $Id: socket.c,v 1.10 2003/11/25 14:08:23 mdw Exp $
*
* Socket source and target definitions
*
/*----- Revision history --------------------------------------------------*
*
* $Log: socket.c,v $
+ * Revision 1.10 2003/11/25 14:08:23 mdw
+ * Debianization. Socket target options. Internet binding.
+ *
* Revision 1.9 2002/02/23 00:08:00 mdw
* Fix stupid bugs from the listen(2) change.
*
/*----- Other persistent variables ----------------------------------------*/
-static addr_opts gao = { 0 };
+static addr_opts gsao = { 0 }, gtao = { 0 };
/*----- Parsing address types ---------------------------------------------*/
DESTROY(ee);
}
-/* --- @stept_go@ --- *
+/* --- @starget_connected@ --- *
*
* Arguments: @int fd@ = file descriptor now ready for use
* @void *p@ = pointer to an endpoint structure
* Use: Handles successful connection of the target endpoint.
*/
-static void stept_go(int fd, void *p)
+void starget_connected(int fd, void *p)
{
stept *e = p;
endpt_kill(&e->e);
} else {
reffd *r = reffd_init(fd);
+ int opt = 1;
REFFD_INC(r);
+ fdflags(fd, O_NONBLOCK, O_NONBLOCK, FD_CLOEXEC, FD_CLOEXEC);
+ setsockopt(fd, SOL_SOCKET, SO_OOBINLINE, &opt, sizeof(opt));
e->e.in = e->e.out = r;
e->e.f &= ~EPF_PENDING;
if (e->e.other)
ssource *ss = (ssource *)s;
ssource_opts *sso = ss ? &ss->o : &ssgo;
- CONF_BEGIN(sc, "socket", "socket")
+ CONF_BEGIN(sc, "socket", "socket source")
/* --- Make sure the next token is a word --- */
if (strcmp(sc->d.buf, "logging") == 0 ||
strcmp(sc->d.buf, "log") == 0) {
- addr_opts *ao = ss ? ss->ao : &gao;
+ addr_opts *ao = ss ? ss->ao : &gsao;
token(sc);
if (sc->t == '=')
token(sc);
/* --- Pass the option around the various address types --- */
if (ss) {
- if (ss->a->ops->option && ss->a->ops->option(sc, ss ? ss->ao : 0))
+ if (ss->a->ops->option && ss->a->ops->option(sc, ss->ao, ADDR_SRC))
CONF_ACCEPT;
} else {
addr_ops **a;
for (a = addrs; *a; a++) {
- if ((*a)->option && (*a)->option(sc, 0))
+ if ((*a)->option && (*a)->option(sc, 0, ADDR_GLOBAL))
CONF_ACCEPT;
}
}
ss->s.desc = 0;
ss->t = 0;
ss->a = getaddr(sc, ADDR_SRC);
- if (ss->a->ops->initopts)
- ss->ao = ss->a->ops->initopts();
+ if (ss->a->ops->initsrcopts)
+ ss->ao = ss->a->ops->initsrcopts();
else
ss->ao = CREATE(addr_opts);
- *ss->ao = gao;
+ *ss->ao = gsao;
ss->o = ssgo;
return (&ss->s);
}
static void ss_listen(ssource *ss)
{
- gen_addr *ga = (gen_addr *)ss->a;
int fd;
+ int opt = 1;
if (!(ss->ao->f & ADDRF_NOLOG))
fw_log(-1, "[%s] reattaching listener", ss->s.desc);
/* --- Make the socket --- */
- if ((fd = socket(ga->a.ops->pf, SOCK_STREAM, 0)) < 0) {
+ if ((fd = ss->a->ops->bind(ss->a, ss->ao)) < 0) {
fw_log(-1, "[%s] couldn't create socket: %s",
ss->s.desc, strerror(errno));
goto fail_0;
}
- /* --- Set it to allow address reuse --- */
-
- {
- int opt = 1;
- setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
- fdflags(fd, O_NONBLOCK, O_NONBLOCK, FD_CLOEXEC, FD_CLOEXEC);
- }
-
- /* --- Bind it to the right port --- */
-
- if (bind(fd, &ga->sa, ga->a.sz)) {
- fw_log(-1, "[%s] couldn't bind socket: %s", ss->s.desc, strerror(errno));
- goto fail_1;
- }
- if (ga->a.ops->bound)
- ga->a.ops->bound(&ga->a, ss->ao);
-
/* --- Set it to listen for connections --- */
+ setsockopt(fd, SOL_SOCKET, SO_OOBINLINE, &opt, sizeof(opt));
+ fdflags(fd, O_NONBLOCK, O_NONBLOCK, FD_CLOEXEC, FD_CLOEXEC);
if (listen(fd, ss->o.listen)) {
fw_log(-1, "[%s] couldn't listen on socket: %s",
ss->s.desc, strerror(errno));
{
ssource *ss = (ssource *)s;
int fd;
+ int opt = 1;
ss->t = t;
/* --- Initialize the socket for listening --- */
- {
- gen_addr *ga = (gen_addr *)ss->a;
-
- /* --- Make the socket --- */
-
- if ((fd = socket(ga->a.ops->pf, SOCK_STREAM, 0)) < 0)
- error(sc, "couldn't create socket: %s", strerror(errno));
-
- /* --- Set it to allow address reuse --- */
+ if ((fd = ss->a->ops->bind(ss->a, ss->ao)) < 0)
+ error(sc, "couldn't bind socket `%s': %s", ss->s.desc, strerror(errno));
- {
- int opt = 1;
- setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
- fdflags(fd, O_NONBLOCK, O_NONBLOCK, FD_CLOEXEC, FD_CLOEXEC);
- }
-
- /* --- Bind it to the right port --- */
-
- if (bind(fd, &ga->sa, ga->a.sz))
- error(sc, "couldn't bind to %s: %s", ss->s.desc, strerror(errno));
- if (ga->a.ops->bound)
- ga->a.ops->bound(&ga->a, ss->ao);
-
- /* --- Set it to listen for connections --- */
+ /* --- Set it to listen for connections --- */
- if (listen(fd, ss->o.listen))
- error(sc, "couldn't listen on socket: %s", strerror(errno));
+ setsockopt(fd, SOL_SOCKET, SO_OOBINLINE, &opt, sizeof(opt));
+ fdflags(fd, O_NONBLOCK, O_NONBLOCK, FD_CLOEXEC, FD_CLOEXEC);
+ if (listen(fd, ss->o.listen)) {
+ error(sc, "couldn't listen on socket `%s': %s",
+ ss->s.desc, strerror(errno));
}
/* --- We're ready to go now --- */
if (ss->a->ops->unbind)
ss->a->ops->unbind(ss->a);
}
- if (ss->a->ops->freeopts)
- ss->a->ops->freeopts(ss->ao);
+ if (ss->a->ops->freesrcopts)
+ ss->a->ops->freesrcopts(ss->ao);
else
DESTROY(ss->ao);
xfree(ss->s.desc);
/*----- Target definition -------------------------------------------------*/
+/* --- @options@ --- */
+
+static int starget_option(target *t, scanner *sc)
+{
+ starget *st = (starget *)t;
+
+ CONF_BEGIN(sc, "starget", "socket target")
+
+ /* --- Pass the option around the various address types --- */
+
+ if (st) {
+ if (st->a->ops->option && st->a->ops->option(sc, st->ao, ADDR_DEST))
+ CONF_ACCEPT;
+ }
+ /* We'd have done it already if it was global */
+
+ /* --- Done --- */
+
+ CONF_END;
+}
+
/* --- @read@ --- */
static target *starget_read(scanner *sc)
st = CREATE(starget);
st->t.ops = &starget_ops;
st->a = getaddr(sc, ADDR_DEST);
+ if (st->a->ops->inittargopts)
+ st->ao = st->a->ops->inittargopts();
+ else
+ st->ao = CREATE(addr_opts);
+ *st->ao = gtao;
dstr_puts(&d, "socket.");
st->a->ops->print(st->a, ADDR_DEST, &d);
st->t.desc = xstrdup(d.buf);
{
starget *st = (starget *)t;
stept *e = CREATE(stept);
- int fd;
- gen_addr *ga = (gen_addr *)st->a;
- int opt;
- if ((fd = socket(st->a->ops->pf, SOCK_STREAM, 0)) < 0)
- return (0);
- setsockopt(fd, SOL_SOCKET, SO_OOBINLINE, &opt, sizeof(opt));
- fdflags(fd, O_NONBLOCK, O_NONBLOCK, FD_CLOEXEC, FD_CLOEXEC);
e->e.ops = &stept_ops;
e->e.other = 0;
e->e.f = EPF_FILE | EPF_PENDING;
e->e.t = 0;
e->desc = xstrdup(desc);
-
- if (conn_init(&e->c, sel, fd, &ga->sa, ga->a.sz, stept_go, e)) {
- fw_log(-1, "[%s] connection failed: %s", e->desc, strerror(errno));
+ if (st->a->ops->connect(st->a, st->ao, &e->c, &e->e)) {
+ fw_log(-1, "[%s] couldn't connect: %s", e->desc, strerror(errno));
DESTROY(e);
return (0);
}
static void starget_destroy(target *t)
{
starget *st = (starget *)t;
+ if (st->a->ops->freetargopts)
+ st->a->ops->freetargopts(st->ao);
+ else
+ DESTROY(st->ao);
st->a->ops->destroy(st->a);
xfree(st->t.desc);
DESTROY(st);
target_ops starget_ops = {
"socket",
- 0, starget_read, starget_create, starget_destroy
+ starget_option, starget_read, starget_create, starget_destroy
};
/*----- That's all, folks -------------------------------------------------*/
/* -*-c-*-
*
- * $Id: socket.h,v 1.1 1999/07/26 23:33:32 mdw Exp $
+ * $Id: socket.h,v 1.2 2003/11/25 14:08:23 mdw Exp $
*
* Socket source and target definitions
*
/*----- Revision history --------------------------------------------------*
*
* $Log: socket.h,v $
+ * Revision 1.2 2003/11/25 14:08:23 mdw
+ * Debianization. Socket target options. Internet binding.
+ *
* Revision 1.1 1999/07/26 23:33:32 mdw
* New sources and targets.
*
extern source_ops ssource_ops;
extern target_ops starget_ops;
+/*----- Functions provided ------------------------------------------------*/
+
+/* --- @starget_connected@ --- *
+ *
+ * Arguments: @int fd@ = file descriptor now ready for use
+ * @void *p@ = pointer to an endpoint structure
+ *
+ * Returns: ---
+ *
+ * Use: Handles successful connection of the target endpoint.
+ */
+
+extern void starget_connected(int /*fd*/, void */*p*/);
+
/*----- That's all, folks -------------------------------------------------*/
#ifdef __cplusplus
/* -*-c-*-
*
- * $Id: target.h,v 1.1 1999/07/26 23:33:01 mdw Exp $
+ * $Id: target.h,v 1.2 2003/11/25 14:08:23 mdw Exp $
*
* Description of forwarding targets
*
/*----- Revision history --------------------------------------------------*
*
* $Log: target.h,v $
+ * Revision 1.2 2003/11/25 14:08:23 mdw
+ * Debianization. Socket target options. Internet binding.
+ *
* Revision 1.1 1999/07/26 23:33:01 mdw
* Infrastructure for the new design.
*
/* --- @option@ --- *
*
- * Arguments: @scanner *sc@ = scanner to read from
- * @target *t@ = pointer to target object, or zero if global
+ * Arguments: @target *t@ = pointer to target object, or zero if global
+ * @scanner *sc@ = scanner to read from
*
* Returns: Nonzero to claim the option.
*
/* -*-c-*-
*
- * $Id: un.c,v 1.5 2002/02/22 23:43:32 mdw Exp $
+ * $Id: un.c,v 1.6 2003/11/25 14:08:23 mdw Exp $
*
* Protocol specific definitions for Unix-domain sockets
*
/*----- Revision history --------------------------------------------------*
*
* $Log: un.c,v $
+ * Revision 1.6 2003/11/25 14:08:23 mdw
+ * Debianization. Socket target options. Internet binding.
+ *
* Revision 1.5 2002/02/22 23:43:32 mdw
* Call @xfree@ rather than @free@.
*
#include "fw.h"
#include "reffd.h"
#include "scan.h"
+#include "socket.h"
#include "un.h"
/*----- Data structures ---------------------------------------------------*/
/* --- @option@ --- */
-static int un_option(scanner *sc, addr_opts *ao)
+static int srcopt(scanner *sc, addr_opts *ao)
{
un_opts *uo = (un_opts *)ao;
CONF_BEGIN(sc, "unix", "Unix domain socket")
CONF_END;
}
+static int un_option(scanner *sc, addr_opts *ao, unsigned type)
+{
+ CONF_BEGIN(sc, "unix", "Unix domain socket");
+ if (type != ADDR_DEST && srcopt(sc, ao))
+ CONF_ACCEPT;
+ CONF_END;
+}
+
/* --- @accept@ --- */
static reffd *un_accept(int fd, addr_opts *ao, const char *desc)
DESTROY(uo);
}
-/* --- @bound@ --- */
+/* --- @bind@ --- */
-static void un_bound(addr *a, addr_opts *ao)
+static int un_bind(addr *a, addr_opts *ao)
{
un_addr *ua = (un_addr *)a;
un_opts *uo = (un_opts *)ao;
- if (fattr_apply(ua->sun.sun_path, &uo->f)) {
- dstr d = DSTR_INIT;
- un_print(a, ADDR_SRC, &d);
- fw_log(-1, "[%s] couldn't apply file attributes: %s",
- d.buf, strerror(errno));
- dstr_destroy(&d);
- }
+ int fd;
+
+ if ((fd = socket(PF_UNIX, SOCK_STREAM, 0)) < 0)
+ goto fail_0;
+ if (bind(fd, (struct sockaddr *)&ua->sun, sizeof(ua->sun)))
+ goto fail_1;
+ if (fattr_apply(ua->sun.sun_path, &uo->f))
+ goto fail_1;
+ return (fd);
+
+fail_1:
+ close(fd);
+fail_0:
+ return (-1);
}
/* --- @unbind@ --- */
unlink(ua->sun.sun_path);
}
+/* --- @connect@ --- */
+
+static int un_connect(addr *a, addr_opts *ao, conn *c, endpt *e)
+{
+ un_addr *ua = (un_addr *)a;
+ int fd;
+
+ if ((fd = socket(PF_UNIX, SOCK_STREAM, 0)) < 0)
+ goto fail_0;
+ return (conn_init(c, sel, fd, (struct sockaddr *)&ua->sun, sizeof(ua->sun),
+ starget_connected, e));
+fail_0:
+ return (-1);
+}
+
/* --- Protocol definition --- */
addr_ops un_ops = {
- "unix", PF_UNIX,
+ "unix",
un_read, un_destroy, un_print,
- un_initopts, un_option, un_accept, un_freeopts, un_bound, un_unbind
+ un_initopts, un_option, un_freeopts, un_bind, un_unbind, un_accept,
+ 0, 0, un_connect
};
/*----- That's all, folks -------------------------------------------------*/