X-Git-Url: https://git.distorted.org.uk/~mdw/fwd/blobdiff_plain/08cb0dd89765683f47206905c9116b73949fee63..0ac54f22a766f068db98e1caecbc913cb0cfd191:/inet.c 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 -------------------------------------------------*/