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
/
util.c
< prev
next >
Wrap
C/C++ Source or Header
|
2012-02-08
|
22KB
|
1,138 lines
/*
* Copyright (c) 2002, 2003, 2004, 2005, 2006, 2008, 2009, 2010, 2011, 2012
* 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: util.c 809 2012-02-09 01:17:58Z leres $ (LBL)";
#endif
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <ctype.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"
/* Locals */
struct s2v syslog2str[] = {
{ "auth", LOG_AUTH, },
{ "authpriv", LOG_AUTHPRIV, },
#ifdef LOG_CONSOLE
{ "console", LOG_CONSOLE, },
#endif
{ "cron", LOG_CRON, },
{ "daemon", LOG_DAEMON, },
{ "ftp", LOG_FTP, },
{ "kern", LOG_KERN, },
{ "lpr", LOG_LPR, },
{ "mail", LOG_MAIL, },
{ "news", LOG_NEWS, },
#ifdef LOG_NTP
{ "ntp", LOG_NTP, },
#endif
#ifdef LOG_SECURITY
{ "security", LOG_SECURITY, },
#endif
{ "syslog", LOG_SYSLOG, },
{ "user", LOG_USER, },
{ "uucp", LOG_UUCP, },
{ "local0", LOG_LOCAL0, },
{ "local1", LOG_LOCAL1, },
{ "local2", LOG_LOCAL2, },
{ "local3", LOG_LOCAL3, },
{ "local4", LOG_LOCAL4, },
{ "local5", LOG_LOCAL5, },
{ "local6", LOG_LOCAL6, },
{ "local7", LOG_LOCAL7, },
{ NULL, -1, }
};
static struct stat sbuf;
void
addr2sa(struct addr *a, u_short port, struct sockaddr *sap)
{
struct sockaddr_in *s4p;
struct sockaddr_in6 *s6p;
memset(sap, 0, sizeof(*sap));
#ifdef HAVE_SOCKADDR_SA_LEN
sap->sa_len = sizeof(*sap);
#endif
sap->sa_family = a->family;
switch (a->family) {
case AF_INET:
s4p = (struct sockaddr_in *)sap;
s4p->sin_port = htons(port);
memmove(&s4p->sin_addr, &a->addr4, sizeof(s4p->sin_addr));
break;
case AF_INET6:
s6p = (struct sockaddr_in6 *)sap;
s6p->sin6_port = htons(port);
memmove(&s6p->sin6_addr, &a->addr6, sizeof(s6p->sin6_addr));
break;
default:
abort();
}
}
const char *
addr2str(const struct addr *addr)
{
int w;
size_t len, size;
char *cp;
static char buf[128];
w = maskwidth(addr);
switch (addr->family) {
case AF_INET:
if (inet_ntop(addr->family, &addr->addr4,
buf, sizeof(buf)) == NULL) {
lg(LOG_ERR, "addr2str: v4 botch");
abort();
}
if (w == 32)
return (buf);
break;
case AF_INET6:
if (inet_ntop(addr->family, &addr->addr6,
buf, sizeof(buf)) == NULL) {
lg(LOG_ERR, "addr2str: v6 botch");
abort();
}
if (w == 128)
return (buf);
break;
default:
abort();
}
/* Append address mask width */
cp = buf;
len = strlen(cp);
cp += len;
size = sizeof(buf) - len;
(void)snprintf(cp, size, "/%d", w);
return (buf);
}
/* Return and error message if there is a problem */
const char *
checklimits(struct cf *cf, struct acllist *ap)
{
struct acllimit *alp;
static char buf[128];
/* Check cap on maxium number of acls */
if (cf->c_maxseq > 0 && ap->acllen >= cf->c_maxseq) {
(void)snprintf(buf, sizeof(buf),
"No free slots in ACL %s (%d in use, %d allowed)",
ap->name, (int)ap->acllen, (int)cf->c_maxseq);
return (buf);
}
/* Check limit on ACLs group */
if ((alp = ap->limitp) != NULL && alp->a_len >= alp->a_maxseq) {
(void)snprintf(buf, sizeof(buf),
"No free slots in ACL %s (group %s)"
" (%d in use, %d allowed)",
ap->name,
fmtargv(alp->a_nacls, alp->a_acls),
alp->a_len,
alp->a_maxseq);
return (buf);
}
return (NULL);
}
/* Reopen logfile if necessary */
void
checklf()
{
struct stat sbuf2;
/* Bail if not managing a logfile */
if (logfile == NULL)
return;
/* Do checks if not first time through */
if (lf != NULL) {
/* Done if the file info matches */
if (stat(logfile, &sbuf2) >= 0 &&
sbuf2.st_ino == sbuf.st_ino && sbuf2.st_dev == sbuf.st_dev)
return;
/* Close file */
if (fclose(lf) == EOF)
syslog(LOG_ERR, "checklf: fclose: %s: %m", logfile);
}
/* Open for append in case logfile already exists */
lf = fopen(logfile, "a");
if (lf == NULL) {
fprintf(stderr, "%s: fopen: %s: %s\n",
prog, logfile, strerror(errno));
syslog(LOG_ERR, "checklf: fopen: %s: %m", logfile);
exit(EX_OSERR);
}
/* Line buffering */
setlinebuf(lf);
/* Sock away stat() info */
if (fstat(fileno(lf), &sbuf) < 0) {
fprintf(stderr, "%s: fstat: %s: %s\n",
prog, logfile, strerror(errno));
syslog(LOG_ERR, "checklf: fstat: %s: %m", logfile);
}
}
const char *
checkmaskwidth(struct cf *cf, const struct addr *a)
{
int w;
static char buf[64];
w = (a->family == AF_INET) ? cf->c_ipv4_maxwidth : cf->c_ipv6_maxwidth;
if (maskwidth(a) < w) {
(void)snprintf(buf, sizeof(buf),
"Subnet mask wider than /%d not supported", w);
return (buf);
}
return (NULL);
}
/*
* p - pointer to dynamic memory
* len - desired new length (objects)
* sizep - returned length of dynamic buffer (objects)
* osize - object size (bytes)
* isize - initial size (objects)
* inc - incremental size (objects)
* what - string for error message
*/
void *
dynarray(void *p, size_t len, size_t *sizep, size_t osize, int isize,
int inc, const char *what)
{
/* Initial allocation? */
if (p == NULL) {
/* Get initial size from *sizep, isize or len */
if (*sizep <= 0)
*sizep = isize;
if (*sizep < len)
*sizep = len;
p = new(*sizep, osize, what);
return (p);
}
if (*sizep <= (len + inc/2)) {
*sizep = len + inc;
p = realloc(p, *sizep * osize);
if (p == NULL) {
lg(LOG_ERR, "dynarray: realloc %s: %s",
what, strerror(errno));
exit(EX_OSERR);
}
memset(p + len * osize, 0, (*sizep - len) * osize);
}
return (p);
}
const char *
escapestr(const char *str)
{
char *cp;
const char *p;
size_t n;
static char *result = NULL;
static char escapes[] = "$[]{}\"\\"; /* XXX check this in book */
if (result != NULL) {
free(result);
result = NULL;
}
/* Return a expect style null */
if (str == NULL || *str == '\0')
return ("{}");
/* Enough space for string and EOS */
n = strlen(str) + 1;
/* Add room for escapes */
for (p = str; *p != '\0'; ++p)
if (strchr(escapes, *p) != NULL)
++n;
result = malloc(n);
if (result == NULL) {
fprintf(lf, "%s: escapenaem: malloc: %s",
prog, strerror(errno));
exit(EX_OSERR);
}
p = str;
cp = result;
while (*p != '\0') {
if (strchr(escapes, *p) != NULL)
*cp++ = '\\';
*cp++ = *p++;
}
*cp = '\0';
return (result);
}
/* Extract an IPv4 or IPv6 host or network address */
const char *
extractaddr(const char *s1, const char *s2, struct addr *a)
{
int i;
long w;
char *cp, *ep;
const char *p;
char temp[64];
memset(a, 0, sizeof(*a));
/* Let's see what we've got here */
if (strchr(s1, '.') != NULL) {
a->family = AF_INET;
w = 32;
} else if (strchr(s1, ':') != NULL) {
a->family = AF_INET6;
w = 128;
} else
return ("unrecognized address type");
p = strchr(s1, '/');
if (p != NULL) {
/* Mask length was specified */
if (s2 != NULL)
return ("garbage following mask width");
strncpy(temp, s1, sizeof(temp));
temp[sizeof(temp) - 1] = '\0';
cp = strchr(temp, '/');
if (cp == NULL)
abort();
*cp++ = '\0';
ep = NULL;
w = strtol(cp, &ep, 10);
if (*ep != '\0')
return ("garbage following mask width");
s1 = temp;
}
switch (a->family) {
case AF_INET:
if (!inet_pton(a->family, s1, &a->addr4))
return ("cannot parse IPv4 address");
if (s2 != NULL) {
if (!inet_pton(a->family, s2, &a->mask4))
return ("cannot parse IPv4 address mask");
w = maskwidth(a);
}
if (w > 32)
return ("mask length must be <= 32");
setmaskwidth(w, a);
if ((a->addr4 & ~a->mask4) != 0)
return ("non-network bits set in addr");
#ifdef notdef
if ((ntohl(a->addr4) & 0xff000000) == 0)
return ("high octet must be non-zero");
#endif
break;
case AF_INET6:
if (!inet_pton(a->family, s1, &a->addr6))
return ("cannot parse IPv6 address");
if (s2 != NULL) {
if (!inet_pton(a->family, s2, &a->mask6))
return ("cannot parse IPv6 address mask");
w = maskwidth(a);
}
if (w > 128)
return ("mask length must be <= 128");
setmaskwidth(w, a);
for (i = 0; i < 16; ++i) {
if ((a->addr6[i] & ~a->mask6[i]) != 0)
return ("non-network bits set in addr");
}
break;
default:
abort();
}
return (NULL);
}
/* Extract an IPv4 or IPv6 host address */
const char *
extracthost(const char *s1, const char *s2, struct addr *a)
{
const char *p;
p = extractaddr(s1, s2, a);
if (p == NULL && !ISHOST(a))
p = "must be an address, not a network";
return (p);
}
void
freeargv(char **av)
{
char **av2;
if (av != NULL) {
av2 = av;
while (*av2 != NULL)
free(*av2++);
free(av);
}
}
void *
freedynarray(void *p, size_t *lenp, size_t *sizep)
{
if (p != NULL)
free(p);
*lenp = 0;
*sizep = 0;
return (NULL);
}
void
getts(struct timeval *tsp)
{
if (gettimeofday(tsp, NULL) < 0) {
/* Can't use lg() since it can indirectly call us */
syslog(LOG_ERR, "getts: gettimeofday: %s", strerror(errno));
exit(EX_OSERR);
}
}
int
insubnet(const struct addr *net, const struct addr *a)
{
int i;
if (net->family != a->family)
return (0);
switch (net->family) {
case AF_INET:
return (net->addr4 == (a->addr4 & net->mask4));
case AF_INET6:
for (i = 0; i < 16; ++i)
if (net->addr6[i] != (a->addr6[i] & net->mask6[i]))
return (0);
return (1);
default:
abort();
}
}
/*
* Return true if the addr is a default for its address family
* This means all address and maskbits are zero
*/
int
isdefaultaddr(struct addr *a)
{
int i;
switch (a->family) {
case AF_INET:
return (a->addr4 == 0 && a->mask4 == 0);
case AF_INET6:
for (i = 0; i < 16; ++i)
if (a->addr6[i] != 0 || a->mask6[i] != 0)
return (0);
/* If we got here, all bytes were zero */
return (1);
default:
abort();
}
}
void
lg(int pri, const char *fmt, ...)
{
va_list ap;
if (debug) {
if (logfile != NULL)
checklf();
fputs(tsstr(), lf);
putc(' ', lf);
va_start(ap, fmt);
(void)vfprintf(lf, fmt, ap);
va_end(ap);
putc('\n', lf);
}
va_start(ap, fmt);
vsyslog(pri, fmt, ap);
va_end(ap);
}
const char *
fmtargv(int ac, char **av)
{
int i;
static char buf[256];
char *cp;
size_t len, size;
cp = buf;
size = sizeof(buf);
for (i = 0; i < ac; ++i) {
if (i > 0 && size > 1) {
*cp++ = ' ';
--size;
}
len = snprintf(cp, size, "%s", av[i]);
if (len < 0)
abort();
cp += len;
size -= len;
}
*cp = '\0';
return (buf);
}
int
makeargv(const char *args, char ***avp)
{
const char *p, *p2, *ep;
int n, len;
char **av;
if (args == NULL)
return (0);
/* Setup end pointer (trimming trailing whitespace) */
p = args;
ep = args + strlen(args);
while (ep - 1 >= args && isspace((int)ep[-1]))
--ep;
/* Eat leading whitespace */
while (isspace((int)*args))
++args;
/* Count arguments */
n = 0;
while (p < ep) {
if (!isspace((int)*p)) {
++n;
while (p < ep && !isspace((int)*p))
++p;
}
while (p < ep && isspace((int)*p))
++p;
}
av = new(n + 1, sizeof(*av), "makeargs av");
*avp = av;
/* Copy arguments */
n = 0;
p = args;
p2 = p;
while (p < ep) {
if (!isspace((int)*p)) {
++n;
while (p < ep && !isspace((int)*p))
++p;
len = p - p2;
*av = new(len + 1, sizeof(char), "makeargs string");
strncpy(*av, p2, len);
av[0][len] = '\0';
++av;
}
while (p < ep && isspace((int)*p))
++p;
p2 = p;
}
return (n);
}
int
maskwidth(const struct addr *a)
{
int w;
int i, j;
u_int32_t m, tm;
/* Work backwards until we find a set bit */
switch (a->family) {
case AF_INET:
m = ntohl(a->mask4);
for (w = 32; w > 0; --w) {
tm = 0xffffffff << (32 - w);
if (tm == m)
break;
}
break;
case AF_INET6:
w = 128;
for (j = 15; j >= 0; --j) {
m = a->mask6[j];
for (i = 8; i > 0; --w, --i) {
tm = (0xff << (8 - i)) & 0xff;
if (tm == m)
return (w);
}
}
break;
default:
abort();
}
return (w);
}
void
nets_log(struct state *sp, struct req *rp)
{
char *cp;
const char *p;
struct timeval *tvp;
char detail[1024];
size_t cc, len;
/* Completion timestamp */
tvp = &rp->cts;
if (tvp->tv_sec == 0 && tvp->tv_sec == 0)
getts(tvp);
/* Initial pointer/size left */
cp = detail;
cc = sizeof(detail) - 1;
/* Optional NETS id */
if (sp->cf->c_id != NULL) {
(void)snprintf(cp, cc, " id=%s", sp->cf->c_id);
len = strlen(cp);
cp += len;
cc -= len;
}
/* Log the acllist name if we know it */
if (rp->acllist != NULL) {
(void)snprintf(cp, cc, " acl=%s", rp->acllist->name);
len = strlen(cp);
cp += len;
cc -= len;
}
/* No default so we'll get an error for missing cases */
switch (rp->type) {
case REQ_NULLZERO:
case REQ_NONULLZERO:
/* route detail */
if (rp->nullzero.type == ROUTE_NULLZERO )
(void)snprintf(cp, cc, " ip=%s",
addr2str(&rp->nullzero.dst));
break;
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:
case REQ_COMPACT:
/* ACL detail */
switch (rp->acl.type) {
case ATYPE_PERMITHOST:
case ATYPE_BLOCKHOST:
(void)snprintf(cp, cc, " ip=%s",
addr2str(&rp->acl.addr1));
break;
case ATYPE_PERMITNET:
case ATYPE_BLOCKNET:
(void)snprintf(cp, cc, " net=%s",
addr2str(&rp->acl.addr1));
break;
case ATYPE_PERMITHOSTHOST:
case ATYPE_BLOCKHOSTHOST:
(void)snprintf(cp, cc, " ip=%s",
addr2str(&rp->acl.addr1));
len = strlen(cp);
cp += len;
cc -= len;
(void)snprintf(cp, cc, " ip2=%s",
addr2str(&rp->acl.addr2));
break;
case ATYPE_PERMITUDPPORT:
case ATYPE_BLOCKUDPPORT:
case ATYPE_PERMITTCPPORT:
case ATYPE_BLOCKTCPPORT:
(void)snprintf(cp, cc, " port=%s", rp->acl.port1);
break;
case ATYPE_PERMITUDPHOSTPORT:
case ATYPE_BLOCKUDPHOSTPORT:
case ATYPE_PERMITTCPHOSTPORT:
case ATYPE_BLOCKTCPHOSTPORT:
case ATYPE_PERMITUDPDSTHOSTPORT:
case ATYPE_BLOCKUDPDSTHOSTPORT:
case ATYPE_PERMITTCPDSTHOSTPORT:
case ATYPE_BLOCKTCPDSTHOSTPORT:
case ATYPE_PERMITUDPHOSTSRCPORT:
case ATYPE_BLOCKUDPHOSTSRCPORT:
case ATYPE_PERMITTCPHOSTSRCPORT:
case ATYPE_BLOCKTCPHOSTSRCPORT:
(void)snprintf(cp, cc, " ip=%s port=%s",
addr2str(&rp->acl.addr1), rp->acl.port1);
break;
default:
(void)snprintf(cp, cc, " ?=ATYPE_#%d",
rp->acl.type);
break;
}
break;
case REQ_ADDWHITELIST:
case REQ_REMWHITELIST:
/* whitelist detail */
if (ISHOST(&rp->whitelist))
p = "ip";
else
p = "net";
(void)snprintf(cp, cc, " %s=%s", p, addr2str(&rp->whitelist));
break;
case REQ_AYT:
case REQ_EXIT:
case REQ_HELP:
case REQ_LISTACL:
case REQ_LISTROUTE:
case REQ_QUERY:
case REQ_QUERYNULLZERO:
case REQ_QUERYWHITELIST:
case REQ_RELOAD:
case REQ_STATE:
case REQ_SYNC:
case REQ_TEST:
case REQ_UNKNOWN:
case REQ_WHITELIST:
/* Don't nets_log these */
return;
}
/* Status */
if ((rp->flags & RFLAG_FAILED) != 0)
p = "failed";
else if ((rp->flags & RFLAG_IGNORE) != 0)
p = "ignore";
else
p = "success";
syslog(sp->cf->c_netsfac | LOG_DEBUG,
"NETS status=%s cmd=%s%s ats=%lu.%06lu cts=%lu.%06lu cmt=%s",
p,
rp->cmd,
detail,
(u_long)rp->ats.tv_sec, (u_long)rp->ats.tv_usec,
(u_long)rp->cts.tv_sec, (u_long)rp->cts.tv_usec,
pretty(rp->comment));
}
void *
new(size_t num, size_t size, const char *what)
{
void *p;
p = calloc(num, size);
if (p == NULL) {
lg(LOG_ERR, "new: calloc %s: %s", what, strerror(errno));
exit(EX_OSERR);
}
return (p);
}
const char *
pretty(const char *str)
{
size_t cc;
char *cp;
const char *p;
static char buf[8192];
if (str == NULL)
return ("");
cp = buf;
cc = sizeof(buf) - 1;
/* Leave room for possible escape, char and eos */
for (p = str; *p != '\0' && cc >= 3; ++p) {
if (*p == '\n') {
*cp++ = '\\';
*cp++ = 'n';
cc -= 2;
} else if (*p == '\r') {
*cp++ = '\\';
*cp++ = 'r';
cc -= 2;
} else if (isprint((int)*p)) {
*cp++ = *p;
--cc;
} else {
/* DEL to ?, others to alpha */
*cp++ = '^';
*cp++ = *p ^ 0x40;
cc -= 2;
}
}
*cp = '\0';
return (buf);
}
void
sa2addr(struct sockaddr *sap, struct addr *a, u_int16_t *portp)
{
struct sockaddr_in *s4p;
struct sockaddr_in6 *s6p;
memset(a, 0, sizeof(*a));
a->family = sap->sa_family;
switch (a->family) {
case AF_INET:
s4p = (struct sockaddr_in *)sap;
*portp = ntohs(s4p->sin_port);
memmove(&a->addr4, &s4p->sin_addr, sizeof(a->addr4));
a->mask4 = 0xffffffff;
break;
case AF_INET6:
s6p = (struct sockaddr_in6 *)sap;
*portp = ntohs(s6p->sin6_port);
memmove(&a->addr6, &s6p->sin6_addr, sizeof(a->addr6));
setmaskwidth(128, a);
break;
default:
abort();
}
}
/* Set address mask in network order */
void
setmaskwidth(u_int w, struct addr *a)
{
int i, j;
switch (a->family) {
case AF_INET:
if (w <= 0)
a->mask4 = 0;
else
a->mask4 = htonl(0xffffffff << (32 - w));
break;
case AF_INET6:
/* XXX is this right? */
memset(a->mask6, 0, sizeof(a->mask6));
for (i = 0; i < w / 8; ++i)
a->mask6[i] = 0xff;
i = w / 8;
j = w % 8;
if (j > 0 && i < 16)
a->mask6[i] = 0xff << (8 - j);
break;
default:
abort();
}
}
const char *
simplewd(void)
{
char *cp;
static char wd[1024];
if (getcwd(wd, sizeof(wd)) == NULL) {
lg(LOG_ERR, "simplewd: getcwd: %s", strerror(errno));
exit(EX_OSERR);
}
cp = strrchr(wd, '/');
if (cp == NULL)
return (wd);
return (++cp);
}
int
suck2dot(FILE *f, char **pp)
{
int n, size, len, i;
char *p, *cp;
char buf[1024];
n = 0;
size = 256;
len = 0;
p = (char *)malloc(size);
if (p == NULL) {
lg(LOG_ERR, "suck2dot: malloc: %s", strerror(errno));
exit(EX_OSERR);
}
*p = '\0';
*pp = p;
while (fgets(buf, sizeof(buf), f) != NULL) {
++n;
cp = buf;
/* Eat leading dot; done if there was only one */
if (*cp == '.' && *++cp == '\n' && cp[1] == '\0')
break;
i = strlen(cp);
if (len + i + 1 > size) {
size += i + 256;
*pp = (char *)realloc(*pp, size);
if (*pp == NULL) {
lg(LOG_ERR, "suck2dot: realloc: %s",
strerror(errno));
exit(EX_OSERR);
}
p = *pp + len;
}
strcpy(p, cp);
p += i;
len += i;
}
return (n);
}
int
str2val(const struct s2v *lp, const char *suffix)
{
const struct s2v *tp;
for (tp = lp; tp->s != NULL; ++tp)
if (strcmp(suffix, tp->s) == 0)
break;
return (tp->v);
}
int
str2valcase(const struct s2v *lp, const char *suffix)
{
const struct s2v *tp;
for (tp = lp; tp->s != NULL; ++tp)
if (strcasecmp(suffix, tp->s) == 0)
break;
return (tp->v);
}
void
strappend(char **pp, const char *str)
{
int len;
if (*pp == NULL)
*pp = strsave(str);
else {
len = strlen(*pp);
*pp = realloc(*pp, len + strlen(str) + 1);
if (*pp == NULL) {
lg(LOG_ERR, "strappend: realloc: %s", strerror(errno));
exit(EX_OSERR);
}
strcpy(*pp + len, str);
}
}
char *
strsave(const char *str)
{
char *cp;
cp = strdup(str);
if (cp == NULL) {
lg(LOG_ERR, "strsave: strdup: %s", strerror(errno));
exit(EX_OSERR);
}
return (cp);
}
const char *
tcporudpreqstr(int rtype)
{
const char *p;
p = "?";
switch (rtype) {
case REQ_DROPUDPPORT:
case REQ_RESTOREUDPPORT:
case REQ_PERMITUDPDSTHOSTPORT:
case REQ_UNPERMITUDPDSTHOSTPORT:
p = "UDP";
break;
case REQ_DROPTCPPORT:
case REQ_RESTORETCPPORT:
case REQ_PERMITTCPDSTHOSTPORT:
case REQ_UNPERMITTCPDSTHOSTPORT:
case REQ_DROPTCPDSTHOSTPORT:
case REQ_RESTORETCPDSTHOSTPORT:
p = "TCP";
break;
case REQ_UNKNOWN:
case REQ_RELOAD:
case REQ_DROP:
case REQ_RESTORE:
case REQ_BLOCKHOSTHOST:
case REQ_RESTOREHOSTHOST:
case REQ_NULLZERO:
case REQ_NONULLZERO:
case REQ_STATE:
case REQ_LISTACL:
case REQ_LISTROUTE:
case REQ_WHITELIST:
case REQ_ADDWHITELIST:
case REQ_REMWHITELIST:
case REQ_QUERY:
case REQ_QUERYNULLZERO:
case REQ_QUERYWHITELIST:
case REQ_COMPACT:
case REQ_TEST:
case REQ_EXIT:
case REQ_HELP:
case REQ_SYNC:
case REQ_AYT:
break;
}
return (p);
}
void
trimws(char *str, size_t len)
{
char *cp;
cp = str + len;
while (cp > str && isspace((int)cp[-1]))
--cp;
*cp = '\0';
}
const char *
tsstr()
{
struct timeval tv;
static char buf[32];
getts(&tv);
(void)snprintf(buf, sizeof(buf), "%ld.%06ld",
(u_long)tv.tv_sec, (u_long)tv.tv_usec);
return (buf);
}
int
typ2flag(const struct v2v *lp, int wtype)
{
const struct v2v *vp;
for (vp = lp; vp->v1 != 0; ++vp)
if (vp->v1 == wtype)
break;
return (vp->v2);
}
const char *
val2str(const struct s2v *lp, int val)
{
const struct s2v *tp;
for (tp = lp; tp->s != NULL; ++tp)
if (val == tp->v)
break;
return (tp->s);
}