home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
ftp.ee.lbl.gov
/
2014.05.ftp.ee.lbl.gov.tar
/
ftp.ee.lbl.gov
/
acld-1.11.tar.gz
/
acld-1.11.tar
/
acld-1.11
/
server.c
< prev
next >
Wrap
C/C++ Source or Header
|
2012-02-07
|
15KB
|
615 lines
/*
* Copyright (c) 2004, 2006, 2007, 2008, 2009, 2010, 2011
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that: (1) source code distributions
* retain the above copyright notice and this paragraph in its entirety, (2)
* distributions including binary code include the above copyright notice and
* this paragraph in its entirety in the documentation or other materials
* provided with the distribution, and (3) all advertising materials mentioning
* features or use of this software display the following acknowledgement:
* ``This product includes software developed by the University of California,
* Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
* the University nor the names of its contributors may be used to endorse
* or promote products derived from this software without specific prior
* written permission.
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*/
#ifndef lint
static const char rcsid[] =
"@(#) $Id: server.c 806 2012-02-08 03:40:06Z leres $ (LBL)";
#endif
#include <sys/types.h>
#include <sys/time.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sysexits.h>
#include <syslog.h>
#include <unistd.h>
#include "acld.h"
#include "cf.h"
#include "child.h"
#include "server.h"
/* Forwards */
void servercompactone(struct state *, struct acllist *);
void servercompactport(struct state *, struct acllist *);
void servercompactpermithostport(struct state *, struct acllist *);
void serverdroprestore(struct state *, struct req *);
void servermoveacl(struct state *, struct acllist *, struct acl *, int);
void
serverayt(struct state *sp)
{
struct req *rp;
rp = new(1, sizeof(*rp), "serverayt: req");
rp->state = RSTATE_PENDING;
rp->type = REQ_AYT;
rp->cmd = "ayt";
/* Arrival timestamp */
getts(&rp->ats);
/* Append the new request to end of list */
appendreq(&sp->req, rp);
}
void
servercompact(struct state *sp)
{
int i;
struct acllist *ap;
struct cf *cf;
cf = sp->cf;
for (i = 0, ap = cf->c_acllist; i < cf->c_acllistlen; ++i, ++ap) {
if (ap->compactseq > 0) {
servercompactone(sp, ap);
break;
}
if (ap->compactportseq > 0) {
servercompactport(sp, ap);
break;
}
if (ap->compactpermithostportseq > 0) {
servercompactpermithostport(sp, ap);
break;
}
}
/* Reschedule if we're not done yet */
if (ap->compactseq > 0 ||
ap->compactportseq > 0 ||
ap->compactpermithostportseq > 0) {
timerset(&sp->t_compact, 0);
return;
}
/* Terminado! */
timerreset(&sp->t_compact);
/* Schedule a sync */
if (sp->cf->c_sync_secs > 0 && timercheck(&sp->t_sync) < 0)
timerset(&sp->t_sync, sp->cf->c_sync_secs);
lg(LOG_INFO, "servercompact: finished compacting ACL %s", ap->name);
/* Tell client the good news */
if (ap->compactclient != NULL) {
/*
* XXX What happens if the client goes away
* before we get here?
*/
if (ap->compactreq == NULL)
abort();
clientsend(ap->compactclient, ap->compactreq);
freereq(ap->compactreq);
ap->compactclient = NULL;
ap->compactreq = NULL;
}
}
void
servercompactone(struct state *sp, struct acllist *ap)
{
int n, inc, seq;
struct acl *al;
n = ap->acllen;
if (sp->cf->c_incrseq) {
al = ap->acl;
inc = 1;
} else {
al = ap->acl + n - 1;
inc = -1;
}
/* Host block range */
for (; n > 0; --n, al += inc) {
if (al->seq < sp->cf->c_lowseq || al->seq > sp->cf->c_highseq)
continue;
if (sp->cf->c_incrseq) {
if (al->seq < ap->compactseq)
continue;
} else {
if (al->seq > ap->compactseq)
continue;
}
if (al->type == ATYPE_UNKNOWN) {
ap->compactseq = 0;
timerreset(&sp->t_compact);
lg(LOG_ERR, "servercompactone: Can't handle"
" unknown ACL type (seq %d)", al->seq);
return;
}
seq = ap->compactseq;
ap->compactseq += inc;
if (al->seq != seq) {
/* XXX Check to see if it's in use? */
servermoveacl(sp, ap, al, seq);
return;
}
/* XXX paranoid */
if (sp->cf->c_incrseq) {
if (ap->compactseq >= sp->cf->c_highseq)
abort();
} else {
if (ap->compactseq <= sp->cf->c_lowseq)
abort();
}
}
/* If we got here we're done */
ap->lastseq = ap->compactseq - inc;
ap->compactseq = 0;
}
void
servercompactport(struct state *sp, struct acllist *ap)
{
int n, seq;
struct acl *al;
/* Port block range */
for (n = ap->acllen, al = ap->acl; n > 0; --n, ++al) {
if (al->seq < sp->cf->c_lowportseq ||
al->seq > sp->cf->c_highportseq)
continue;
if (al->seq < ap->compactportseq)
continue;
if (al->type == ATYPE_UNKNOWN) {
ap->compactportseq = 0;
timerreset(&sp->t_compact);
lg(LOG_ERR, "servercompactport: Can't handle"
" unknown ACL type (seq %d)", al->seq);
return;
}
seq = ap->compactportseq;
++ap->compactportseq;
if (al->seq != seq) {
/* XXX Check to see if it's in use? */
servermoveacl(sp, ap, al, seq);
return;
}
/* XXX paranoid */
if (ap->compactportseq >= sp->cf->c_highportseq)
abort();
}
/* If we got here we're done */
ap->lastportseq = ap->compactportseq - 1;
ap->compactportseq = 0;
}
void
servercompactpermithostport(struct state *sp, struct acllist *ap)
{
int n, seq;
struct acl *al;
/* Port block range */
for (n = ap->acllen, al = ap->acl; n > 0; --n, ++al) {
if (al->seq < sp->cf->c_lowpermithostportseq ||
al->seq > sp->cf->c_highpermithostportseq)
continue;
if (al->seq < ap->compactpermithostportseq)
continue;
if (al->type == ATYPE_UNKNOWN) {
ap->compactpermithostportseq = 0;
timerreset(&sp->t_compact);
lg(LOG_ERR, "servercompactport: Can't handle"
" unknown ACL type (seq %d)", al->seq);
return;
}
seq = ap->compactpermithostportseq;
++ap->compactpermithostportseq;
if (al->seq != seq) {
/* XXX Check to see if it's in use? */
servermoveacl(sp, ap, al, seq);
return;
}
/* XXX paranoid */
if (ap->compactpermithostportseq >=
sp->cf->c_highpermithostportseq)
abort();
}
/* If we got here we're done */
ap->lastpermithostportseq = ap->compactpermithostportseq - 1;
ap->compactpermithostportseq = 0;
}
void
servermoveacl(struct state *sp, struct acllist *ap, struct acl *al, int seq)
{
struct req *rp;
int remreq, addreq;
char compactstr[] = "compact";
switch (al->type) {
case ATYPE_BLOCKHOST:
remreq = REQ_RESTORE;
addreq = REQ_DROP;
break;
case ATYPE_BLOCKNET:
remreq = REQ_RESTORE;
addreq = REQ_DROP;
break;
case ATYPE_BLOCKHOSTHOST:
remreq = REQ_RESTOREHOSTHOST;
addreq = REQ_BLOCKHOSTHOST;
break;
case ATYPE_BLOCKUDPPORT:
remreq = REQ_RESTOREUDPPORT;
addreq = REQ_DROPUDPPORT;
break;
case ATYPE_BLOCKTCPPORT:
remreq = REQ_RESTORETCPPORT;
addreq = REQ_DROPTCPPORT;
break;
case ATYPE_PERMITUDPDSTHOSTPORT:
remreq = REQ_UNPERMITUDPDSTHOSTPORT;
addreq = REQ_PERMITUDPDSTHOSTPORT;
break;
case ATYPE_PERMITTCPDSTHOSTPORT:
remreq = REQ_UNPERMITTCPDSTHOSTPORT;
addreq = REQ_PERMITTCPDSTHOSTPORT;
break;
case ATYPE_BLOCKTCPDSTHOSTPORT:
remreq = REQ_RESTORETCPDSTHOSTPORT;
addreq = REQ_DROPTCPDSTHOSTPORT;
break;
default:
lg(LOG_ERR, "servermoveacl: bad type %s",
val2str(str2acl, al->type));
exit(EX_SOFTWARE);
}
rp = new(1, sizeof(*rp), "servermoveacl: req 1");
rp->state = RSTATE_PENDING;
rp->type = remreq;
rp->cmd = val2str(cmd2req, rp->type);
rp->acl = *al;
rp->aclname = strsave(ap->name);
aclcopy(&rp->acl, al);
rp->payload.buf = compactstr;
rp->payload.len = sizeof(compactstr) - 1;
rp->payload.size = 0;
getts(&rp->ats);
appendreq(&sp->req, rp);
/* Change the sequence number */
al->seq = seq;
rp = new(1, sizeof(*rp), "servermoveacl: req 2");
rp->state = RSTATE_PENDING;
rp->type = addreq;
rp->cmd = val2str(cmd2req, rp->type);
rp->acl = *al;
rp->aclname = strsave(ap->name);
aclcopy(&rp->acl, al);
rp->payload.buf = compactstr;
rp->payload.len = sizeof(compactstr) - 1;
rp->payload.size = 0;
getts(&rp->ats);
appendreq(&sp->req, rp);
}
/* XXX unfortunately, this duplicates a lot of childdroprestore() */
void
serverdroprestore(struct state *sp, struct req *rp)
{
struct acllist *ap;
struct acl *al;
char buf[32];
/* XXX server should normally supply the sequence number */
if (rp->acl.seq == 0) {
lg(LOG_ERR, "serverdroprestore: seq number shouldn't be zero");
rp->state = RSTATE_DONE;
getts(&rp->cts);
return;
}
/* Find ACL list */
switch (rp->acl.type) {
case ATYPE_BLOCKHOST:
case ATYPE_BLOCKNET:
case ATYPE_BLOCKHOSTHOST:
case ATYPE_BLOCKTCPDSTHOSTPORT:
/* By address */
ap = aclfindlistbyaddr(sp->cf, &rp->acl.addr1);
if (ap == NULL) {
lg(LOG_ERR,
"serverdroprestore: can't find acllist for %s",
addr2str(&rp->acl.addr1));
rp->state = RSTATE_DONE;
getts(&rp->cts);
return;
}
rp->acllist = ap;
break;
case ATYPE_BLOCKUDPPORT:
case ATYPE_BLOCKTCPPORT:
/* By ACL name */
ap = aclfindlistbyname(sp->cf, rp->aclname);
if (ap == NULL) {
lg(LOG_ERR,
"serverdroprestore: can't find acllist for %s",
rp->acl.port1);
rp->state = RSTATE_DONE;
getts(&rp->cts);
return;
}
rp->acllist = ap;
break;
case ATYPE_PERMITUDPDSTHOSTPORT:
case ATYPE_PERMITTCPDSTHOSTPORT:
/* Use default ACL list for permit guys */
ap = aclfindlistdefault(sp->cf, &rp->acl.addr1);
if (ap == NULL) {
lg(LOG_ERR,
"serverdroprestore: can't find acllist for %s",
addr2str(&rp->acl.addr1));
rp->state = RSTATE_DONE;
getts(&rp->cts);
return;
}
rp->acllist = ap;
break;
default:
lg(LOG_ERR, "ACL type %d not implemented", rp->acl.type);
rp->state = RSTATE_DONE;
getts(&rp->cts);
return;
}
/*
* Since we're just changing the sequence number, and we
* don't remove the ACL, it should always exist.
*/
al = aclfindacl(ap, &rp->acl, 0);
switch (rp->type) {
case REQ_DROP:
case REQ_RESTORE:
if (al == NULL) {
lg(LOG_ERR, "serverdroprestore:"
" %s wasn't already blocked in ACL %s!",
addr2str(&rp->acl.addr1), ap->name);
rp->state = RSTATE_DONE;
getts(&rp->cts);
return;
}
break;
case REQ_BLOCKHOSTHOST:
case REQ_RESTOREHOSTHOST:
(void)snprintf(buf, sizeof(buf), "%s",
addr2str(&rp->acl.addr2));
if (al == NULL) {
lg(LOG_ERR, "serverdroprestore:"
" %s/%s wasn't already blocked in ACL %s!",
addr2str(&rp->acl.addr1), buf, ap->name);
rp->state = RSTATE_DONE;
getts(&rp->cts);
return;
}
break;
case REQ_DROPUDPPORT:
case REQ_DROPTCPPORT:
case REQ_RESTOREUDPPORT:
case REQ_RESTORETCPPORT:
if (al == NULL) {
lg(LOG_ERR, "serverdroprestore: "
" port %s/%s wasn't already blocked in ACL %s!",
tcporudpreqstr(rp->type), rp->acl.port1, ap->name);
rp->state = RSTATE_DONE;
getts(&rp->cts);
return;
}
break;
case REQ_PERMITUDPDSTHOSTPORT:
case REQ_PERMITTCPDSTHOSTPORT:
case REQ_DROPTCPDSTHOSTPORT:
if (al == NULL) {
lg(LOG_ERR, "serverdroprestore:"
" %s:%s/%s wasn't already permitted in ACL %s!",
addr2str(&rp->acl.addr1), tcporudpreqstr(rp->type),
rp->acl.port1, ap->name);
rp->state = RSTATE_DONE;
getts(&rp->cts);
return;
}
break;
case REQ_UNPERMITUDPDSTHOSTPORT:
case REQ_UNPERMITTCPDSTHOSTPORT:
case REQ_RESTORETCPDSTHOSTPORT:
if (al == NULL) {
lg(LOG_ERR, "serverdroprestore:"
" %s:%s/%s wasn't already permitted in ACL %s!",
addr2str(&rp->acl.addr1), tcporudpreqstr(rp->type),
rp->acl.port1, ap->name);
rp->state = RSTATE_DONE;
getts(&rp->cts);
return;
}
break;
default:
lg(LOG_ERR, "serverdroprestore: bad type %s (1)",
val2str(str2acl, al->type));
exit(EX_SOFTWARE);
}
/* No need to check the sequence number further, just check the type */
switch (rp->type) {
case REQ_DROP:
case REQ_RESTORE:
case REQ_BLOCKHOSTHOST:
case REQ_RESTOREHOSTHOST:
case REQ_DROPTCPPORT:
case REQ_RESTORETCPPORT:
case REQ_DROPUDPPORT:
case REQ_RESTOREUDPPORT:
case REQ_PERMITUDPDSTHOSTPORT:
case REQ_UNPERMITUDPDSTHOSTPORT:
case REQ_PERMITTCPDSTHOSTPORT:
case REQ_UNPERMITTCPDSTHOSTPORT:
case REQ_DROPTCPDSTHOSTPORT:
case REQ_RESTORETCPDSTHOSTPORT:
break;
default:
lg(LOG_ERR, "serverdroprestore: bad type %s (2)",
val2str(str2acl, al->type));
exit(EX_SOFTWARE);
}
/* Send the request to the child */
switch (rp->acl.type) {
case ATYPE_BLOCKHOST:
case ATYPE_BLOCKNET:
childsend(sp, "%s %s %s %d",
rp->cmd, addr2str(&rp->acl.addr1),
ap->name, rp->acl.seq);
break;
case ATYPE_BLOCKHOSTHOST:
(void)snprintf(buf, sizeof(buf), "%s",
addr2str(&rp->acl.addr2));
childsend(sp, "%s %s %s %s %d",
rp->cmd, addr2str(&rp->acl.addr1), buf,
ap->name, rp->acl.seq);
break;
case ATYPE_BLOCKUDPPORT:
case ATYPE_BLOCKTCPPORT:
childsend(sp, "%s %s %s %d",
rp->cmd, rp->acl.port1, ap->name, rp->acl.seq);
break;
case ATYPE_PERMITUDPDSTHOSTPORT:
case ATYPE_PERMITTCPDSTHOSTPORT:
case ATYPE_BLOCKTCPDSTHOSTPORT:
childsend(sp, "%s %s %s %s %d",
rp->cmd, addr2str(&rp->acl.addr1), rp->acl.port1,
ap->name, rp->acl.seq);
break;
default:
lg(LOG_ERR, "childdroprestore: bad atype %d", rp->acl.type);
exit(EX_SOFTWARE);
}
/* Update request state */
rp->state = RSTATE_CHILD;
}
void
serverprocess(struct state *sp, struct req *rp)
{
switch (rp->type) {
case REQ_DROP:
case REQ_RESTORE:
case REQ_BLOCKHOSTHOST:
case REQ_RESTOREHOSTHOST:
case REQ_DROPUDPPORT:
case REQ_RESTOREUDPPORT:
case REQ_DROPTCPPORT:
case REQ_RESTORETCPPORT:
case REQ_PERMITUDPDSTHOSTPORT:
case REQ_UNPERMITUDPDSTHOSTPORT:
case REQ_PERMITTCPDSTHOSTPORT:
case REQ_UNPERMITTCPDSTHOSTPORT:
case REQ_DROPTCPDSTHOSTPORT:
case REQ_RESTORETCPDSTHOSTPORT:
serverdroprestore(sp, rp);
break;
case REQ_AYT:
case REQ_SYNC:
childsend(sp, "%s", rp->cmd);
rp->state = RSTATE_CHILD;
break;
default:
lg(LOG_ERR, "serverprocess: unhandled request type %d",
rp->type);
exit(EX_SOFTWARE);
}
}
void
serversync(struct state *sp)
{
struct req *rp;
rp = new(1, sizeof(*rp), "serversync: req");
rp->state = RSTATE_PENDING;
rp->type = REQ_SYNC;
rp->cmd = "sync";
/* Arrival timestamp */
getts(&rp->ats);
/* Append the new request to end of list */
appendreq(&sp->req, rp);
/* Cancel possible pending "ayt" */
timerreset(&sp->t_ayt);
}