Mercurial > notdcc
diff srvrlib/flod.c @ 0:c7f6b056b673
First import of vendor version
author | Peter Gervai <grin@grin.hu> |
---|---|
date | Tue, 10 Mar 2009 13:49:58 +0100 |
parents | |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/srvrlib/flod.c Tue Mar 10 13:49:58 2009 +0100 @@ -0,0 +1,440 @@ +/* Distributed Checksum Clearinghouse + * + * open, create, and check DCC server output flood mapped file + * + * Copyright (c) 2008 by Rhyolite Software, LLC + * + * This agreement is not applicable to any entity which sells anti-spam + * solutions to others or provides an anti-spam solution as part of a + * security solution sold to other entities, or to a private network + * which employs the DCC or uses data provided by operation of the DCC + * but does not provide corresponding data to other users. + * + * Permission to use, copy, modify, and distribute this software without + * changes for any purpose with or without fee is hereby granted, provided + * that the above copyright notice and this permission notice appear in all + * copies and any distributed versions or copies are either unchanged + * or not called anything similar to "DCC" or "Distributed Checksum + * Clearinghouse". + * + * Parties not eligible to receive a license under this agreement can + * obtain a commercial license to use DCC by contacting Rhyolite Software + * at sales@rhyolite.com. + * + * A commercial license would be for Distributed Checksum and Reputation + * Clearinghouse software. That software includes additional features. This + * free license for Distributed ChecksumClearinghouse Software does not in any + * way grant permision to use Distributed Checksum and Reputation Clearinghouse + * software + * + * THE SOFTWARE IS PROVIDED "AS IS" AND RHYOLITE SOFTWARE, LLC DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL RHYOLITE SOFTWARE, LLC + * BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES + * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, + * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS + * SOFTWARE. + * + * Rhyolite Software DCC 1.3.103-1.58 $Revision$ + */ + +#include "srvr_defs.h" + +FLOD_MMAPS *flod_mmaps; +DCC_PATH flod_mmap_path; +DCC_PATH flod_path; + +static int mmap_fd = -1; + + +void +flod_mmap_path_set(void) +{ + fnm2rel_good(flod_mmap_path, + grey_on ? GREY_FLOD_NM : DCCD_FLOD_NM, + ".map"); + fnm2rel_good(flod_path, + grey_on ? GREY_FLOD_NM : DCCD_FLOD_NM, + 0); +} + + + +u_char +flod_mmap_sync(DCC_EMSG emsg, u_char touch) +{ + u_char result = 1; + + if (flod_mmap_path[0] == '\0') + flod_mmap_path_set(); + + if (flod_mmaps + && 0 > MSYNC(flod_mmaps, sizeof(*flod_mmaps), MS_SYNC)) { + dcc_pemsg(EX_IOERR, emsg, "msync(%s): %s", + flod_mmap_path, ERROR_STR()); + result = 0; + emsg = 0; + } + + if (touch) { + if (mmap_fd >= 0 + && 0 > fsync(mmap_fd)) { + dcc_pemsg(EX_IOERR, emsg, "fsync(%s): %s", + flod_mmap_path, ERROR_STR()); + result = 0; + emsg = 0; + } + + /* Ensure that the mtime changes at least occassionally. + * Several systems do not update the mtimes of files modified + * with mmap(). Some like BSD/OS delay changing the mtime until + * the file is accessed with read(). Others including + * filesystems on some versions of Linux apparently never change + * the mtime. */ + if (!dcc_set_mtime(emsg, flod_mmap_path, mmap_fd, 0)) { + result = 0; + emsg = 0; + } + } + + return result; +} + + + +u_char /* 1=no problems, 0=complaints */ +flod_unmap(DCC_EMSG emsg, const DCCD_STATS *dccd_stats) +{ + u_char result = 1; + + if (!flod_mmap_sync(emsg, 0)) { + result = 0; + emsg = 0; + } + + if (flod_mmaps) { + if (dccd_stats) + memcpy(&flod_mmaps->dccd_stats, dccd_stats, + sizeof(flod_mmaps->dccd_stats)); + if (0 > munmap((void *)flod_mmaps, sizeof(*flod_mmaps))) { + dcc_pemsg(EX_IOERR, emsg, "munmap(%s,%d): %s", + flod_mmap_path, + ISZ(*flod_mmaps), ERROR_STR()); + result = 0; + emsg = 0; + } + flod_mmaps = 0; + } + + if (mmap_fd >= 0) { + if (close(mmap_fd) < 0) { + dcc_pemsg(EX_IOERR, emsg, "close(%s): %s", + flod_mmap_path, ERROR_STR()); + result = 0; + emsg = 0; + } + mmap_fd = -1; + } + + return result; +} + + + +static int /* 1=success, 0=retry, -1=fatal */ +flod_mmap_try(DCC_EMSG emsg, + const DB_SN *sn, + u_char rw) /* 0=rdonly/unlocked, 1=write/locked */ +{ + int flags; + struct stat sb; + union { + FLOD_MMAPS m; + u_char b[1]; + } init; + void *p; + int i; + + if (flod_mmap_path[0] == '\0') + flod_mmap_path_set(); + + if (rw) + mmap_fd = dcc_lock_open(emsg, flod_mmap_path, O_RDWR|O_CREAT, + DCC_LOCK_OPEN_NOWAIT, + DCC_LOCK_ALL_FILE, 0); + else + mmap_fd = dcc_lock_open(emsg, flod_mmap_path, O_RDONLY, + DCC_LOCK_OPEN_NOLOCK, 0, 0); + if (mmap_fd == -1) + return (errno == EWOULDBLOCK) ? -1 : 0; + + if (fstat(mmap_fd, &sb) < 0) { + dcc_pemsg(EX_IOERR, emsg, "stat(%s): %s", + flod_mmap_path, ERROR_STR()); + flod_unmap(0, 0); + return 0; + } + if (0 > fcntl(mmap_fd, F_SETFD, FD_CLOEXEC)) { + dcc_pemsg(EX_IOERR, emsg, "fcntl(%s, FD_CLOEXEC): %s", + flod_mmap_path, ERROR_STR()); + flod_unmap(0, 0); + return 0; + } + + if (sb.st_size == 0 && rw) { + memset(&init, 0, sizeof(init)); + strcpy(init.m.magic, FLOD_MMAP_MAGIC); + if (sn) + init.m.sn = *sn; + i = write(mmap_fd, &init, sizeof(init)); + if (i < 0) { + dcc_pemsg(EX_IOERR, emsg, "write(%s, init): %s", + flod_mmap_path, ERROR_STR()); + flod_unmap(0, 0); + return -1; + } + if (i != ISZ(init)) { + dcc_pemsg(EX_IOERR, emsg, + "write(%s, init)=%d instead of %d", + flod_mmap_path, i, ISZ(init)); + flod_unmap(0, 0); + return -1; + } + } else { + i = read(mmap_fd, &init, sizeof(init)); + if (i < 0) { + dcc_pemsg(EX_IOERR, emsg, "read(%s, init): %s", + flod_mmap_path, ERROR_STR()); + flod_unmap(0, 0); + return -1; + } + if (i < ISZ(init)) { + if (i < sb.st_size) { + dcc_pemsg(EX_IOERR, emsg, "read(%s, init)=%d", + flod_mmap_path, i); + flod_unmap(0, 0); + return -1; + } + } + } + + if (sb.st_size >= (off_t)sizeof(init.m.magic) + && strcmp(init.m.magic, FLOD_MMAP_MAGIC)) { + dcc_pemsg(EX_IOERR, emsg, "wrong magic in %s;" + " \"%s\" instead of \"%s\"", + flod_mmap_path, init.m.magic, FLOD_MMAP_MAGIC); + flod_unmap(0, 0); + return 0; + } + + flags = rw ? (PROT_READ|PROT_WRITE) : PROT_READ; + p = mmap(0, sizeof(*flod_mmaps), flags, MAP_SHARED, mmap_fd, 0); + if (p == MAP_FAILED) { + dcc_pemsg(EX_IOERR, emsg, "mmap(%s): %s", + flod_mmap_path, ERROR_STR()); + flod_unmap(0, 0); + return 0; + } + flod_mmaps = p; + + if (sb.st_size == 0) { + dcc_pemsg(EX_IOERR, emsg, "%s (re)created", flod_mmap_path); + } else if (sb.st_size != sizeof(FLOD_MMAPS)) { + dcc_pemsg(EX_IOERR, emsg, "%s has size %d instead of %d", + flod_mmap_path, (int)sb.st_size, ISZ(FLOD_MMAPS)); + flod_unmap(0, 0); + return 0; + } + + if (sn + && memcmp(&flod_mmaps->sn, sn, sizeof(flod_mmaps->sn))) { + char sn1_buf[30], sn2_buf[32]; + dcc_pemsg(EX_IOERR, emsg, "s/n %s instead of %s in %s", + ts2str(sn1_buf, sizeof(sn1_buf), &flod_mmaps->sn), + ts2str(sn2_buf, sizeof(sn2_buf), sn), + flod_mmap_path); + flod_unmap(0, 0); + return 0; + } + + return 1; +} + + + +u_char /* 0=failed, 1=mapped */ +flod_mmap(DCC_EMSG emsg, + const DB_SN *sn, + const DCCD_STATS *dccd_stats, + u_char rw, /* 0=rdonly/unlocked, 1=write/locked */ + u_char trace) +{ + int i; + + if (!flod_unmap(emsg, dccd_stats) && emsg) { + if (trace) + dcc_trace_msg("%s", emsg); + *emsg = '\0'; + } + + /* try to open the existing file */ + i = flod_mmap_try(emsg, sn, rw); + + /* finished if that went well or we are not allowed to fix things */ + if (i != 0 || !rw) + return i > 0; + + /* delete the file if it is broken */ + if (emsg && *emsg != '\0') { + if (trace) + dcc_trace_msg("%s", emsg); + *emsg = '\0'; + } + if (0 > unlink(flod_mmap_path) + && errno != ENOENT) { + dcc_pemsg(EX_IOERR, emsg, "unlink(%s): %s", + flod_mmap_path, ERROR_STR()); + flod_unmap(0, 0); + return 0; + } + flod_unmap(0, 0); + + /* try to recreate the file */ + if (flod_mmap_try(emsg, sn, 1) > 0) { + if (emsg) { + if (trace) + dcc_trace_msg("%s", emsg); + *emsg = '\0'; + } + return 1; + } + + flod_unmap(0, 0); + return 0; +} + + + +const char * +flod_stats_printf(char *buf, int buf_len, + int st, /* 0=off, 1=restarting, 2=on */ + int oflods_total, + int oflods_active, + int iflods_active) +{ + snprintf(buf, buf_len, + "flood %s %3d streams %d out active %d in", + st == 0 ? "off" : st == 1 ? "restarting" : "on", + oflods_total, oflods_active, iflods_active); + return buf; +} + + + +static void +mmap_fg_sub(char **bufp, int *buf_lenp, + const char **prefix, const char *str) +{ + int i; + + i = snprintf(*bufp, *buf_lenp, "%s%s", *prefix, str); + if (*buf_lenp <= i) { + *buf_lenp = 0; + } else { + *bufp += i; + *buf_lenp -= i; + } + *prefix = " "; +} + + +const char * +flodmap_fg(char *buf, int buf_len, + const char *prefix, const FLOD_MMAP *mp) +{ + char *buf0 = buf; + + if (!buf_len) + return ""; + *buf = '\0'; + if (!mp) + return buf0; + + if ((mp->flags & FLODMAP_FG_IN_OFF) + && (mp->flags & FLODMAP_FG_OUT_OFF)) { + mmap_fg_sub(&buf, &buf_len, &prefix, "off"); + } else { + if (mp->flags & FLODMAP_FG_IN_OFF) + mmap_fg_sub(&buf, &buf_len, &prefix, "in off"); + if (mp->flags & FLODMAP_FG_OUT_OFF) + mmap_fg_sub(&buf, &buf_len, &prefix, "out off"); + } + + if (mp->flags & FLODMAP_FG_ROGUE) + mmap_fg_sub(&buf, &buf_len, &prefix, "crazy"); + + if (mp->flags & FLODMAP_FG_REWINDING) + mmap_fg_sub(&buf, &buf_len, &prefix, "rewinding"); + + if (mp->flags & FLODMAP_FG_NEED_REWIND) + mmap_fg_sub(&buf, &buf_len, &prefix, "need rewind"); + else if (mp->flags & FLODMAP_FG_FFWD_IN) + mmap_fg_sub(&buf, &buf_len, &prefix, "need FFWD"); + + if (mp->flags & FLODMAP_FG_PASSIVE) + mmap_fg_sub(&buf, &buf_len, &prefix, "passive"); + if ((mp->flags & FLODMAP_FG_OUT_SRVR) + && !(mp->flags & FLODMAP_FG_PASSIVE)) + mmap_fg_sub(&buf, &buf_len, &prefix, "forced passive"); + + if (!(mp->flags & FLODMAP_FG_IN_SRVR)) { + if (mp->flags & FLODMAP_FG_SOCKS) + mmap_fg_sub(&buf, &buf_len, &prefix, "SOCKS"); + if (mp->flags & FLODMAP_FG_NAT) + mmap_fg_sub(&buf, &buf_len, &prefix, "NAT"); + } else { + if (mp->flags & FLODMAP_FG_SOCKS) + mmap_fg_sub(&buf, &buf_len, &prefix, "rejected SOCKS"); + if (mp->flags & FLODMAP_FG_NAT) + mmap_fg_sub(&buf, &buf_len, &prefix, "rejected NAT"); + } + + if (mp->flags & FLODMAP_FG_LEAF) + mmap_fg_sub(&buf, &buf_len, &prefix, "leaf"); + + if (mp->flags & FLODMAP_FG_MAPPED) + mmap_fg_sub(&buf, &buf_len, &prefix, "IDs mapped"); + + if (mp->flags & FLODMAP_FG_FFWD_IN) + mmap_fg_sub(&buf, &buf_len, &prefix, "want fastforward"); + + if (mp->flags & FLODMAP_FG_USE_2PASSWD) + mmap_fg_sub(&buf, &buf_len, &prefix, "2nd password"); + + if (mp->flags & FLODMAP_FG_IPv4) + mmap_fg_sub(&buf, &buf_len, &prefix, "IPv4"); + + if (mp->flags & FLODMAP_FG_IPv6) + mmap_fg_sub(&buf, &buf_len, &prefix, "IPv6"); + + return buf0; +} + + + +/* this function lets clients such as dbclean know when flooding is quiet */ +int /* -1=sick, 0=off, 1=not off */ +flod_running(const char *st) +{ + char off_buf[11]; + int out, active, in; + + if (4 != sscanf(st, "flood %10s %d streams %d out active %d in", + off_buf, &out, &active, &in)) + return 1; + + if (strcmp(off_buf, "off")) + return 1; + return active != 0 || in != 0; +}