From 0ac54f22a766f068db98e1caecbc913cb0cfd191 Mon Sep 17 00:00:00 2001 From: mdw Date: Tue, 25 Nov 2003 14:08:23 +0000 Subject: [PATCH] Debianization. Socket target options. Internet binding. --- .cvsignore | 1 + Makefile.am | 9 +- acl.c | 158 ++++++++++++++++++++++----------- acl.h | 56 +++++++++--- addr.h | 111 ++++++++++++++++------- conf.h | 7 +- configure.in | 9 +- debian/.cvsignore | 2 + debian/changelog | 11 +++ debian/control | 17 ++++ debian/copyright | 16 ++++ debian/rules | 45 ++++++++++ inet.c | 258 +++++++++++++++++++++++++++++++++++++++++++----------- socket.c | 133 ++++++++++++++-------------- socket.h | 19 +++- target.h | 9 +- un.c | 61 ++++++++++--- 17 files changed, 691 insertions(+), 231 deletions(-) create mode 100644 debian/.cvsignore create mode 100644 debian/changelog create mode 100644 debian/control create mode 100644 debian/copyright create mode 100755 debian/rules diff --git a/.cvsignore b/.cvsignore index 19a3c54..4b605eb 100644 --- a/.cvsignore +++ b/.cvsignore @@ -5,3 +5,4 @@ build config.h.in configure stamp-h.in +deb-build diff --git a/Makefile.am b/Makefile.am index 2c270c7..c9598c6 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,6 +1,6 @@ ## -*-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 ## @@ -28,6 +28,9 @@ ##----- 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. ## @@ -49,7 +52,9 @@ AUTOMAKE_OPTIONS = foreign 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 \ diff --git a/acl.c b/acl.c index 059ec9c..29dd2db 100644 --- a/acl.c +++ b/acl.c @@ -1,6 +1,6 @@ /* -*-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 * @@ -29,6 +29,9 @@ /*----- 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. * @@ -61,38 +64,122 @@ #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@ --- * @@ -107,14 +194,10 @@ int acl_check(acl_entry *a, struct in_addr addr) 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); } } @@ -133,33 +216,8 @@ void acl_free(acl_entry *a) 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 -------------------------------------------------*/ diff --git a/acl.h b/acl.h index 21f398d..373df4b 100644 --- a/acl.h +++ b/acl.h @@ -1,6 +1,6 @@ /* -*-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 * @@ -29,6 +29,9 @@ /*----- 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. * @@ -61,27 +64,46 @@ 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@ --- * * @@ -106,7 +128,7 @@ extern void acl_dump(acl_entry */*a*/, FILE */*fp*/); 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 @@ -114,11 +136,25 @@ extern void acl_free(acl_entry */*a*/); * * 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 -------------------------------------------------*/ diff --git a/addr.h b/addr.h index cc5b790..adc4cd1 100644 --- a/addr.h +++ b/addr.h @@ -1,6 +1,6 @@ /* -*-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 * @@ -29,6 +29,9 @@ /*----- 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. * @@ -50,11 +53,16 @@ #include #include +#include #ifndef REFFD_H # include "reffd.h" #endif +#ifndef ENDPT_H +# include "endpt.h" +#endif + #ifndef SCAN_H # include "scan.h" #endif @@ -73,11 +81,6 @@ typedef struct addr { size_t sz; } addr; -typedef struct gen_addr { - addr a; - struct sockaddr sa; -} gen_addr; - #define ADDRSZ(sz) (sizeof(addr) + (sz)) /* --- Address configuration --- * @@ -99,14 +102,14 @@ typedef struct addr_opts { 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@ --- * * @@ -145,7 +148,7 @@ typedef struct addr_ops { void (*print)(addr */*a*/, unsigned /*type*/, dstr */*d*/); - /* --- @initopts@ --- * + /* --- @initsrcopts@ --- * * * Arguments: --- * @@ -156,19 +159,57 @@ typedef struct addr_ops { * 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@ --- * * @@ -183,42 +224,52 @@ typedef struct addr_ops { 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; diff --git a/conf.h b/conf.h index f9e25e9..7b656e0 100644 --- a/conf.h +++ b/conf.h @@ -1,6 +1,6 @@ /* -*-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 * @@ -29,6 +29,9 @@ /*----- 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. @@ -232,7 +235,7 @@ extern int conf_prefix(scanner */*sc*/, const char */*p*/); * because the option wasn't accepted. \ */ \ \ - goto _conf_reject; \ + goto _conf_reject; \ _conf_reject: \ if (_conf_state == CS_PLAIN) \ _conf_state = CS_UNKNOWN; \ diff --git a/configure.in b/configure.in index 6b7f0f3..446e361 100644 --- a/configure.in +++ b/configure.in @@ -1,6 +1,6 @@ -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 @@ -28,6 +28,9 @@ dnl Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 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 @@ -73,7 +76,7 @@ mdw_DECL_ENVIRON 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) diff --git a/debian/.cvsignore b/debian/.cvsignore new file mode 100644 index 0000000..fd2495d --- /dev/null +++ b/debian/.cvsignore @@ -0,0 +1,2 @@ +files tmp substvars *.substvars *.debhelper +fw diff --git a/debian/changelog b/debian/changelog new file mode 100644 index 0000000..edbda91 --- /dev/null +++ b/debian/changelog @@ -0,0 +1,11 @@ +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 Tue, 25 Nov 2003 14:07:42 +0000 diff --git a/debian/control b/debian/control new file mode 100644 index 0000000..d0a1a28 --- /dev/null +++ b/debian/control @@ -0,0 +1,17 @@ +Source: fw +Section: net +Priority: extra +Build-Depends: mlib-dev (>= 2.0.2), debhelper (>= 4.0.2) +Maintainer: Mark Wooding +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. diff --git a/debian/copyright b/debian/copyright new file mode 100644 index 0000000..6401701 --- /dev/null +++ b/debian/copyright @@ -0,0 +1,16 @@ +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. diff --git a/debian/rules b/debian/rules new file mode 100755 index 0000000..d592b5b --- /dev/null +++ b/debian/rules @@ -0,0 +1,45 @@ +#! /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 diff --git a/inet.c b/inet.c index f98c7fa..70e5c90 100644 --- a/inet.c +++ b/inet.c @@ -1,6 +1,6 @@ /* -*-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 * @@ -29,6 +29,9 @@ /*----- 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. @@ -64,16 +67,19 @@ #include #include +#include #include #include #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 ---------------------------------------------------*/ @@ -84,9 +90,23 @@ typedef struct inet_addrx { 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 -----------------------------------------------*/ @@ -168,24 +188,64 @@ static void inet_print(addr *a, unsigned type, dstr *d) /* --- @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)) || @@ -195,50 +255,61 @@ static int inet_option(scanner *sc, addr_opts *ao) 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; } @@ -247,14 +318,78 @@ static int inet_option(scanner *sc, addr_opts *ao) 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 --- */ @@ -269,9 +404,12 @@ static reffd *inet_accept(int fd, addr_opts *ao, const char *desc) /* --- 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); @@ -280,26 +418,48 @@ static reffd *inet_accept(int fd, addr_opts *ao, const char *desc) /* --- 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 -------------------------------------------------*/ diff --git a/socket.c b/socket.c index 87b3d96..5f1a731 100644 --- a/socket.c +++ b/socket.c @@ -1,6 +1,6 @@ /* -*-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 * @@ -29,6 +29,9 @@ /*----- 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. * @@ -153,7 +156,7 @@ static addr_ops *addrs[] = { &inet_ops, &un_ops, 0 }; /*----- Other persistent variables ----------------------------------------*/ -static addr_opts gao = { 0 }; +static addr_opts gsao = { 0 }, gtao = { 0 }; /*----- Parsing address types ---------------------------------------------*/ @@ -269,7 +272,7 @@ static void stept_close(endpt *e) DESTROY(ee); } -/* --- @stept_go@ --- * +/* --- @starget_connected@ --- * * * Arguments: @int fd@ = file descriptor now ready for use * @void *p@ = pointer to an endpoint structure @@ -279,7 +282,7 @@ static void stept_close(endpt *e) * 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; @@ -288,7 +291,10 @@ static void stept_go(int fd, void *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) @@ -315,7 +321,7 @@ static int ssource_option(source *s, scanner *sc) 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 --- */ @@ -360,7 +366,7 @@ static int ssource_option(source *s, scanner *sc) 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); @@ -374,12 +380,12 @@ static int ssource_option(source *s, scanner *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; } } @@ -401,11 +407,11 @@ static source *ssource_read(scanner *sc) 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); } @@ -506,39 +512,24 @@ static void ss_accept(int fd, unsigned mode, void *p) 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)); @@ -569,6 +560,7 @@ static void ssource_attach(source *s, scanner *sc, target *t) { ssource *ss = (ssource *)s; int fd; + int opt = 1; ss->t = t; @@ -586,33 +578,16 @@ static void ssource_attach(source *s, scanner *sc, target *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 --- */ @@ -635,8 +610,8 @@ static void ssource_destroy(source *s) 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); @@ -656,6 +631,27 @@ source_ops ssource_ops = { /*----- 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) @@ -667,6 +663,11 @@ 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); @@ -688,22 +689,14 @@ static endpt *starget_create(target *t, const char *desc) { 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); } @@ -716,6 +709,10 @@ static endpt *starget_create(target *t, const char *desc) 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); @@ -725,7 +722,7 @@ static void starget_destroy(target *t) target_ops starget_ops = { "socket", - 0, starget_read, starget_create, starget_destroy + starget_option, starget_read, starget_create, starget_destroy }; /*----- That's all, folks -------------------------------------------------*/ diff --git a/socket.h b/socket.h index b64bd5e..e85d455 100644 --- a/socket.h +++ b/socket.h @@ -1,6 +1,6 @@ /* -*-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 * @@ -29,6 +29,9 @@ /*----- 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. * @@ -56,6 +59,20 @@ 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 diff --git a/target.h b/target.h index 5077c39..862527a 100644 --- a/target.h +++ b/target.h @@ -1,6 +1,6 @@ /* -*-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 * @@ -29,6 +29,9 @@ /*----- 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. * @@ -69,8 +72,8 @@ typedef struct target_ops { /* --- @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. * diff --git a/un.c b/un.c index e120f95..e415256 100644 --- a/un.c +++ b/un.c @@ -1,6 +1,6 @@ /* -*-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 * @@ -29,6 +29,9 @@ /*----- 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@. * @@ -77,6 +80,7 @@ #include "fw.h" #include "reffd.h" #include "scan.h" +#include "socket.h" #include "un.h" /*----- Data structures ---------------------------------------------------*/ @@ -141,7 +145,7 @@ static addr_opts *un_initopts(void) /* --- @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") @@ -152,6 +156,14 @@ static int un_option(scanner *sc, addr_opts *ao) 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) @@ -189,19 +201,26 @@ static void un_freeopts(addr_opts *ao) 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@ --- */ @@ -212,12 +231,28 @@ static void un_unbind(addr *a) 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 -------------------------------------------------*/ -- 2.11.0