]> jfr.im git - irc/ircd-hybrid/bopm.git/commitdiff
Sources moved to src/ dir.
authorandy <redacted>
Sun, 26 May 2002 05:01:12 +0000 (05:01 +0000)
committerandy <redacted>
Sun, 26 May 2002 05:01:12 +0000 (05:01 +0000)
29 files changed:
src/.cvsignore [new file with mode: 0644]
src/Makefile.am [new file with mode: 0644]
src/Makefile.in [new file with mode: 0644]
src/bopchecker.c [moved from bopchecker.c with 96% similarity]
src/bopchecker.h [moved from bopchecker.h with 100% similarity]
src/compat.c [moved from compat.c with 100% similarity]
src/compat.h [moved from compat.h with 100% similarity]
src/config.c [moved from config.c with 100% similarity]
src/config.h [moved from config.h with 100% similarity]
src/dnsbl.c [new file with mode: 0644]
src/dnsbl.h [new file with mode: 0644]
src/extern.h [new file with mode: 0644]
src/irc.c [new file with mode: 0644]
src/irc.h [new file with mode: 0644]
src/log.c [new file with mode: 0644]
src/log.h [new file with mode: 0644]
src/main.c [new file with mode: 0644]
src/match.c [new file with mode: 0644]
src/match.h [new file with mode: 0644]
src/misc.c [new file with mode: 0644]
src/misc.h [new file with mode: 0644]
src/opercmd.c [new file with mode: 0644]
src/opercmd.h [new file with mode: 0644]
src/options.h [new file with mode: 0644]
src/scan.c [new file with mode: 0644]
src/scan.h [new file with mode: 0644]
src/setup.h.in [new file with mode: 0644]
src/stats.c [new file with mode: 0644]
src/stats.h [new file with mode: 0644]

diff --git a/src/.cvsignore b/src/.cvsignore
new file mode 100644 (file)
index 0000000..2c353b3
--- /dev/null
@@ -0,0 +1,16 @@
+*.sw[op]
+*.bb*
+*.da
+*.dat
+*.gcov
+gmon.out
+config.log
+config.cache
+config.status
+Makefile
+bopm
+bopchecker
+setup.h
+.deps
+stamp-h
+stamp-h.in
diff --git a/src/Makefile.am b/src/Makefile.am
new file mode 100644 (file)
index 0000000..627789c
--- /dev/null
@@ -0,0 +1,12 @@
+bin_PROGRAMS = bopm bopchecker
+
+AM_CPPFLAGS = -DBOPM_ETCDIR="\"$(sysconfdir)\"" -DBOPM_LOGDIR="\"$(localstatedir)\""
+
+bopm_SOURCES = compat.c compat.h config.c config.h dnsbl.c dnsbl.h extern.h \
+    irc.c irc.h log.c log.h main.c match.c match.h misc.c misc.h opercmd.c \
+    opercmd.h options.h scan.c scan.h setup.h stats.c stats.h
+bopchecker_SOURCES = bopchecker.c bopchecker.h compat.c compat.h config.c \
+    config.h match.c match.h misc.c misc.h scan.c scan.h setup.h
+
+bopm_LDADD = @LNSL@ @LSOCKET@
+bopchecker_LDADD = @LNSL@ @LSOCKET@
diff --git a/src/Makefile.in b/src/Makefile.in
new file mode 100644 (file)
index 0000000..6f4b646
--- /dev/null
@@ -0,0 +1,366 @@
+# Makefile.in generated automatically by automake 1.4-p5 from Makefile.am
+
+# Copyright (C) 1994, 1995-8, 1999, 2001 Free Software Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+
+SHELL = @SHELL@
+
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+VPATH = @srcdir@
+prefix = @prefix@
+exec_prefix = @exec_prefix@
+
+bindir = @bindir@
+sbindir = @sbindir@
+libexecdir = @libexecdir@
+datadir = @datadir@
+sysconfdir = @sysconfdir@
+sharedstatedir = @sharedstatedir@
+localstatedir = @localstatedir@
+libdir = @libdir@
+infodir = @infodir@
+mandir = @mandir@
+includedir = @includedir@
+oldincludedir = /usr/include
+
+DESTDIR =
+
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+
+top_builddir = ..
+
+ACLOCAL = @ACLOCAL@
+AUTOCONF = @AUTOCONF@
+AUTOMAKE = @AUTOMAKE@
+AUTOHEADER = @AUTOHEADER@
+
+INSTALL = @INSTALL@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@ $(AM_INSTALL_PROGRAM_FLAGS)
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+transform = @program_transform_name@
+
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+CC = @CC@
+LNSL = @LNSL@
+LSOCKET = @LSOCKET@
+MAKEINFO = @MAKEINFO@
+PACKAGE = @PACKAGE@
+VERSION = @VERSION@
+
+bin_PROGRAMS = bopm bopchecker
+
+AM_CPPFLAGS = -DBOPM_ETCDIR="\"$(sysconfdir)\"" -DBOPM_LOGDIR="\"$(localstatedir)\""
+
+bopm_SOURCES = compat.c compat.h config.c config.h dnsbl.c dnsbl.h extern.h \
+    irc.c irc.h log.c log.h main.c match.c match.h misc.c misc.h opercmd.c \
+    opercmd.h options.h scan.c scan.h setup.h stats.c stats.h
+
+bopchecker_SOURCES = bopchecker.c bopchecker.h compat.c compat.h config.c \
+    config.h match.c match.h misc.c misc.h scan.c scan.h setup.h
+
+
+bopm_LDADD = @LNSL@ @LSOCKET@
+bopchecker_LDADD = @LNSL@ @LSOCKET@
+mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs
+CONFIG_HEADER = setup.h
+CONFIG_CLEAN_FILES = 
+PROGRAMS =  $(bin_PROGRAMS)
+
+
+DEFS = @DEFS@ -I. -I$(srcdir) -I.
+CPPFLAGS = @CPPFLAGS@
+LDFLAGS = @LDFLAGS@
+LIBS = @LIBS@
+bopm_OBJECTS =  compat.o config.o dnsbl.o irc.o log.o main.o match.o \
+misc.o opercmd.o scan.o stats.o
+bopm_DEPENDENCIES = 
+bopm_LDFLAGS = 
+bopchecker_OBJECTS =  bopchecker.o compat.o config.o match.o misc.o \
+scan.o
+bopchecker_DEPENDENCIES = 
+bopchecker_LDFLAGS = 
+CFLAGS = @CFLAGS@
+COMPILE = $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+CCLD = $(CC)
+LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(LDFLAGS) -o $@
+DIST_COMMON =  ./stamp-h.in Makefile.am Makefile.in setup.h.in
+
+
+DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST)
+
+TAR = gtar
+GZIP_ENV = --best
+DEP_FILES =  .deps/bopchecker.P .deps/compat.P .deps/config.P \
+.deps/dnsbl.P .deps/irc.P .deps/log.P .deps/main.P .deps/match.P \
+.deps/misc.P .deps/opercmd.P .deps/scan.P .deps/stats.P
+SOURCES = $(bopm_SOURCES) $(bopchecker_SOURCES)
+OBJECTS = $(bopm_OBJECTS) $(bopchecker_OBJECTS)
+
+all: all-redirect
+.SUFFIXES:
+.SUFFIXES: .S .c .o .s
+$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4) 
+       cd $(top_srcdir) && $(AUTOMAKE) --gnu src/Makefile
+
+Makefile: $(srcdir)/Makefile.in  $(top_builddir)/config.status $(BUILT_SOURCES)
+       cd $(top_builddir) \
+         && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status
+
+
+setup.h: stamp-h
+       @if test ! -f $@; then \
+               rm -f stamp-h; \
+               $(MAKE) stamp-h; \
+       else :; fi
+stamp-h: $(srcdir)/setup.h.in $(top_builddir)/config.status
+       cd $(top_builddir) \
+         && CONFIG_FILES= CONFIG_HEADERS=src/setup.h \
+            $(SHELL) ./config.status
+       @echo timestamp > stamp-h 2> /dev/null
+$(srcdir)/setup.h.in: $(srcdir)/stamp-h.in
+       @if test ! -f $@; then \
+               rm -f $(srcdir)/stamp-h.in; \
+               $(MAKE) $(srcdir)/stamp-h.in; \
+       else :; fi
+$(srcdir)/stamp-h.in: $(top_srcdir)/configure.in $(ACLOCAL_M4) 
+       cd $(top_srcdir) && $(AUTOHEADER)
+       @echo timestamp > $(srcdir)/stamp-h.in 2> /dev/null
+
+mostlyclean-hdr:
+
+clean-hdr:
+
+distclean-hdr:
+       -rm -f setup.h
+
+maintainer-clean-hdr:
+
+mostlyclean-binPROGRAMS:
+
+clean-binPROGRAMS:
+       -test -z "$(bin_PROGRAMS)" || rm -f $(bin_PROGRAMS)
+
+distclean-binPROGRAMS:
+
+maintainer-clean-binPROGRAMS:
+
+install-binPROGRAMS: $(bin_PROGRAMS)
+       @$(NORMAL_INSTALL)
+       $(mkinstalldirs) $(DESTDIR)$(bindir)
+       @list='$(bin_PROGRAMS)'; for p in $$list; do \
+         if test -f $$p; then \
+           echo "  $(INSTALL_PROGRAM) $$p $(DESTDIR)$(bindir)/`echo $$p|sed 's/$(EXEEXT)$$//'|sed '$(transform)'|sed 's/$$/$(EXEEXT)/'`"; \
+            $(INSTALL_PROGRAM) $$p $(DESTDIR)$(bindir)/`echo $$p|sed 's/$(EXEEXT)$$//'|sed '$(transform)'|sed 's/$$/$(EXEEXT)/'`; \
+         else :; fi; \
+       done
+
+uninstall-binPROGRAMS:
+       @$(NORMAL_UNINSTALL)
+       list='$(bin_PROGRAMS)'; for p in $$list; do \
+         rm -f $(DESTDIR)$(bindir)/`echo $$p|sed 's/$(EXEEXT)$$//'|sed '$(transform)'|sed 's/$$/$(EXEEXT)/'`; \
+       done
+
+.s.o:
+       $(COMPILE) -c $<
+
+.S.o:
+       $(COMPILE) -c $<
+
+mostlyclean-compile:
+       -rm -f *.o core *.core
+
+clean-compile:
+
+distclean-compile:
+       -rm -f *.tab.c
+
+maintainer-clean-compile:
+
+bopm: $(bopm_OBJECTS) $(bopm_DEPENDENCIES)
+       @rm -f bopm
+       $(LINK) $(bopm_LDFLAGS) $(bopm_OBJECTS) $(bopm_LDADD) $(LIBS)
+
+bopchecker: $(bopchecker_OBJECTS) $(bopchecker_DEPENDENCIES)
+       @rm -f bopchecker
+       $(LINK) $(bopchecker_LDFLAGS) $(bopchecker_OBJECTS) $(bopchecker_LDADD) $(LIBS)
+
+tags: TAGS
+
+ID: $(HEADERS) $(SOURCES) $(LISP)
+       list='$(SOURCES) $(HEADERS)'; \
+       unique=`for i in $$list; do echo $$i; done | \
+         awk '    { files[$$0] = 1; } \
+              END { for (i in files) print i; }'`; \
+       here=`pwd` && cd $(srcdir) \
+         && mkid -f$$here/ID $$unique $(LISP)
+
+TAGS:  $(HEADERS) $(SOURCES) setup.h.in $(TAGS_DEPENDENCIES) $(LISP)
+       tags=; \
+       here=`pwd`; \
+       list='$(SOURCES) $(HEADERS)'; \
+       unique=`for i in $$list; do echo $$i; done | \
+         awk '    { files[$$0] = 1; } \
+              END { for (i in files) print i; }'`; \
+       test -z "$(ETAGS_ARGS)setup.h.in$$unique$(LISP)$$tags" \
+         || (cd $(srcdir) && etags $(ETAGS_ARGS) $$tags setup.h.in $$unique $(LISP) -o $$here/TAGS)
+
+mostlyclean-tags:
+
+clean-tags:
+
+distclean-tags:
+       -rm -f TAGS ID
+
+maintainer-clean-tags:
+
+distdir = $(top_builddir)/$(PACKAGE)-$(VERSION)/$(subdir)
+
+subdir = src
+
+distdir: $(DISTFILES)
+       here=`cd $(top_builddir) && pwd`; \
+       top_distdir=`cd $(top_distdir) && pwd`; \
+       distdir=`cd $(distdir) && pwd`; \
+       cd $(top_srcdir) \
+         && $(AUTOMAKE) --include-deps --build-dir=$$here --srcdir-name=$(top_srcdir) --output-dir=$$top_distdir --gnu src/Makefile
+       @for file in $(DISTFILES); do \
+         d=$(srcdir); \
+         if test -d $$d/$$file; then \
+           cp -pr $$d/$$file $(distdir)/$$file; \
+         else \
+           test -f $(distdir)/$$file \
+           || ln $$d/$$file $(distdir)/$$file 2> /dev/null \
+           || cp -p $$d/$$file $(distdir)/$$file || :; \
+         fi; \
+       done
+
+DEPS_MAGIC := $(shell mkdir .deps > /dev/null 2>&1 || :)
+
+-include $(DEP_FILES)
+
+mostlyclean-depend:
+
+clean-depend:
+
+distclean-depend:
+       -rm -rf .deps
+
+maintainer-clean-depend:
+
+%.o: %.c
+       @echo '$(COMPILE) -c $<'; \
+       $(COMPILE) -Wp,-MD,.deps/$(*F).pp -c $<
+       @-cp .deps/$(*F).pp .deps/$(*F).P; \
+       tr ' ' '\012' < .deps/$(*F).pp \
+         | sed -e 's/^\\$$//' -e '/^$$/ d' -e '/:$$/ d' -e 's/$$/ :/' \
+           >> .deps/$(*F).P; \
+       rm .deps/$(*F).pp
+
+%.lo: %.c
+       @echo '$(LTCOMPILE) -c $<'; \
+       $(LTCOMPILE) -Wp,-MD,.deps/$(*F).pp -c $<
+       @-sed -e 's/^\([^:]*\)\.o[      ]*:/\1.lo \1.o :/' \
+         < .deps/$(*F).pp > .deps/$(*F).P; \
+       tr ' ' '\012' < .deps/$(*F).pp \
+         | sed -e 's/^\\$$//' -e '/^$$/ d' -e '/:$$/ d' -e 's/$$/ :/' \
+           >> .deps/$(*F).P; \
+       rm -f .deps/$(*F).pp
+info-am:
+info: info-am
+dvi-am:
+dvi: dvi-am
+check-am: all-am
+check: check-am
+installcheck-am:
+installcheck: installcheck-am
+all-recursive-am: setup.h
+       $(MAKE) $(AM_MAKEFLAGS) all-recursive
+
+install-exec-am: install-binPROGRAMS
+install-exec: install-exec-am
+
+install-data-am:
+install-data: install-data-am
+
+install-am: all-am
+       @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+install: install-am
+uninstall-am: uninstall-binPROGRAMS
+uninstall: uninstall-am
+all-am: Makefile $(PROGRAMS) setup.h
+all-redirect: all-am
+install-strip:
+       $(MAKE) $(AM_MAKEFLAGS) AM_INSTALL_PROGRAM_FLAGS=-s install
+installdirs:
+       $(mkinstalldirs)  $(DESTDIR)$(bindir)
+
+
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+       -rm -f Makefile $(CONFIG_CLEAN_FILES)
+       -rm -f config.cache config.log stamp-h stamp-h[0-9]*
+
+maintainer-clean-generic:
+mostlyclean-am:  mostlyclean-hdr mostlyclean-binPROGRAMS \
+               mostlyclean-compile mostlyclean-tags mostlyclean-depend \
+               mostlyclean-generic
+
+mostlyclean: mostlyclean-am
+
+clean-am:  clean-hdr clean-binPROGRAMS clean-compile clean-tags \
+               clean-depend clean-generic mostlyclean-am
+
+clean: clean-am
+
+distclean-am:  distclean-hdr distclean-binPROGRAMS distclean-compile \
+               distclean-tags distclean-depend distclean-generic \
+               clean-am
+
+distclean: distclean-am
+
+maintainer-clean-am:  maintainer-clean-hdr maintainer-clean-binPROGRAMS \
+               maintainer-clean-compile maintainer-clean-tags \
+               maintainer-clean-depend maintainer-clean-generic \
+               distclean-am
+       @echo "This command is intended for maintainers to use;"
+       @echo "it deletes files that may require special tools to rebuild."
+
+maintainer-clean: maintainer-clean-am
+
+.PHONY: mostlyclean-hdr distclean-hdr clean-hdr maintainer-clean-hdr \
+mostlyclean-binPROGRAMS distclean-binPROGRAMS clean-binPROGRAMS \
+maintainer-clean-binPROGRAMS uninstall-binPROGRAMS install-binPROGRAMS \
+mostlyclean-compile distclean-compile clean-compile \
+maintainer-clean-compile tags mostlyclean-tags distclean-tags \
+clean-tags maintainer-clean-tags distdir mostlyclean-depend \
+distclean-depend clean-depend maintainer-clean-depend info-am info \
+dvi-am dvi check check-am installcheck-am installcheck all-recursive-am \
+install-exec-am install-exec install-data-am install-data install-am \
+install uninstall-am uninstall all-redirect all-am all installdirs \
+mostlyclean-generic distclean-generic clean-generic \
+maintainer-clean-generic clean mostlyclean distclean maintainer-clean
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
similarity index 96%
rename from bopchecker.c
rename to src/bopchecker.c
index 950680ee9764246e09dfed4599472d46d36f1a07..eb059c6ce7dcd90f792a3778515e6515ab870785 100644 (file)
@@ -62,6 +62,7 @@ extern struct config_hash hash[];
 
 int OPT_DEBUG = 1;
 char *CONFNAME = DEFAULTNAME;
+char *CONFDIR = BOPM_ETCDIR;
 char *CONFFILE;
 int RC = 0;
 
@@ -98,9 +99,9 @@ int main(int argc, char **argv)
 
        signal(SIGPIPE, SIG_IGN);
 
-       len = strlen(CONFNAME) + strlen(CONFEXT) + 2;
+       len = strlen(CONFDIR) + strlen(CONFNAME) + strlen(CONFEXT) + 3;
        CONFFILE = malloc(len * sizeof(*CONFFILE));
-       snprintf(CONFFILE, len, "%s.%s", CONFNAME, CONFEXT);
+       snprintf(CONFFILE, len, "%s/%s.%s", CONFDIR, CONFNAME, CONFEXT);
 
        /*
         * The only things we need in a conf file are SCANIP and
similarity index 100%
rename from bopchecker.h
rename to src/bopchecker.h
similarity index 100%
rename from compat.c
rename to src/compat.c
similarity index 100%
rename from compat.h
rename to src/compat.h
similarity index 100%
rename from config.c
rename to src/config.c
similarity index 100%
rename from config.h
rename to src/config.h
diff --git a/src/dnsbl.c b/src/dnsbl.c
new file mode 100644 (file)
index 0000000..01e7950
--- /dev/null
@@ -0,0 +1,169 @@
+/*
+Copyright (C) 2002  Erik Fears
+
+This program 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.
+
+This program 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 received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+
+      Foundation, Inc.
+      59 Temple Place - Suite 330
+      Boston, MA  02111-1307, USA.
+
+*/
+
+#include "setup.h"
+
+#include <stdio.h>
+
+#ifdef STDC_HEADERS
+#include <stdlib.h>
+#endif
+
+#include <string.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <time.h>
+#include <errno.h>
+
+#include "irc.h"
+#include "opercmd.h"
+#include "scan.h"
+#include "dnsbl.h"
+#include "config.h"
+#include "extern.h"
+#include "log.h"
+
+extern unsigned int STAT_DNSBL_MATCHES;
+
+/*
+ * Check an ip address for presence in a DNS (black|block)list.  All we need
+ * to do is reverse the octets, append the BL zone and then do a
+ * gethostbyname.  If that gives us an answer, then it is on the BL.
+ */
+int dnsbl_check(const char *addr, const char *irc_nick,
+    const char *irc_user, char *irc_addr)
+{
+       size_t buflen;
+       struct in_addr in;
+       struct hostent *he;
+       char *buf;
+       unsigned char a, b, c, d;
+  
+       if (!inet_aton(addr, &in)) {
+               log("DNSBL -> Invalid address '%s', ignoring.", addr);
+               return(0);
+       }
+
+       d = (unsigned char) (in.s_addr >> 24) & 0xFF;
+       c = (unsigned char) (in.s_addr >> 16) & 0xFF;
+       b = (unsigned char) (in.s_addr >> 8) & 0xFF;
+       a = (unsigned char) in.s_addr & 0xFF;
+
+       /* Enough for a reversed IP and the zone. */
+       buflen = 18 + strlen(CONF_DNSBL_ZONE);
+       buf = malloc(buflen * sizeof(*buf));
+
+#ifdef WORDS_BIGENDIAN
+       snprintf(buf, buflen, "%d.%d.%d.%d.%s.", a, b, c, d,
+           CONF_DNSBL_ZONE);
+#else
+       snprintf(buf, buflen, "%d.%d.%d.%d.%s.", d, c, b, a,
+           CONF_DNSBL_ZONE);
+#endif
+
+       if (OPT_DEBUG)
+               log("DNSBL -> Checking %s", buf);
+   
+       if (!(he = gethostbyname(buf))) {
+               switch(h_errno) {
+                       /*
+                        * Some of these errors indicate serious problems
+                        * that will require admin intervention.
+                        */
+               case NO_RECOVERY:
+                       irc_send("PRIVMSG %s :Whilst checking '%s' "
+                           "against my dnsbl zone '%s', I got a "
+                           "non-recoverable name server error.  Might "
+                           "want to take a look, check if your local "
+                           "resolver is working!?", CONF_CHANNELS, addr,
+                           CONF_DNSBL_ZONE);
+                       break;
+               case TRY_AGAIN:
+                       irc_send("PRIVMSG %s :Whilst checking '%s' "
+                           "against my dnsbl zone '%s', I got a "
+                           "temporary nameserver error.  Might want to "
+                           "take a look, check if your local resolver is "
+                           "working!?", CONF_CHANNELS, addr,
+                           CONF_DNSBL_ZONE);
+                       break;
+
+               default:
+                       /*
+                        * Some other error but we don't care, we can just
+                        * treat this IP as OK.
+                        */
+                       break;
+               }
+
+               free(buf);
+               return(0);
+       }
+       free(buf);
+
+       /*
+        * We got an answer, so we need to kline this IP now.
+        */
+       irc_kline(irc_addr, (char *)addr);
+       log("DNSBL -> %s appears in BL zone %s", addr, CONF_DNSBL_ZONE);
+       irc_send("PRIVMSG %s :DNSBL: %s!%s@%s appears in BL zone %s",
+           CONF_CHANNELS, irc_nick, irc_user, irc_addr, CONF_DNSBL_ZONE);
+
+       STAT_DNSBL_MATCHES++;
+       return(1);
+}
+
+/*
+ * Send an email to report this open proxy.
+ */
+void dnsbl_report(struct scan_struct *ss)
+{
+       char buf[4096], cmdbuf[512];
+       FILE *fp;
+
+       if (!ss || !ss->addr)
+               return;
+
+       snprintf(cmdbuf, sizeof(cmdbuf), "%s -t", CONF_SENDMAIL);
+       snprintf(buf, sizeof(buf),
+           "From: %s <%s>\n"
+            "To: %s\n"
+           "Subject: BOPM Report\n\n"
+           "%s: %s\n\n"
+           "%s\n", CONF_NICK, CONF_DNSBL_FROM, CONF_DNSBL_TO,
+           ss->protocol->type, ss->addr, ss->conn_notice);
+
+       if ((fp = popen(cmdbuf, "w")) == NULL) {
+               log("DNSBL -> Failed to create pipe to '%s' for email "
+                   "report!", cmdbuf);
+               irc_send("PRIVMSG %s :I was trying to create a pipe to "
+                   "'%s' to send a DNSBL report, and it failed!  I'll "
+                   "give up for now.", CONF_CHANNELS, cmdbuf);
+               return;
+       }
+
+       fputs(buf, fp);
+       pclose(fp);
+       log("DNSBL -> Sent report to %s", CONF_DNSBL_TO);
+}
diff --git a/src/dnsbl.h b/src/dnsbl.h
new file mode 100644 (file)
index 0000000..aa80481
--- /dev/null
@@ -0,0 +1,8 @@
+#ifndef DNSBL_H
+#define DNSBL_H
+
+extern int dnsbl_check(const char *addr, const char *irc_nick,
+    const char *irc_user, char *irc_addr);
+extern void dnsbl_report(struct scan_struct *ss);
+
+#endif
diff --git a/src/extern.h b/src/extern.h
new file mode 100644 (file)
index 0000000..8aea0f3
--- /dev/null
@@ -0,0 +1,41 @@
+#ifndef EXTERN_H
+#define EXTERN_H
+
+extern int h_errno;
+
+extern char *CONF_SERVER;
+extern char *CONF_PASSWORD;
+extern char *CONF_USER;
+extern char *CONF_NICK;
+extern char *CONF_REALNAME;
+extern char *CONF_OPER;
+extern char *CONF_OPER_MODES;
+extern char *CONF_REASON;
+extern char *CONF_SCANIP;
+extern char *CONF_BINDIRC;
+extern char *CONF_BINDSCAN;
+extern char *CONF_CHANNELS;
+extern char *CONF_KEYS;
+extern char *CONF_NICKSERV_IDENT;
+extern char *CONF_CHANSERV_INVITE;
+extern char *CONF_KLINE_COMMAND;
+extern char *CONF_DNSBL_ZONE;
+extern char *CONF_DNSBL_FROM;
+extern char *CONF_DNSBL_TO;
+extern char *CONF_SENDMAIL;
+extern char *CONF_HELP_EMAIL;
+extern char *CONF_AWAY;
+extern char *CONF_TARGET_STRING;
+extern string_list *CONF_EXCLUDE;
+
+extern unsigned int CONF_PORT;
+extern unsigned int CONF_SCANPORT;
+extern unsigned int CONF_FDLIMIT;
+extern unsigned int CONF_TIMEOUT;
+
+extern unsigned int OPT_DEBUG;
+extern time_t STAT_START_TIME;
+extern unsigned int STAT_NUM_CONNECTS;
+
+#endif    
diff --git a/src/irc.c b/src/irc.c
new file mode 100644 (file)
index 0000000..5100d27
--- /dev/null
+++ b/src/irc.c
@@ -0,0 +1,1022 @@
+/*
+Copyright (C) 2002  Erik Fears
+
+This program 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.
+
+This program 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 received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+
+      Foundation, Inc.
+      59 Temple Place - Suite 330
+      Boston, MA  02111-1307, USA.
+
+*/
+
+#include "setup.h"
+
+#include <stdio.h>
+#include <unistd.h>
+
+#ifdef STDC_HEADERS
+# include <stdlib.h>
+# include <string.h>
+#endif
+
+#ifdef HAVE_STRINGS_H
+# include <strings.h>
+#endif
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+
+#ifdef TIME_WITH_SYS_TIME
+# include <sys/time.h>
+# include <time.h>
+#else
+# ifdef HAVE_SYS_TIME_H
+#  include <sys/time.h>
+# else
+#  include <time.h>
+# endif
+#endif
+
+#include <errno.h>
+#include <stdarg.h>
+
+#include "irc.h"
+#include "log.h"
+#include "config.h"
+#include "opercmd.h"
+#include "scan.h"
+#include "dnsbl.h"
+#include "stats.h"
+#include "extern.h"
+#include "options.h"
+#include "match.h"
+#include "compat.h"
+
+static void irc_init(void);
+static void irc_connect(void);
+static void irc_reconnect(void);
+static void irc_read(void);
+static void irc_parse(void);
+static void do_perform(void);
+static void do_connect(char *addr, char *irc_nick, char *irc_user,
+    char *irc_addr, char *conn_notice);
+static void do_hybrid_connect(int tokens, char **token);
+static void do_trircd_connect(int tokens, char **token);
+static void do_ultimateircd_connect(int tokens, char **token);
+static void do_xnet_connect(int tokens, char **token);
+static char *get_chan_key(const char *channel);
+static char *check_channel(const char *channel);
+
+extern char *CONFFILE;
+extern time_t LAST_REAP_TIME;
+
+/*
+ * Certain variables we don't want to allocate memory for over and over
+ * again so global scope is given.
+ */
+
+char                IRC_RAW[MSGLENMAX];      /* Buffer to read data into              */
+char                IRC_SENDBUFF[MSGLENMAX]; /* Send buffer                           */
+int                 IRC_RAW_LEN = 0;         /* Position of IRC_RAW                   */
+
+int                 IRC_FD = -1;      /* File descriptor for IRC client        */
+struct sockaddr_in  IRC_SVR;          /* Sock Address Struct for IRC server    */
+struct sockaddr_in  IRC_LOCAL;        /* Sock Address Struct for Bind          */
+struct hostent     *IRC_HOST;         /* Hostent struct for IRC server         */
+fd_set              IRC_READ_FDSET;   /* fd_set for IRC (read) data for select()*/
+
+struct timeval      IRC_TIMEOUT;      /* timeval struct for select() timeout   */
+time_t              IRC_NICKSERV_LAST = 0; /* Last notice from nickserv        */
+time_t              IRC_LAST = 0;     /* Last full line of data from irc server*/
+
+/* Give one cycle to the IRC client, which
+ * will allow it to poll for data and handle
+ * that data if need be.
+ */
+
+void irc_cycle(void)
+{      
+       if (IRC_FD <= 0) {
+               /* No socket open. */
+               config_load(CONFFILE);  /* Reload config. */
+               irc_init();             /* Resolve remote host. */
+               irc_connect();          /* Connect to remote host. */
+        }
+
+       IRC_TIMEOUT.tv_sec  = 0;
+       /*
+        * Block .05 seconds to avoid excessive CPU use on select(). */
+       IRC_TIMEOUT.tv_usec = 50000;
+           
+       FD_ZERO(&IRC_READ_FDSET);
+
+       FD_SET(IRC_FD, &IRC_READ_FDSET);
+            
+       switch (select((IRC_FD + 1), &IRC_READ_FDSET, 0, 0, &IRC_TIMEOUT)) {
+       case -1:         
+               return;
+               break;
+       case 0:
+               break;
+       default:
+               /* Check if IRC data is available. */
+               if (FD_ISSET(IRC_FD, &IRC_READ_FDSET))
+                       irc_read();
+               break;
+       }
+}
+
+
+/*  Allocate socket file descriptor for connection,
+ *  and resolve remote host.
+ *
+ */
+
+static void irc_init(void)
+{
+       if (IRC_FD)
+               close(IRC_FD);  
+
+       memset(&IRC_SVR, 0, sizeof(IRC_SVR));
+       memset(&IRC_LOCAL, 0, sizeof(IRC_LOCAL));
+
+       /* Resolve IRC host. */
+       if (!(IRC_HOST = gethostbyname(CONF_SERVER))) {
+               switch(h_errno) {
+               case HOST_NOT_FOUND:
+                       log("IRC -> gethostbyname(): The specified host "
+                           "(%s) is unknown", CONF_SERVER);
+                       break;
+               case NO_ADDRESS:
+                       log("IRC -> gethostbyname(): The specified name "
+                           "(%s) exists, but does not have an IP",
+                           CONF_SERVER);
+                       break;
+               case NO_RECOVERY:
+                       log("IRC -> gethostbyname(): An unrecoverable "
+                           "error occured resolving (%s)", CONF_SERVER);
+                       break;
+               case TRY_AGAIN:
+                       log("IRC -> gethostbyname(): Error occured with "
+                           "authoritive name server (%s)", CONF_SERVER);
+                       break;
+               default:
+                       log("IRC -> gethostbyname(): Unknown error "
+                           "resolving (%s)", CONF_SERVER);
+                       break;
+                }
+               exit(EXIT_FAILURE);
+       }
+
+       IRC_SVR.sin_family      = AF_INET;
+       IRC_SVR.sin_port        = htons(CONF_PORT);
+       IRC_SVR.sin_addr = *((struct in_addr *) IRC_HOST->h_addr);
+
+       if (IRC_SVR.sin_addr.s_addr == INADDR_NONE) {
+               log("IRC -> Unknown error resolving remote host (%s)",
+                   CONF_SERVER);
+               exit(EXIT_FAILURE);
+       }
+
+       /* Request file desc for IRC client socket. */
+       IRC_FD = socket(PF_INET, SOCK_STREAM, 0);
+
+       if (IRC_FD == -1) {
+               switch(errno) {
+               case EINVAL:
+               case EPROTONOSUPPORT:
+                       log("IRC -> socket(): SOCK_STREAM is not "
+                           "supported on this domain");
+                       break;
+               case ENFILE:
+                       log("IRC -> socket(): Not enough free file "
+                           "descriptors to allocate IRC socket");
+                       break;
+               case EMFILE:
+                       log("IRC -> socket(): Process table overflow when "
+                           "requesting file descriptor");
+                       break;
+               case EACCES:
+                       log("IRC -> socket(): Permission denied to create "
+                           "socket of type SOCK_STREAM");
+                       break;
+               case ENOMEM:
+                       log("IRC -> socket(): Insufficient memory to "
+                           "allocate socket");
+                       break;
+               default:
+                       log("IRC -> socket(): Unknown error allocating "
+                           "socket");
+                       break;
+               }
+               exit(EXIT_FAILURE);
+       }
+
+       if (CONF_BINDIRC) {
+               if (!inet_aton(CONF_BINDIRC, &(IRC_LOCAL.sin_addr))) {
+                       log("IRC -> bind(): %s is an invalid address",
+                           CONF_BINDIRC);
+                       exit(EXIT_FAILURE);
+               }
+
+               IRC_LOCAL.sin_family = AF_INET;
+               IRC_LOCAL.sin_port = 0;
+
+               if (bind(IRC_FD, (struct sockaddr *)&IRC_LOCAL,
+                   sizeof(struct sockaddr_in)) == -1) {
+                       switch(errno) {
+                       case EACCES:
+                               log("IRC -> bind(): No access to bind to %s",
+                                   CONF_BINDIRC);
+                               break;
+                       default:
+                               log("IRC -> bind(): Error binding to %s (%d)",
+                                   CONF_BINDIRC, errno);
+                               break;
+                       }
+                       exit(EXIT_FAILURE);
+               }
+       }
+}
+
+
+/* 
+ * Send data to remote IRC host.
+ */
+
+
+void irc_send(char *data, ...)
+{
+       va_list arglist;
+       char    data2[MSGLENMAX];
+       char    tosend[MSGLENMAX];
+       va_start(arglist, data);
+       vsnprintf(data2, MSGLENMAX - 1, data, arglist);
+       va_end(arglist);
+
+       if (OPT_DEBUG >= 2)
+               log("IRC SEND -> %s", data2);
+
+       snprintf(tosend, MSGLENMAX - 1, "%s\n", data2);
+
+       if (send(IRC_FD, tosend, strlen(tosend), 0) == -1) {
+               /* Return of -1 indicates error sending data; we reconnect. */
+               irc_reconnect();
+       }
+}
+
+/*
+ * K:line given ip for given reason.
+ */
+
+void irc_kline(char *addr, char *ip)
+{
+       irc_send(CONF_KLINE_COMMAND, addr, ip);
+}
+
+/*
+ * Create socket and connect to IRC server specificied in config file
+ * (CONF_SERVER) with port CONF_PORT.
+ */
+
+static void irc_connect(void)
+{
+       /* Connect to IRC server as client. */
+       if (connect(IRC_FD, (struct sockaddr *) &IRC_SVR,
+           sizeof(IRC_SVR)) == -1) {
+               switch(errno) {
+               case EISCONN: 
+                       /* Already connected */
+                       return;
+               case ECONNREFUSED:
+                       log("IRC -> connect(): Connection refused by (%s)",
+                           CONF_SERVER);
+                       break;
+               case ETIMEDOUT:
+                       log("IRC -> connect(): Timed out connecting to (%s)",
+                           CONF_SERVER);
+                       break;
+               case ENETUNREACH:
+                       log("IRC -> connect(): Network unreachable");
+                       break;
+               case EALREADY:
+                       /* Previous attempt not complete */
+                       return;
+               default:
+                       log("IRC -> connect(): Unknown error connecting to (%s)",
+                           CONF_SERVER);
+
+                        if (OPT_DEBUG >= 1)
+                               log(strerror(errno));
+               }       
+               exit(EXIT_FAILURE);
+       }
+
+#ifdef WITH_UNREAL
+       irc_send("PROTOCTL HCN");
+#endif /* WITH_UNREAL */
+
+       irc_send("NICK %s",CONF_NICK);
+       if (CONF_PASSWORD)
+               irc_send("PASS %s",CONF_PASSWORD);
+       irc_send("USER %s %s %s :%s", CONF_USER, CONF_USER, CONF_USER,
+           CONF_REALNAME);
+}
+
+
+static void irc_reconnect(void)
+{
+       if(IRC_FD > 0)
+               close(IRC_FD);
+
+       /* Set IRC_FD 0 for reconnection on next irc_cycle(). */
+       IRC_FD = 0;
+
+       log("IRC -> Connection to (%s) lost, rehashing and reconnecting.",
+           CONF_SERVER);
+}
+
+/*
+ * Read one character at a time until an endline is hit, at which time control
+ * is passed to irc_parse() to parse that line.
+ */
+static void irc_read(void)
+{
+       int len;
+       char c;
+
+       while ((len = read(IRC_FD, &c, 1))) {
+               if (len <= 0) {
+                       irc_reconnect();
+                       return;
+               }
+            
+               if (c == '\r')
+                       continue;
+               
+               if (c == '\n') {
+                       /* Null string. */
+                       IRC_RAW[IRC_RAW_LEN] = 0;
+                       /* Parse line. */
+                       irc_parse();
+                       /* Reset counter. */
+                       IRC_RAW_LEN = 0;
+                       break;
+               }
+
+               if (c != '\r' && c != '\n' && c != 0)
+                       IRC_RAW[IRC_RAW_LEN++] = c;
+       }
+       
+       if (len <= 0) {
+               irc_reconnect();
+               return;
+       } 
+}
+
+/*
+ * A full line has been read by irc_read(); this function begins parsing it.
+ */
+
+static void irc_parse(void)
+{
+       char nick[NICKMAX];
+       char *token[32];
+       time_t present;
+       size_t prefixlen;
+       unsigned int tokens;
+       char *irc_channel, *key, *user, *target, *msg;
+
+       tokens = 0;
+
+       /* Update timeout tracking. */ 
+       time(&IRC_LAST);
+
+       if(OPT_DEBUG >= 2)
+               log("IRC READ -> %s", IRC_RAW);
+
+       /*
+        * Tokenize the first 32 words in the incoming data, we really don't
+        * need to worry about anything else and we don't need the original
+        * string for anything.
+        */
+
+       token[tokens] = strtok(IRC_RAW, " ");
+
+       while (++tokens < 32 && (token[tokens] = strtok(NULL, " ")))
+               ; 
+
+       /* Anything with less than 1 token is useless to us. */  
+
+       if (tokens <= 1)
+               return;
+
+       if (!strcasecmp(token[0], "PING")) {
+               irc_send("PONG %s", token[1]);
+               return;
+       }
+
+       /* 001 is sent on initial connect to the IRC host. */
+
+       if (!strcasecmp(token[1], "001")) { 
+               do_perform();
+               if (CONF_AWAY)
+                       irc_send("AWAY :%s (/msg %s INFO)", CONF_AWAY, CONF_NICK);
+               irc_send("OPER %s", CONF_OPER);
+               irc_send("MODE %s %s", CONF_NICK, CONF_OPER_MODES);      
+               return;
+       }   
+    
+       /* 471, 473, 474, 475 are 'Cannot Join' messages. */
+
+       if (!strcasecmp(token[1], "471") ||
+           !strcasecmp(token[1], "473") ||
+           !strcasecmp(token[1], "474") ||
+           !strcasecmp(token[1], "475")) { 
+               if(CONF_CHANSERV_INVITE) {
+                       /* 4th token is channel we can't join. */             
+                       irc_send(CONF_CHANSERV_INVITE, token[3]);
+               }
+               return;
+       }
+
+       /*
+        * Handle invites, complicated code ahead is due to a decision not to
+        * use strtok() or strstr() in the following block
+        */
+
+       if (!strcasecmp(token[1], "INVITE")) {
+               /* token 4 is the channel, + 1 to shift past ':'. */
+               irc_channel = check_channel(token[3] + 1);
+
+               if (irc_channel) {
+                       key = get_chan_key(irc_channel);
+
+                       if (key)
+                               irc_send("JOIN %s %s", irc_channel, key);
+                       else
+                               irc_send("JOIN %s", irc_channel);
+
+                       return;
+               }
+       }
+    
+       /* Handle nickserv identification. */
+            
+       if (!strcasecmp(token[1], "NOTICE") && strchr(token[0], '@')) {
+               if (CONF_NICKSERV_IDENT &&
+                   !strcasecmp(strtok(token[0] + 1, "!") , "NICKSERV")) {
+                       time(&present);
+                       /*
+                        * If last used notice was greater than/equal to
+                        * 10 sec ago
+                        */
+                       if ((present - IRC_NICKSERV_LAST) >= 10) {
+                               /* Identify to nickserv. */  
+                               irc_send(CONF_NICKSERV_IDENT);
+                               /* Record last ident. */
+                               time(&IRC_NICKSERV_LAST);
+                       }
+                       return;
+               }
+          }
+
+       /* Handle rejoining when kicked. */
+
+       /* :grifferz!goats@pc-62-30-219-54-pb.blueyonder.co.uk KICK #wg penguinBopm :test */
+       if (!strcasecmp(token[1], "KICK") &&
+           !strcasecmp(token[3], CONF_NICK)) {
+               /*
+                * Someone kicked us from channel token[2] so let's
+                * rejoin.
+                */
+               log("IRC -> Kicked from %s by %s! (%s)", token[2],
+                   token[0], token[4]);
+               key = get_chan_key(token[2]);
+
+               if (key)
+                       irc_send("JOIN %s %s", token[2], key);
+               else
+                       irc_send("JOIN %s", token[2]);
+               return;
+       }
+
+       /* Any messages from users that we need to respond to. */
+       if (!strcasecmp(token[1], "PRIVMSG") && token[0][0] == ':') {
+               /* work out who it was from */
+               strncpy(nick, token[0] + 1, NICKMAX);
+               user = index(nick, '!');
+
+               if(user) {
+                       /*
+                        * Nick is currently the first 32 chars of a userhost,
+                        * so null terminate at !
+                        */
+                       *user = '\0';
+
+                       msg = token[3];
+
+                       if (msg && msg[0] == ':')
+                               msg++;
+
+                       prefixlen = strlen(msg);
+
+                       if (token[2][0] == '#' || token[2][0] == '&')
+                               target = CONF_CHANNELS;
+                       else
+                               target = nick;
+
+                       /* CTCP VERSION */
+                       if (strncasecmp(msg, "\001VERSION\001", 9) == 0) {
+                               irc_send("NOTICE %s :\001VERSION Blitzed "
+                                   "Open Proxy Monitor %s\001", nick,
+                                   VERSION);
+                               return;
+                       }
+
+                       if (strncasecmp(msg, "INFO", 4) == 0) {
+                               irc_send("NOTICE %s :This bot is designed "
+                                   "to scan incoming connections for the "
+                                   "presence of open SOCKS, HTTP and "
+                                   "other similar servers.", nick);
+                               irc_send("NOTICE %s :These misconfigured "
+                                   "servers allow anyone to abuse them "
+                                   "to 'bounce' through, and are "
+                                   "frequently used to harass.  As a "
+                                   "result, use of such proxies is not "
+                                   "permitted on this IRC network.", nick);
+                               irc_send("NOTICE %s :If you found this bot "
+                                   "because of NukeNabber or other "
+                                   "firewall software on your computer, "
+                                   "please be aware that this is \ 2not\ 2 "
+                                   "a nuke or any other form of abusive "
+                                   "activity.", nick);
+                               irc_send("NOTICE %s :You can get more "
+                                   "information about this bot and what "
+                                   "it does by contacting %s.", nick,
+                                   CONF_HELP_EMAIL);
+                               return;
+                       }
+
+                       if (strncasecmp(msg, CONF_NICK,
+                           prefixlen > 3 ? prefixlen : 3) &&
+                           strcasecmp(msg, "!all")) {
+                               /*
+                                * Not in the form we accept, ignore this
+                                * message
+                                */
+                               return;
+                       }
+
+                       if (!token[4]) {
+                               irc_send("PRIVMSG %s :Some form of "
+                                   "command would be nice.", target);
+                               return;
+                       }
+              
+                       if (strncasecmp(token[4], "STAT", 4) == 0) {
+                               do_stats(target);
+                               return;
+                       }
+
+                       /* Otherwise it might be an oper command. */
+                       do_oper_cmd(nick, token[4], token[5], target);
+               }
+       }
+
+       if (!strcasecmp(token[1], "302")) {
+               check_userhost(token[3]);
+               return;
+       }
+
+       /* Search for +c notices. */
+       /* Some ircd (just hybrid/xnet/df?) don't send a server name. */
+       if (tokens >= 11 && strcasecmp(token[0], "NOTICE") == 0 &&
+           strcasecmp(token[6], "connecting:") == 0)
+               do_xnet_connect(tokens, token);
+
+       if (token[0][0] == ':') {
+               /* Toss any notices NOT from a server. */
+
+               if (strchr(token[0], '@'))
+                       return;
+
+               if (tokens >= 11 && strcmp(token[7], "connecting:") == 0)
+                       do_hybrid_connect(tokens, token);
+               else if (tokens >= 9 && strcmp(token[4], "connecting:") == 0)
+                       do_trircd_connect(tokens, token);
+               else if (tokens >= 17 && strcmp(token[8], "Client") == 0 &&
+                   strcmp(token[9], "connecting") == 0)
+                       do_ultimateircd_connect(tokens, token);
+       }
+}
+
+/*
+ * Perform on connect functions.
+ */
+
+static void do_perform(void)
+{    
+       log("IRC -> Connected to %s:%d", CONF_SERVER, CONF_PORT);
+
+       if (CONF_NICKSERV_IDENT) {
+               /* Identify to nickserv. */
+               irc_send(CONF_NICKSERV_IDENT);
+       }
+       
+       /* Join all listed channels. */
+       if (CONF_KEYS)
+               irc_send("JOIN %s %s", CONF_CHANNELS, CONF_KEYS);
+       else
+               irc_send("JOIN %s", CONF_CHANNELS);
+}
+
+/*
+ * Functions we need to perform ~1 seconds.
+ */
+
+void irc_timer(void)
+{
+       time_t present;
+   
+       time(&present);
+   
+       /* No data in NODATA_TIMEOUT minutes (set in options.h). */
+       if ((present - IRC_LAST) >= NODATA_TIMEOUT) {
+               irc_reconnect();
+               /* Make sure we dont do this again for another 5 minutes */
+               time(&IRC_LAST);
+       }
+
+       /* Get rid of old command structures. */
+       if ((present - LAST_REAP_TIME) >= 120) {
+               reap_commands(present);
+               time(&LAST_REAP_TIME);
+       }
+}
+
+static void do_connect(char *addr, char *irc_nick, char *irc_user,
+    char *irc_addr, char *conn_notice)
+{
+       string_list *list;
+
+       /*
+        * Check that neither the user's IP nor host matches anything in our
+        * exclude list.
+        */
+       for (list = (string_list *) CONF_EXCLUDE; list; list = list->next) {
+               if (match(list->text, addr) || match(list->text, irc_addr)) {
+                       if (OPT_DEBUG) {
+                               log("SCAN -> excluded user %s!%s@%s",
+                                   irc_nick, irc_user, irc_addr);
+                       }
+                       return;
+               }
+       }
+   
+       if (CONF_DNSBL_ZONE &&
+           dnsbl_check(addr, irc_nick, irc_user, irc_addr))
+               return;
+
+       scan_connect(addr, irc_addr, irc_nick, irc_user, 0, conn_notice);
+}
+
+/*
+ * :porkscratchings.pa.us.blitzed.org NOTICE grifferz :*** Notice -- Client connecting: griff (goats@pc-62-30-219-54-pb.blueyonder.co.uk) [62.30.219.54] {1}
+ */
+static void do_hybrid_connect(int tokens, char **token)
+{
+       char conn_notice[MSGLENMAX];
+       char *addr;     /* IP of remote host in connection notices */
+       char *irc_addr; /* IRC host address of the remote host     */
+       char *irc_user;     
+       char *irc_nick;
+
+       /* Paranoia. */
+       if (tokens < 11)
+               return;
+
+       STAT_NUM_CONNECTS++;
+
+       /*
+        * Take a copy of the original connect notice now in case we need it
+        * for evidence later.
+        */
+       snprintf(conn_notice, sizeof(conn_notice),
+           "%s %s %s %s %s %s %s %s %s %s %s", token[0], token[1],
+           token[2], token[3], token[4], token[5], token[6], token[7],
+           token[8], token[9], token[10]);
+
+       /* Make sure it is null terminated. */
+       conn_notice[MSGLENMAX - 1] = '\0';
+
+       /*
+        * Token 11 is the IP of the remote host enclosed in [ ]. We need
+        * to remove it from [ ] and pass it to the scanner.
+        */
+
+       /* Shift over 1 byte to pass over [. */
+       addr = token[10] + 1;
+        /* Replace ] with a \0. */
+       addr = strtok(addr, "]");
+
+       /* Token 9 is the nickname of the connecting client. */
+       irc_nick = token[8];
+
+       /*
+        * Token 10 is (user@host), we want to parse the user/host out for
+        * future reference in case we need to kline the host.
+        */
+       
+        /* Shift one byte over to discard '('. */
+       irc_user = token[9] + 1;
+       /* Username is everything before the '@'. */
+       if(!(irc_user = strtok(irc_user, "@")))
+               return;
+       /* irc_addr is everything between '@' and closing ')'. */
+       if(!(irc_addr = strtok(NULL , ")")))
+               return;
+       
+       do_connect(addr, irc_nick, irc_user, irc_addr, conn_notice);
+}
+
+/*
+ * :test.teklan.com.tr NOTICE &CONNECTS :Client connecting: griff (andy@pc-62-30-219-54-pb.blueyonder.co.uk) [62.30.219.54] {1}
+ */
+static void do_trircd_connect(int tokens, char **token)
+{
+       char conn_notice[MSGLENMAX];
+       char *addr;     /* IP of remote host in connection notices */
+       char *irc_addr; /* IRC host address of the remote host     */
+       char *irc_user;     
+       char *irc_nick;
+
+       /* Paranoia. */
+       if (tokens < 9)
+               return;
+
+       STAT_NUM_CONNECTS++;
+
+       /*
+        * Take a copy of the original connect notice now in case we need it
+        * for evidence later.
+        */
+       snprintf(conn_notice, sizeof(conn_notice),
+           "%s %s %s %s %s %s %s %s %s", token[0], token[1], token[2],
+           token[3], token[4], token[5], token[6], token[7], token[8]);
+
+       /* Make sure it is null terminated. */
+       conn_notice[MSGLENMAX - 1] = '\0';
+
+       /*
+        * Token 8 is the IP of the remote host enclosed in [ ]. We need
+        * to remove it from [ ] and pass it to the scanner.
+        */
+
+       /* Shift over 1 byte to pass over [. */
+       addr = token[7] + 1;
+        /* Replace ] with a \0. */
+       addr = strtok(addr, "]");
+
+       /* Token 6 is the nickname of the connecting client */
+       irc_nick = token[5];
+
+       /*
+        * Token 7 is (user@host), we want to parse the user/host out for
+        * future reference in case we need to kline the host.
+        */
+       
+        /* Shift one byte over to discard '('. */
+       irc_user = token[6] + 1;
+       /* username is everything before the '@' */
+       if(!(irc_user = strtok(irc_user, "@")))
+               return;
+       /* irc_addr is everything between '@' and closing ')' */
+       if(!(irc_addr = strtok(NULL , ")")))
+               return;
+       
+       do_connect(addr, irc_nick, irc_user, irc_addr, conn_notice);
+}
+
+/*
+ * :CurCuNa.NeT NOTICE AndyBopm :*** Connect/Exit -- from CurCuNa.NeT: Client connecting on port 6667: Misafir (jirc@213.14.40.51) [213.14.40.51] {1} [JPilot jIRC applet User]
+ */
+static void do_ultimateircd_connect(int tokens, char **token)
+{
+       char conn_notice[MSGLENMAX];
+       char *addr;     /* IP of remote host in connection notices */
+       char *irc_addr; /* IRC host address of the remote host     */
+       char *irc_user;     
+       char *irc_nick;
+
+       /* Paranoia. */
+       if (tokens < 17)
+               return;
+
+       STAT_NUM_CONNECTS++;
+
+       /*
+        * Take a copy of the original connect notice now in case we need it
+        * for evidence later.
+        */
+       snprintf(conn_notice, sizeof(conn_notice),
+           "%s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s", token[0],
+           token[1], token[2], token[3], token[4], token[5], token[6],
+           token[7], token[8], token[9], token[10], token[11], token[12],
+           token[13], token[14], token[15], token[16]);
+
+       /* Make sure it is null terminated. */
+       conn_notice[MSGLENMAX - 1] = '\0';
+
+       /*
+        * Token 16 is the IP of the remote host enclosed in [ ]. We need
+        * to remove it from [ ] and pass it to the scanner.
+        */
+
+       /* Shift over 1 byte to pass over [. */
+       addr = token[15] + 1;
+        /* Replace ] with a \0. */
+       addr = strtok(addr, "]");
+
+       /* Token 14 is the nickname of the connecting client. */
+       irc_nick = token[13];
+
+       /*
+        * Token 15 is (user@host), we want to parse the user/host out for
+        * future reference in case we need to kline the host.
+        */
+       
+        /* Shift one byte over to discard '('. */
+       irc_user = token[14] + 1;
+       /* Username is everything before the '@'. */
+       if(!(irc_user = strtok(irc_user, "@")))
+               return;
+       /* irc_addr is everything between '@' and closing ')' */
+       if(!(irc_addr = strtok(NULL , ")")))
+                return;
+       
+       do_connect(addr, irc_nick, irc_user, irc_addr, conn_notice);
+}
+
+
+
+/*
+ * NOTICE BopmMirage :*** Notice -- Client connecting: Iain (iain@modem-449.gacked.dialup.pol.co.uk) [62.25.241.193] {1} (6667)
+ */
+static void do_xnet_connect(int tokens, char **token)
+{
+       char conn_notice[MSGLENMAX];
+       char *addr;     /* IP of remote host in connection notices */
+       char *irc_addr; /* IRC host address of the remote host     */
+       char *irc_user;     
+       char *irc_nick;
+
+       /* Paranoia. */
+       if (tokens < 11)
+               return;
+
+       STAT_NUM_CONNECTS++;
+
+       /*
+        * Take a copy of the original connect notice now in case we need
+        * it for evidence later.
+        */
+       snprintf(conn_notice, sizeof(conn_notice),
+           "%s %s %s %s %s %s %s %s %s %s %s", token[0], token[1],
+           token[2], token[3], token[4], token[5], token[6], token[7],
+           token[8], token[9], token[10]);
+
+       /* Make sure it is null terminated. */
+       conn_notice[MSGLENMAX - 1] = '\0';
+         
+       /*
+        * Token 10 is the IP of the remote host enclosed in [ ]. We need to
+        * remove it from [ ] and pass it to the scanner.
+        */
+       
+       /* Shift over 1 byte to pass over [. */
+       addr = token[9] + 1;
+       /* Replace ] with a \0. */
+        addr = strtok(addr, "]");
+
+       /* Token 8 is the nickname of the connecting client. */
+       irc_nick = token[7];
+
+       /*
+        * Token 9 is (user@host), we want to parse the user/host out for
+        * future reference in case we need to kline the host.
+        */
+
+       /* Shift one byte over to discard '('. */
+       irc_user = token[8] + 1;
+       /* Username is everything before the '@'. */
+       if(!(irc_user = strtok(irc_user, "@")))
+               return;
+       /* irc_addr is everything between '@' and closing ')'. */
+       if(!(irc_addr = strtok(NULL , ")")))
+               return;
+
+       do_connect(addr, irc_nick, irc_user, irc_addr, conn_notice);
+}
+
+/*
+ * Return a pointer into CONF_KEYS for the given channel, or NULL if there
+ * is no key.
+ */
+static char *get_chan_key(const char *channel)
+{
+       int ci, ki;
+       char *kp;
+       size_t i, h, len;
+
+       ci = 0;
+       
+       if (!CONF_KEYS || !channel)
+               return(NULL);
+
+       len = strlen(CONF_CHANNELS);
+
+       for (i = 0; i < len; i++) {
+               if (CONF_CHANNELS[i] != '#') 
+                       continue;
+               
+               for (h = (i + 1); h < len; h++) {
+                       if (CONF_CHANNELS[h] == ',' ||
+                           CONF_CHANNELS[h] == ' ' || h == (len - 1)) {
+                               if (CONF_CHANNELS[h] == ',')
+                                       ci++;
+
+                               if (h == (len - 1))
+                                       h++;
+
+                               if (strlen(channel) != (h - i))
+                                       break; 
+
+                               if (!strncasecmp(&(CONF_CHANNELS[i]),
+                                   channel, strlen(channel))) {
+                                       for (kp = CONF_KEYS, ki = 0;
+                                           (ki < ci) && (kp = strchr(kp, ','));
+                                           ki++) ; /* empty loop */
+
+                                       if (kp && *kp == ',')
+                                               kp++;
+
+                                       if (kp && *kp)
+                                               return(kp);
+                                       else
+                                               return(NULL);
+                               }
+                       }
+               }
+       }
+       return(NULL);
+}
+
+/*
+ * Check if channel is one of our configured report channels, and return a
+ * pointer to it if so, or NULL if not.
+ */
+static char *check_channel(const char *channel)
+{
+       size_t i, len, h;
+       
+       len = strlen(CONF_CHANNELS);
+
+       for (i = 0; i < len; i++) {
+               if (CONF_CHANNELS[i] != '#') 
+                       continue;
+
+               for (h = (i + 1); h < len; h++) {
+                       if (CONF_CHANNELS[h] == ',' ||
+                           CONF_CHANNELS[h] == ' ' || h == (len - 1)) {
+                               if(h == (len - 1))
+                                       h++;
+                                   
+                               if (strlen(channel) != (h - i))
+                                       break; 
+                                 
+                               if (!strncasecmp(&(CONF_CHANNELS[i]),
+                                   channel, strlen(channel))) {
+                                       return(&(CONF_CHANNELS[i]));
+                               }
+                       }
+               }
+       }
+       return(NULL);
+}
diff --git a/src/irc.h b/src/irc.h
new file mode 100644 (file)
index 0000000..aa1eef9
--- /dev/null
+++ b/src/irc.h
@@ -0,0 +1,12 @@
+#ifndef IRC_H
+#define IRC_H
+
+#define NICKMAX 32
+#define MSGLENMAX 513
+
+extern void irc_send(char *data, ...);
+extern void irc_kline(char *addr, char *ip);
+extern void irc_cycle(void);
+extern void irc_timer(void);
+
+#endif
diff --git a/src/log.c b/src/log.c
new file mode 100644 (file)
index 0000000..779e89a
--- /dev/null
+++ b/src/log.c
@@ -0,0 +1,84 @@
+/*
+Copyright (C) 2002  Erik Fears
+
+This program 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.
+
+This program 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 received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+
+      Foundation, Inc.
+      59 Temple Place - Suite 330
+      Boston, MA  02111-1307, USA.
+
+*/
+
+#include "setup.h"
+
+#include <stdio.h>
+
+#ifdef STDC_HEADERS
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#endif
+
+#include <time.h>
+
+#include "config.h"
+#include "extern.h"
+#include "log.h"
+
+
+FILE *logfile;
+
+void log_open(char *filename)
+{
+       logfile = fopen(filename, "a");
+    
+       if (!logfile) {
+               perror("Cannot open log file. Aborting.");
+               exit(EXIT_FAILURE);
+       }
+}
+
+void log_close(void)
+{
+       fclose(logfile);
+}
+
+void log(char *data, ...)
+{
+        char data2[513];
+       char buf_present[25];
+        va_list arglist;
+       time_t present;
+       struct tm *tm_present;
+       if (!OPT_DEBUG && !logfile)
+               return;
+
+       time(&present);
+       tm_present = gmtime(&present);
+       strftime(buf_present, sizeof(buf_present), "%b %d %H:%M:%S %Y",
+           tm_present);
+       va_start(arglist, data);
+       vsnprintf(data2, 512, data, arglist);
+       va_end(arglist);
+
+       if (OPT_DEBUG) {
+               fprintf(stderr, "[%s] %s\n", buf_present, data2);
+       } else {
+               fprintf(logfile, "[%s] %s\n", buf_present, data2);
+               fflush(logfile);
+       }
+}
+
diff --git a/src/log.h b/src/log.h
new file mode 100644 (file)
index 0000000..fa696e7
--- /dev/null
+++ b/src/log.h
@@ -0,0 +1,9 @@
+#ifndef LOG_H
+#define LOG_H
+
+extern void log_open(char *filename);
+extern void log_close(void);
+extern void log(char *data, ...);
+     
+#endif
+
diff --git a/src/main.c b/src/main.c
new file mode 100644 (file)
index 0000000..c290a37
--- /dev/null
@@ -0,0 +1,193 @@
+/*
+Copyright (C) 2002  Erik Fears
+
+This program 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.
+
+This program 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 received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+
+      Foundation, Inc.
+      59 Temple Place - Suite 330
+      Boston, MA  02111-1307, USA.
+
+*/
+
+#include "setup.h"
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <signal.h>
+#include <unistd.h>
+
+#ifdef STDC_HEADERS
+#include <stdlib.h>
+#include <string.h>
+#endif
+
+#include "config.h"
+#include "extern.h"
+#include "irc.h"
+#include "log.h"
+#include "opercmd.h"
+#include "scan.h"
+#include "stats.h"
+#include "options.h"
+
+static RETSIGTYPE do_signal(int signum);
+
+int ALARMED = 0;
+
+unsigned int OPT_DEBUG = 0;
+char *CONFNAME = DEFAULTNAME;
+
+char *CONFDIR = BOPM_ETCDIR;
+char *LOGDIR = BOPM_LOGDIR;
+char *CONFFILE, *LOGFILE, *PIDFILE;
+
+struct sigaction ALARMACTION;
+struct sigaction INTACTION;
+
+int main(int argc, char **argv)
+{
+       char spid[16];
+       int pid, c, lenc, lenl, lenp;
+       FILE *pidout;
+
+       do_stats_init();
+       do_scan_init();
+
+       while (1) {
+               c = getopt(argc, argv, "dc:v:");
+
+               if (c == -1)
+                       break;
+
+               switch (c) {
+               case 'c':
+                       CONFNAME = strdup(optarg);
+                       break;
+               case 'd':
+                       OPT_DEBUG++;
+                       break;
+               case 'v':
+                       CONFDIR = strdup(optarg);
+                       break;
+               case '?':
+               default:
+                       /* Unknown arg, guess we'll just do nothing for now. */
+                       break;
+               }
+       }       
+
+       lenc = strlen(CONFDIR) + strlen(CONFNAME) + strlen(CONFEXT) + 3;
+       lenl = strlen(LOGDIR) + strlen(CONFNAME) + strlen(LOGEXT) + 3;
+       lenp = strlen(LOGDIR) + strlen(CONFNAME) + strlen(PIDEXT) + 3;
+
+       CONFFILE = (char *) malloc(lenc * sizeof(*CONFFILE));
+       LOGFILE = (char *) malloc(lenl * sizeof(*LOGFILE));
+       PIDFILE = (char *) malloc(lenp * sizeof(*PIDFILE));
+
+       snprintf(CONFFILE, lenc, "%s/%s.%s", CONFDIR, CONFNAME, CONFEXT);
+       snprintf(LOGFILE, lenl, "%s/%s.%s", LOGDIR, CONFNAME, LOGEXT);
+       snprintf(PIDFILE, lenp, "%s/%s.%s", LOGDIR, CONFNAME, PIDEXT);
+
+       /* Fork off. */
+
+       if (!OPT_DEBUG) {
+               if ((pid = fork()) < 0) {
+                       perror("fork()");
+                       exit(EXIT_FAILURE);
+               } else if (pid != 0) {
+                       pidout = fopen(PIDFILE, "w");
+                       snprintf(spid, 16, "%d", pid);
+
+                       if (pidout) {
+                               fwrite(spid, sizeof(char), strlen(spid),
+                                   pidout);
+                       }
+
+                       fclose(pidout);
+                       _exit(EXIT_SUCCESS);
+               }
+
+               /* Get us in our own process group. */
+               if (setpgid(0, 0) < 0) {
+                       perror("setpgid()");
+                       exit(EXIT_FAILURE);
+               }
+
+               /* Reset file mode. */
+               /* shasta: o+w is BAD, mmkay? */
+               umask(002);
+
+               /* Close file descriptors. */
+               close(STDIN_FILENO);
+               close(STDOUT_FILENO);
+               close(STDERR_FILENO);
+
+               log_open(LOGFILE); 
+       } else {
+               log("MAIN -> Debug level %d", OPT_DEBUG);
+       }
+
+       log("MAIN -> BOPM %s started.", VERSION);
+       log("MAIN -> Reading configuration file...");
+
+       config_load(CONFFILE);
+
+       /* Setup alarm & int handlers. */
+       ALARMACTION.sa_handler = &(do_signal);  
+       ALARMACTION.sa_flags = SA_RESTART;
+       INTACTION.sa_handler = &(do_signal);
+    
+       sigaction(SIGALRM, &ALARMACTION, 0);
+       sigaction(SIGINT, &INTACTION, 0);
+
+       /* Ignore SIGPIPE. */
+       signal(SIGPIPE, SIG_IGN);
+
+       alarm(1);
+
+       while (1) {
+               irc_cycle();
+               scan_cycle();
+
+               if (ALARMED) {
+                       irc_timer();
+                       scan_timer();
+                       ALARMED = 0;
+               }
+       }
+    
+       if (!OPT_DEBUG)
+               log_close();
+       return(0);
+}
+
+static void do_signal(int signum)
+{
+       switch (signum) {
+       case SIGALRM:
+               ALARMED = 1;
+               alarm(1);
+               break;
+       case SIGINT:
+               log("MAIN -> Caught SIGINT, bye!");
+               exit(0);
+               break;
+       }
+}
diff --git a/src/match.c b/src/match.c
new file mode 100644 (file)
index 0000000..167dafe
--- /dev/null
@@ -0,0 +1,223 @@
+/*
+    Copyright (C) 1990-2002 by Jarkko Oikarinen, Thomas Helvey,
+    Douglas A Lewis and the hybrid ircd development team.  Minor
+    changes were made by and are copyrighted by Robert Levin of
+    the dancer-ircd development team.
+    
+    This program 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 1
+    of the License, or (at your option) any later version.
+    
+    This program 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 received a copy of the GNU General Public
+    License along with this program; if not, write to the Free
+    Software Foundation, Inc., 59 Temple Place - Suite 330,
+    Boston, MA  02111-1307, USA.
+   
+*/
+
+#include <assert.h>
+#include <stdio.h>
+
+#ifdef STDC_HEADERS
+# include <stdarg.h>
+# include <string.h>
+#endif
+
+#include <time.h>
+#include <unistd.h>
+
+#include "match.h"
+
+#define ToLower(c) (ToLowerTab[(unsigned char)(c)])
+
+const unsigned char ToLowerTab[] = {
+       0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xa,
+       0xb, 0xc, 0xd, 0xe, 0xf, 0x10, 0x11, 0x12, 0x13, 0x14,
+       0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 
+       0x1e, 0x1f,
+       ' ', '!', '"', '#', '$', '%', '&', 0x27, '(', ')',
+       '*', '+', ',', '-', '.', '/',
+       '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
+       ':', ';', '<', '=', '>', '?',
+       '@', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i',
+       'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's',
+       't', 'u', 'v', 'w', 'x', 'y', 'z', '[', '\\', ']', '^',
+       '_',
+       '`', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i',
+       'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's',
+       't', 'u', 'v', 'w', 'x', 'y', 'z', '{', '|', '}', '~',
+       0x7f,
+       0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89,
+       0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
+       0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99,
+       0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
+       0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9,
+       0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
+       0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9,
+       0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
+       0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9,
+       0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
+       0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9,
+       0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,
+       0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9,
+       0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
+       0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9,
+       0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff
+};
+
+#define MATCH_MAX_CALLS 512  /* ACK! This dies when it's less that this and
+                               we have long lines to parse */
+
+/*
+ * Compare if a given string (name) matches the given mask (which can
+ * contain wild cards: '*' - match any number of chars, '?' - match any
+ * single character.
+ *
+ * return 1, if match
+ *        0, if no match
+ */
+
+/*
+ * match()
+ * Iterative matching function, rather than recursive.
+ * Written by Douglas A Lewis (dalewis@acsu.buffalo.edu)
+ *
+ * behavior change - (Thomas Helvey <tomh@inxpress.net>)
+ *
+ * removed escape handling, none of the masks used with this function
+ * should contain an escape '\\' unless you are searching for one, it is no
+ * longer possible to escape * and ?.
+ *
+ * Moved calls rollup to function body, since match isn't recursive there
+ * isn't any reason to have it exposed to the file, this change also has
+ * the added benefit of making match reentrant. :)
+ *
+ * Added asserts, mask and name cannot be null.
+ *
+ * Changed ma and na to unsigned to get rid of casting.
+ *
+ * NOTICE: match is now a boolean operation, not a lexical comparison; if a
+ * line matches a mask, true (1) is returned, otherwise false (0) is
+ * returned.
+ */
+
+int match(const char *mask, const char *name)
+{
+       const unsigned char *m = (const unsigned char *)  mask;
+       const unsigned char *n = (const unsigned char *)  name;
+       const unsigned char *ma = (const unsigned char *) mask;
+       const unsigned char *na = (const unsigned char *) name;
+       int wild  = 0;
+       int calls = 0;
+
+       assert(0 != mask);
+       assert(0 != name);
+
+       if (!mask || !name)
+               return 0;
+
+       while (calls++ < MATCH_MAX_CALLS) {
+               if (*m == '*') {
+                       /* XXX - shouldn't need to spin here, the mask
+                        * should have been collapsed before match is
+                        * called
+                        */
+                       while (*m == '*')
+                               m++;
+
+                       wild = 1;
+                       ma = m;
+                       na = n;
+               }
+
+               if (!*m) {
+                       if (!*n)
+                               return 1;
+
+                       for (m--; (m > (const unsigned char *) mask) && (*m == '?'); m--)
+                               ; /* empty loop */
+
+                       if ((*m == '*') && (m > (const unsigned char *) mask))
+                               return 1;
+
+                       if (!wild)
+                               return 0;
+
+                       m = ma;
+                       n = ++na;
+               } else if (!*n) {
+                       /* XXX - shouldn't need to spin here, the mask
+                        * should have been collapsed before match is
+                        * called
+                        */
+                       while (*m == '*')
+                               m++;
+
+                       return (*m == 0);
+               }
+
+               if (ToLower(*m) != ToLower(*n) && *m != '?') {
+                       if (!wild)
+                               return 0;
+
+                       m = ma;
+                       n = ++na;
+               } else {
+                       if (*m)
+                               m++;
+
+                       if (*n)
+                               n++;
+               }
+       }
+       return 0;
+}
+                                       
+
+/*
+ * collapse a pattern string into minimal components.
+ * This particular version is "in place", so that it changes the pattern
+ * which is to be reduced to a "minimal" size.
+ *
+ * behavior modification (Thomas Helvey <tomh@inxpress.net>)
+ * Removed mask escapes, we don't escape wildcards or call match on a mask.
+ * This change is somewhat subtle, the old version converted \\*** to \\**,
+ * the new version blindly converts it to \\*.
+ *
+ * Removed code that did a lot of work but achieved nothing, testing showed
+ * that the code in test for '?' produced exactly the same results as code
+ * that ignored '?'. The only thing you can do with a mask is to remove
+ * adjacent '*' characters, attempting anything else breaks the re.
+ *
+ * convert adjacent *'s to a single *
+ */
+char *collapse(char *pattern)
+{
+       char *s = pattern;
+       char *s1;
+       char *t;
+
+       /* XXX - null pointers OK? */
+       if (s) {
+               for (; *s; s++) {
+                       if ('*' == *s) {
+                               t = s1 = s + 1;
+                               while ('*' == *t)
+                                       ++t;
+
+                               if (s1 != t) {
+                                       while ((*s1++ = *t++))
+                                               ; /* empty loop */
+                               }
+                       }
+               }
+       }
+       return pattern;
+}
+
diff --git a/src/match.h b/src/match.h
new file mode 100644 (file)
index 0000000..cce7077
--- /dev/null
@@ -0,0 +1,7 @@
+#ifndef MATCH_H
+#define MATCH_H
+
+int match(const char *mask, const char *name);
+char *collapse(char *pattern);
+
+#endif    
diff --git a/src/misc.c b/src/misc.c
new file mode 100644 (file)
index 0000000..abf6596
--- /dev/null
@@ -0,0 +1,142 @@
+/*
+Copyright (C) 2002  Erik Fears
+
+This program 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.
+
+This program 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 received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+
+      Foundation, Inc.
+      59 Temple Place - Suite 330
+      Boston, MA  02111-1307, USA.
+
+*/
+
+#include "setup.h"
+
+#include <stdio.h>
+#include <time.h>
+
+#ifdef STDC_HEADERS
+# include <string.h>
+#endif
+
+#include "config.h"
+#include "extern.h"
+
+/*
+ * Split a time_t into an English-language explanation of how
+ * much time it represents, e.g. "2 hours 45 minutes 8 seconds"
+ */
+char *dissect_time(time_t time)
+{
+       static char buf[64];
+       unsigned int years, weeks, days, hours, minutes, seconds;
+
+       years = weeks = days = hours = minutes = seconds = 0;
+
+       while (time >= 60 * 60 * 24 * 365) {
+               time -= 60 * 60 * 24 * 365;
+               years++;
+       }
+
+       while (time >= 60 * 60 * 24 * 7) {
+               time -= 60 * 60 * 24 * 7;
+               weeks++;
+       }
+
+       while (time >= 60 * 60 * 24) {
+               time -= 60 * 60 * 24;
+               days++;
+       }
+
+       while (time >= 60 * 60) {
+               time -= 60 * 60;
+               hours++;
+       }
+
+       while (time >= 60) {
+               time -= 60;
+               minutes++;
+       }
+
+       seconds = time;
+
+       if (years) {
+               snprintf(buf, sizeof(buf),
+                   "%d year%s, %d week%s, %d day%s, %02d:%02d:%02d",
+                   years, years == 1 ? "" : "s", weeks,
+                   weeks == 1 ? "" : "s", days, days == 1 ? "" : "s",
+                   hours, minutes, seconds);
+       } else if (weeks) {
+               snprintf(buf, sizeof(buf),
+                   "%d week%s, %d day%s, %02d:%02d:%02d", weeks,
+                   weeks == 1 ? "" : "s", days, days == 1 ? "" : "s",
+                   hours, minutes, seconds);
+       } else if (days) {
+               snprintf(buf, sizeof(buf), "%d day%s, %02d:%02d:%02d",
+                   days, days == 1 ? "" : "s", hours, minutes, seconds);
+       } else if (hours) {
+               if (minutes || seconds) {
+                       snprintf(buf, sizeof(buf),
+                           "%d hour%s, %d minute%s, %d second%s", hours,
+                           hours == 1 ? "" : "s", minutes,
+                           minutes == 1 ? "" : "s", seconds,
+                           seconds == 1 ? "" : "s");
+               } else {
+                       snprintf(buf, sizeof(buf), "%d hour%s", hours,
+                           hours == 1 ? "" : "s");
+               }
+       } else if (minutes) {
+               snprintf(buf, sizeof(buf), "%d minute%s, %d second%s",
+                   minutes, minutes == 1 ? "" : "s", seconds,
+                   seconds == 1 ? "" : "s");
+       } else {
+               snprintf(buf, sizeof(buf), "%d second%s", seconds,
+                   seconds == 1 ? "" : "s");
+       }
+
+       return(buf);
+}
+
+/*
+ * Strip leading/tailing characters from null terminated str and return a
+ * pointer to the new string.
+ */
+
+char *clean(char *str)
+{
+       size_t i;
+       /* Position of last non space. */
+       int lastnon;
+       /* Position of first non space. */
+       int firstnon;
+
+       lastnon = 0;
+       firstnon = 0;
+
+       /* Dont need to deal with 1 character */ 
+       if (strlen(str) <= 1)
+               return str;
+
+       for (i = 0; i < strlen(str); i++) {
+               if (firstnon == 0 && str[i] != ' ')           
+                       firstnon = i;
+               if (str[i] != ' ')
+                       lastnon = i;  
+       }
+
+       /* Null terminate before the tailing spaces. */ 
+       str[lastnon + 1] = 0;
+       
+       /* Return pointer to point after leading spaces. */
+       return(str + (firstnon - 1));
+}
diff --git a/src/misc.h b/src/misc.h
new file mode 100644 (file)
index 0000000..ac00a82
--- /dev/null
@@ -0,0 +1,7 @@
+#ifndef MISC_H
+#define MISC_H
+
+extern char *dissect_time(time_t time);
+extern char *clean(char *str);
+
+#endif
diff --git a/src/opercmd.c b/src/opercmd.c
new file mode 100644 (file)
index 0000000..11a8002
--- /dev/null
@@ -0,0 +1,171 @@
+/*
+Copyright (C) 2002  Erik Fears
+
+This program 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.
+
+This program 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 received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+
+      Foundation, Inc.
+      59 Temple Place - Suite 330
+      Boston, MA  02111-1307, USA.
+
+*/
+
+#include "setup.h"
+
+#ifdef STDC_HEADERS
+# include <string.h>
+# include <stdlib.h>
+#endif
+
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <time.h>
+
+#include "irc.h"
+#include "log.h"
+#include "misc.h"
+#include "opercmd.h"
+#include "scan.h"
+#include "config.h"
+#include "extern.h"
+
+static void checkoper(const char *nick, const char *param,
+    const char *target, unsigned int cmd_type);
+static void delete_command(unsigned int index);
+
+struct command cmd_stack[MAXCMD];
+time_t LAST_REAP_TIME;
+
+void do_oper_cmd(const char *nick, const char *cmd, const char *param,
+    const char *target)
+{
+       if (strncasecmp(cmd, "CHECK", 5) == 0) {
+               if (!param) {
+                       irc_send("PRIVMSG %s :*ring* Hello, cluephone for "
+                           "%s, you need to specify a host or IP address "
+                           "if you want me to do any checking, yo.",
+                           target, nick);
+                       return;
+               }
+               checkoper(nick, param, target, CMD_CHECK);
+       } else {
+               irc_send("PRIVMSG %s :Sorry, I don't know how to %s, %s.",
+                   target, cmd, nick);
+       }
+       return;
+}
+
+static void checkoper(const char *nick, const char *param,
+    const char *target, unsigned int cmd_type)
+{
+       unsigned int i;
+
+       for (i = 0; i < MAXCMD; i++) {
+               if (cmd_stack[i].type == CMD_NONE) {
+                       cmd_stack[i].type = cmd_type;
+                       cmd_stack[i].param = strdup(param);
+                       cmd_stack[i].target = strdup(target);
+                       strncpy(cmd_stack[i].nick, nick, NICKMAX);
+                       break;
+               }
+       }
+
+       if (i == MAXCMD) {
+               irc_send("PRIVMSG %s :Too many queued commands, try later.",
+                   target);
+       } else {
+               irc_send("USERHOST %s", nick);
+       }
+}
+
+/*
+ * Check a userhost to see if it is from an oper, we're looking for the
+ * asterisk (*) between the nick and the ident as below:
+ * :grifferz*=+goats@pc-62-30-219-54-pb.blueyonder.co.uk
+ */
+void check_userhost(const char *userhost)
+{
+       int c, oper;
+       char *tmp;
+
+       oper = 0;
+   
+       tmp = strchr(userhost, '=');
+
+       if (!tmp) {
+               /* Looks like they quit, oh well, just ignore it. */
+               return;
+       }
+
+       if (*(tmp - 1) == '*') {
+               oper = 1;
+               tmp--;
+       }
+
+       /* Null terminate userhost so we have a nickname there now. */
+       *tmp = '\0';
+
+       /* Go through the command list looking for commands by this person */
+       for (c = 0; c < MAXCMD; c++) {
+               if (!strcasecmp(userhost + 1, cmd_stack[c].nick)) {
+                       if (oper) {
+                               /* Do the command. */
+                               if (cmd_stack[c].type == CMD_CHECK) {
+                                       do_manual_check(&cmd_stack[c]);
+                               }
+                       } else {
+                               irc_send("PRIVMSG %s :You are not an IRC "
+                                   "Operator.  Go away.",
+                                   cmd_stack[c].target);
+                       }
+
+                       delete_command(c);
+               }
+       }
+}
+
+/*
+ * Set a command to CMD_NONE and free all resources it used, so that it
+ * can be reused later.
+ */
+static void delete_command(unsigned int index)
+{
+       if (cmd_stack[index].type == CMD_NONE)
+               return;
+   
+       cmd_stack[index].type = CMD_NONE;
+       cmd_stack[index].added = 0;
+       free(cmd_stack[index].param);
+       free(cmd_stack[index].target);
+}
+
+/*
+ * Delete any commands which are more than 2 minutes old, they are almost certainly
+ * no longer relevant.
+ */
+void reap_commands(time_t present)
+{
+       int c;
+
+       for (c = 0; c < MAXCMD; c++) {
+               if (cmd_stack[c].type != CMD_NONE &&
+                   (present - cmd_stack[c].added >= 120)) {
+                       irc_send("PRIVMSG %s :Reaping dead command from "
+                           "%s of type %u with param '%s', added %s ago.",
+                           cmd_stack[c].nick, cmd_stack[c].type,
+                           cmd_stack[c].param,
+                           dissect_time(present - cmd_stack[c].added));
+                       delete_command(c);
+               }
+       }
+}
diff --git a/src/opercmd.h b/src/opercmd.h
new file mode 100644 (file)
index 0000000..613e6b7
--- /dev/null
@@ -0,0 +1,40 @@
+#ifndef OPERCMD_H
+#define OPERCMD_H
+
+struct command {
+       /* Types defined below. */
+       /* THIS MUST BE CMD_NONE FOR AN EMPTY COMMAND! */
+       unsigned int type;
+
+       /* Command parameter.
+        * <erik> but i cant think of any commands bopm will ever have that is
+        *   multiple parameters
+        */
+       char *param;
+       
+       /* Who ordered it. */   
+       char nick[NICKMAX];
+
+       /* Where the reply is to be sent. */
+       char *target;
+
+       /*
+        * When it was added, because we might need to remove it if it does
+        * not get executed.
+        */
+       time_t added;
+};
+
+/* Allow 5 outstanding commands. */
+#define MAXCMD 5
+
+/* One for each oper command we support. */
+#define CMD_NONE  0
+#define CMD_CHECK 1
+
+extern void do_oper_cmd(const char *nick, const char *cmd,
+    const char *param, const char *target);
+extern void check_userhost(const char *userhost);
+extern void reap_commands(time_t present);
+
+#endif
diff --git a/src/options.h b/src/options.h
new file mode 100644 (file)
index 0000000..99a8793
--- /dev/null
@@ -0,0 +1,33 @@
+#ifndef OPTIONS_H
+#define OPTIONS_H
+  
+/* The default name for conf, log, pid files */
+#define DEFAULTNAME "bopm"
+
+/* file extensions */
+/* config */
+#define CONFEXT "conf"
+
+/* log file */
+#define LOGEXT "log"
+
+/* PID file */
+#define PIDEXT "pid"
+
+/* Defines time in which bot will timeout * if no data is received
+ * (default 15 min) */
+#define NODATA_TIMEOUT 900
+
+#define MAX_POLL 1024
+
+/* Client buffer size for scan 
+ * Increase as needed, but should never need to be be over 512 bytes */
+
+#define SCANBUFFER 128
+
+/* Max data to read from any port before closing the connection
+ * (to avoid flood attempts)
+ */
+#define MAXREAD 4096
+     
+#endif /* OPTIONS_H */
diff --git a/src/scan.c b/src/scan.c
new file mode 100644 (file)
index 0000000..8f238a8
--- /dev/null
@@ -0,0 +1,845 @@
+/*
+Copyright (C) 2002  Erik Fears
+
+This program 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.
+
+This program 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 received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+
+      Foundation, Inc.
+      59 Temple Place - Suite 330
+      Boston, MA  02111-1307, USA.
+
+*/
+
+#include "setup.h"
+
+#include <stdio.h>
+#include <unistd.h>
+
+#ifdef STDC_HEADERS
+# include <stdlib.h>
+# include <string.h>
+#endif
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+
+#ifdef TIME_WITH_SYS_TIME
+# include <sys/time.h>
+# include <time.h>
+#else
+# ifdef HAVE_SYS_TIME_H
+#  include <sys/time.h>
+# else
+#  include <time.h>
+# endif
+#endif
+
+#include <errno.h>
+#include <fcntl.h>
+
+#ifdef HAVE_SYS_POLL_H
+# include <sys/poll.h>
+#endif
+
+#include "config.h"
+#include "irc.h"
+#include "log.h"
+#include "opercmd.h"
+#include "scan.h"
+#include "stats.h"
+#include "dnsbl.h"
+#include "extern.h"
+#include "options.h"
+
+static void scan_memfail(void);
+static void scan_establish(scan_struct *conn);
+static void scan_check(void);
+static void scan_negfail(scan_struct *conn);
+static void scan_readready(scan_struct *conn);
+static void scan_read(scan_struct *conn);
+static void scan_openproxy(scan_struct *conn);
+static void scan_writeready(scan_struct *conn);
+static void scan_add(scan_struct *newconn);
+static void scan_del(scan_struct *delconn);
+static int scan_w_squid(struct scan_struct *conn);
+static int scan_w_socks4(struct scan_struct *conn);
+static int scan_w_socks5(struct scan_struct *conn);
+static int scan_w_cisco(struct scan_struct *conn);
+static int scan_w_wingate(struct scan_struct *conn);
+
+/* Linked list head for connections. */
+struct scan_struct *CONNECTIONS = 0;
+
+char SENDBUFF[513];
+
+/* Keep track of numbers of open FD's, for use with FDLIMIT. */
+unsigned int FD_USE = 0;
+
+
+/*
+ * Protocol Name, Port, Write Handler, Read Handler
+ *
+ * Always scan Cisco before Wingate, because cisco routers only allow 4
+ * connects at once.
+ */
+
+protocol_hash SCAN_PROTOCOLS[] = {
+
+       {"HTTP"      , 8080, &(scan_w_squid),    0 ,0 },
+/*     {"HTTP"      , 8001, &(scan_w_squid),    0 ,0 },    */
+/*     {"HTTP"      , 8000, &(scan_w_squid),    0 ,0 },    */
+       {"HTTP"      , 3128, &(scan_w_squid),    0 ,0 },
+       {"HTTP"      ,   80, &(scan_w_squid),    0 ,0 },
+       {"Socks4"    , 1080, &(scan_w_socks4),   0 ,0 },
+       {"Socks5"    , 1080, &(scan_w_socks5),   0 ,0 },
+       {"Cisco"     ,   23, &(scan_w_cisco),    0 ,0 },    
+       {"Wingate"   ,   23, &(scan_w_wingate),  0 ,0 },
+};
+
+size_t SCAN_NUMPROTOCOLS;
+
+void do_scan_init(void)
+{
+       SCAN_NUMPROTOCOLS = sizeof(SCAN_PROTOCOLS) / sizeof(protocol_hash);
+}
+
+
+static void scan_memfail(void)
+{
+       log("SCAN -> Error allocating memory.");
+       exit(EXIT_FAILURE);
+}
+
+
+
+/*
+ * IRC client has receieved a +c notice from the remote server. scan_connect
+ * is called with the connecting IP, where we will begin to establish the
+ * proxy testing.
+ */
+
+void scan_connect(char *addr, char *irc_addr, char *irc_nick,
+    char *irc_user, int verbose, char *conn_notice)
+{
+       size_t i;                
+       scan_struct *newconn; 
+
+       if (OPT_DEBUG) {
+               log("SCAN -> checking user %s!%s@%s", irc_nick, irc_user,
+                   irc_addr);
+       }
+
+       /*
+        * Loop through the protocols creating a seperate connection struct
+        * for each port/protocol.
+        */
+
+       for (i = 0; i < SCAN_NUMPROTOCOLS; i++) {
+               newconn = malloc(sizeof(*newconn));
+
+               if (!newconn)
+                       scan_memfail();               
+
+               newconn->addr = strdup(addr);
+               newconn->irc_addr = strdup(irc_addr);
+               newconn->irc_nick = strdup(irc_nick);
+               newconn->irc_user = strdup(irc_user);
+               /* This is allocated later on in scan_establish to save on
+                * memory.
+                */
+               newconn->data = 0;
+               newconn->verbose = verbose;
+               newconn->bytes_read = 0; 
+               newconn->fd = 0;
+     
+               if (conn_notice)
+                       newconn->conn_notice = strdup(conn_notice);
+               else
+                       newconn->conn_notice = 0;
+
+               /*
+                * Give struct a link to information about the protocol it
+                * will be handling.
+                */
+               newconn->protocol = &(SCAN_PROTOCOLS[i]);
+
+               memset(&(newconn->sockaddr), 0, sizeof(struct sockaddr_in));
+
+               /* Fill in sockaddr with information about remote host. */
+               newconn->sockaddr.sin_family = AF_INET;
+               newconn->sockaddr.sin_port =
+                   htons(newconn->protocol->port); 
+               newconn->sockaddr.sin_addr.s_addr = inet_addr(addr);
+               /* Queue connection. */
+               newconn->state = STATE_UNESTABLISHED;
+
+               /* Add struct to list of connections. */
+               scan_add(newconn);
+
+               /* If we have available FD's, overide queue. */
+               if (FD_USE < CONF_FDLIMIT)
+                       scan_establish(newconn);
+               else if (OPT_DEBUG >= 3) {
+                       log("SCAN -> File Descriptor limit (%d) reached, "
+                           "queuing scan for %s", CONF_FDLIMIT,
+                           newconn->addr);
+               }
+       }
+}
+
+/*
+ * Get FD for new socket, bind to interface and connect() (non blocking) then
+ * set conn to ESTABLISHED for write check.
+ */
+static void scan_establish(scan_struct *conn)
+{
+       /* For local bind() */
+       struct sockaddr_in SCAN_LOCAL;
+
+       memset(&SCAN_LOCAL, 0, sizeof(struct sockaddr_in));
+
+       /* Setup SCAN_LOCAL for local bind() */
+       if (CONF_BINDSCAN) {
+               if (!inet_aton(CONF_BINDSCAN, &(SCAN_LOCAL.sin_addr))) {
+                       log("SCAN -> bind(): %s is an invalid address",
+                           CONF_BINDSCAN);
+                       exit(EXIT_FAILURE);
+               }
+
+               SCAN_LOCAL.sin_family = AF_INET;
+               SCAN_LOCAL.sin_port = 0;
+       }
+
+       /* Request file descriptor for socket. */
+       conn->fd = socket(PF_INET, SOCK_STREAM, 0);
+
+        /* Increase global FD Use counter. */
+        FD_USE++;
+
+       /* If error, mark connection for close. */
+       if (conn->fd == -1) {
+               log("SCAN -> Error allocating file descriptor.");
+               conn->state = STATE_CLOSED;
+               return;
+       }
+
+       /* Bind to specific interface designated in conf file. */
+       if (CONF_BINDSCAN) {
+               if (bind(conn->fd, (struct sockaddr *)&SCAN_LOCAL,
+                   sizeof(struct sockaddr_in)) == -1) {
+                       switch (errno) {
+                       case EACCES:
+                               log("SCAN -> bind(): No access to bind to %s",
+                                   CONF_BINDSCAN);
+                               break;
+                       default:
+                               log("SCAN -> bind(): Error binding to %s",
+                                   CONF_BINDSCAN);
+                               break;
+
+                       }
+                       exit(EXIT_FAILURE);
+               }
+       }
+
+       /* Log create time of connection for timeouts. */
+       time(&(conn->create_time));
+       /* Flag conn established (for write). */
+       conn->state = STATE_ESTABLISHED;
+       /* Set socket non blocking. */
+       fcntl(conn->fd, F_SETFL, O_NONBLOCK);
+       /* Connect! */
+       connect(conn->fd, (struct sockaddr *) &(conn->sockaddr),
+           sizeof(conn->sockaddr));
+
+       /* Allocate memory for the scan buffer. */
+       conn->data = malloc((SCANBUFFER + 1) * sizeof(char));
+       conn->datasize = 0;
+
+}
+
+
+/*
+ * Pass one cycle to the proxy scanner so it can do neccessary functions like
+ * testing for sockets to be written to and read from.
+ */
+
+void scan_cycle(void)
+{
+       scan_check();
+}
+
+
+/*
+ * Test for sockets to be written/read to.
+ */
+
+static void scan_check(void)
+{
+#ifdef HAVE_SYS_POLL_H
+       /* MAX_POLL is defined in options.h */
+       static struct pollfd ufds[MAX_POLL];
+       unsigned long size, i;
+#else /* select() */
+       fd_set w_fdset;
+       fd_set r_fdset;
+       struct timeval scan_timeout;
+       int highfd;
+#endif /* HAVE_SYS_POLL_H */
+
+       struct scan_struct *ss;
+  
+       if (!CONNECTIONS)
+               return;
+
+#ifdef HAVE_SYS_POLL_H
+       size = 0;
+
+       /* Get size of list we're interested in. */
+       for (ss = CONNECTIONS; ss; ss = ss->next) {
+               if (ss->state != STATE_CLOSED &&
+                   ss->state != STATE_UNESTABLISHED)
+                       size++;
+       }
+    
+       i = 0;
+
+       /* Setup each element now. */
+       for (ss = CONNECTIONS; ss; ss = ss->next) {
+               if (ss->state == STATE_CLOSED ||
+                   ss->state == STATE_UNESTABLISHED)
+                       continue;
+
+               ufds[i].events = 0;
+               ufds[i].revents = 0;
+               ufds[i].fd = ss->fd;
+
+               /* Check for HUNG UP. */
+               ufds[i].events |= POLLHUP;
+               /* Check for INVALID FD */
+               ufds[i].events |= POLLNVAL;
+
+               switch (ss->state) {
+               case STATE_ESTABLISHED:
+                       /* Check for NO BLOCK ON WRITE. */
+                       ufds[i].events |= POLLOUT;
+                       break;
+               case STATE_SENT:
+                       /* Check for data to be read. */
+                       ufds[i].events |= POLLIN;
+                       break;
+               }
+
+               if (++i >= MAX_POLL)
+                       break;
+       }
+
+#else /* select() */
+       FD_ZERO(&w_fdset);
+       FD_ZERO(&r_fdset);
+       highfd = 0;
+
+       /* Add connections to appropriate sets. */
+
+       for (ss = CONNECTIONS; ss; ss = ss->next) {
+               if (ss->state == STATE_ESTABLISHED) {
+                       if(ss->fd > highfd)    
+                               highfd = ss->fd;
+
+                       FD_SET(ss->fd, &w_fdset);
+                       continue;
+               }
+         
+               if (ss->state == STATE_SENT) {
+                       if (ss->fd > highfd)
+                               highfd = ss->fd;
+             
+                       FD_SET(ss->fd, &r_fdset);
+               }
+       }
+
+       /* No timeout. */
+       scan_timeout.tv_sec = 0;
+       scan_timeout.tv_usec= 0;
+
+#endif /* HAVE_SYS_POLL_H */
+
+
+#ifdef HAVE_SYS_POLL_H
+       switch (poll(ufds, size, 0)) {
+#else /* select() */
+       switch (select((highfd + 1), &r_fdset, &w_fdset, 0, &scan_timeout)) {
+#endif /* HAVE_SYS_POLL_H */
+       case -1:
+               /* error in select/poll */
+               return;
+       case 0:
+               break;
+       default:
+               /* Pass pointer to connection to handler. */
+
+#ifdef HAVE_SYS_POLL_H
+               for (ss = CONNECTIONS; ss; ss = ss->next) {
+                       for (i = 0; i < size; i++) {
+                               if (ufds[i].fd == ss->fd) {
+                                       if (ufds[i].revents & POLLIN)
+                                               scan_readready(ss);
+
+                                       if (ufds[i].revents & POLLOUT)
+                                               scan_writeready(ss);
+             
+                                       if (ufds[i].revents & POLLHUP)
+                                               scan_negfail(ss);
+
+                                       break;
+                               }
+                       }
+               }
+#else
+
+               for (ss = CONNECTIONS; ss; ss = ss->next) {
+                       if ((ss->state == STATE_ESTABLISHED) &&
+                           FD_ISSET(ss->fd, &w_fdset))
+                               scan_writeready(ss);
+
+                       if ((ss->state == STATE_SENT) &&
+                           FD_ISSET(ss->fd, &r_fdset))                    
+                               scan_readready(ss);     
+               }               
+#endif /* HAVE_SYS_POLL_H */
+       }
+}
+
+
+/*
+ * Negotiation failed - Read returned false, we discard the connection as a
+ * closed proxy to save CPU.                                                     
+ */
+static void scan_negfail(scan_struct *conn)
+{
+       if (conn->verbose) {
+               irc_send("PRIVMSG %s :%s (%d): Connection to %s closed, "
+                   "negotiation failed (%d bytes read)", CONF_CHANNELS,
+                   conn->protocol->type, conn->protocol->port,
+                   conn->irc_addr, conn->bytes_read);
+       }
+       conn->state = STATE_CLOSED;
+}
+
+/*
+ * Poll or select returned back that this connection is ready for read.
+ */
+static void scan_readready(scan_struct *conn)
+{
+       char c;
+
+       while(1) {
+               switch (read(conn->fd, &c, 1)) {
+               case  0:
+               case -1:
+                       return;
+
+               default:
+                       conn->bytes_read++;
+                       if (c == 0 || c == '\r')
+                               continue;
+                          
+                       if(c == '\n') {
+                               conn->data[conn->datasize] = 0;
+                               conn->datasize = 0;
+                               scan_read(conn);              
+                               continue;
+                       }
+                       
+                       /* Avoid freezing from reading endless data. */
+                       if (conn->bytes_read >= MAXREAD) {
+                               conn->state = STATE_CLOSED;
+                               return;
+                       }
+
+                       if (conn->datasize < SCANBUFFER) {
+                               /* -1 to pad for null term. */
+                               conn->data[(++conn->datasize) - 1] = c;
+                       }
+               }
+       }
+}
+
+/*
+ * Read one line in from remote, check line against target line.
+ */
+static void scan_read(scan_struct *conn)
+{
+       if (OPT_DEBUG >= 3)
+               log("SCAN -> Checking data from %s [%s:%d] against "
+                   "TARGET_STRING: %s", conn->addr, conn->protocol->type,
+                   conn->protocol->port, conn->data);
+       if (strstr(conn->data, CONF_TARGET_STRING))
+               scan_openproxy(conn);
+}
+
+/*
+ * Test proved positive for open proxy.
+ */
+static void scan_openproxy(scan_struct *conn)
+{
+       scan_struct *ss;
+
+       irc_kline(conn->irc_addr, conn->addr);
+
+       if (CONF_DNSBL_FROM && CONF_DNSBL_TO && CONF_SENDMAIL &&
+           !conn->verbose)                
+               dnsbl_report(conn);
+                
+       log("OPEN PROXY -> %s: %s!%s@%s (%d)", conn->protocol->type,
+           conn->irc_nick, conn->irc_user, conn->irc_addr,
+           conn->protocol->port);
+
+       irc_send("PRIVMSG %s :%s (%d): OPEN PROXY -> %s!%s@%s",
+           CONF_CHANNELS, conn->protocol->type, conn->protocol->port,
+               conn->irc_nick, conn->irc_user, conn->irc_addr);
+
+       /* Increase number OPEN (insecure) of this type. */
+       conn->protocol->stat_numopen++;
+
+       conn->state = STATE_CLOSED;
+
+       /*
+        * Flag connections with the same addr CLOSED aswell, but only if this
+        * is not a verbose check.  When it is verbose/manual, we care about
+        * all types of proxy.  When it is automatic (i.e. when a user
+        * connects) we want them killed quickly sow e can move on.
+        */
+       if (!conn->verbose) {
+               for (ss = CONNECTIONS;ss;ss = ss->next) {
+                       if (conn->sockaddr.sin_addr.s_addr == ss->sockaddr.sin_addr.s_addr)
+                               ss->state = STATE_CLOSED;
+               }
+       }
+}
+
+/*
+ * Poll or select returned back that this connect is ready for write.
+ */
+static void scan_writeready(scan_struct *conn)
+{
+       /* If write returns true, flag STATE_SENT. */
+       if ((*conn->protocol->w_handler)(conn))
+               conn->state = STATE_SENT;
+
+       /* Increase number attempted negotiated of this type. */
+       conn->protocol->stat_num++;
+}
+
+/*
+ * Link struct to connection list.
+ */
+static void scan_add(scan_struct *newconn)
+{
+       scan_struct *ss;
+
+       /* Only item in list. */
+         
+       if (!CONNECTIONS) {
+               newconn->next = 0;
+               CONNECTIONS = newconn;
+       } else {
+               /* Link to end of list. */
+               for(ss = CONNECTIONS; ss; ss = ss->next) {
+                       if (!ss->next) {
+                               newconn->next = 0;
+                               ss->next = newconn;
+                               break;
+                       }
+               }
+       }
+}
+
+
+/*
+ * Unlink struct from connection list and free its memory.
+ */
+static void scan_del(scan_struct *delconn)
+{
+       scan_struct *ss;
+       scan_struct *lastss;
+
+       if (delconn->fd > 0) 
+               close(delconn->fd);
+
+       /* 1 file descriptor freed up for use. */
+       if(delconn->fd)
+               FD_USE--;
+
+       lastss = 0;
+
+       for(ss = CONNECTIONS; ss; ss = ss->next) {
+               if (ss == delconn) {     
+                       /* Link around deleted node */                                   
+                       if (lastss == 0)
+                               CONNECTIONS = ss->next;                     
+                       else
+                               lastss->next = ss->next;
+                     
+                       free(ss->addr);
+                       free(ss->irc_addr);
+                       free(ss->irc_nick);
+                       free(ss->irc_user);
+
+                       if (ss->conn_notice)
+                               free(ss->conn_notice);
+
+                       /* If it's established, free the scan buffer. */
+                       if (delconn->data)
+                               free(delconn->data);
+
+                       free(ss);
+
+                       break;
+               }
+
+               lastss = ss;
+       }
+}
+
+/*
+ * Alarm signaled, loop through connections and remove any we don't need
+ * anymore.
+ */
+void scan_timer()
+{
+       scan_struct *ss;
+       scan_struct *nextss;
+       time_t present;
+       time(&present);
+
+       /*
+        * Check for timed out connections and also check if queued
+        * (UNESTABLISHED) connections can be established now.
+        */
+
+       for (ss = CONNECTIONS; ss;) {
+               if (ss->state == STATE_UNESTABLISHED) { 
+                       if (FD_USE < CONF_FDLIMIT) {
+                               scan_establish(ss);
+                               if (OPT_DEBUG >= 3) {
+                                       log("SCAN -> File descriptor free, "
+                                           "continuing queued scan on %s",
+                                           ss->addr);
+                               }
+                       } else {
+                               ss = ss->next;
+
+                               /*
+                                * Continue to avoid timeout checks on an
+                                * unestablished connection.
+                                */
+                               continue;
+                       }
+               }
+
+               if (((present - ss->create_time) >= CONF_TIMEOUT) ||
+                   (ss->state == STATE_CLOSED)) {
+                       /* State closed or timed out, remove */ 
+                       if (ss->verbose && (ss->state != STATE_CLOSED)) {
+                               if (ss->bytes_read) {
+                                       irc_send("PRIVMSG %s :%s (%d): "
+                                           "Negotiation to %s timed out "
+                                           "(%d bytes read).",
+                                           CONF_CHANNELS,
+                                           ss->protocol->type,
+                                           ss->protocol->port,
+                                           ss->irc_addr, ss->bytes_read);
+                               } else {
+                                       irc_send("PRIVMSG %s :%s (%d): "
+                                           "Negotiation to %s timed out "
+                                           "(No response).",
+                                           CONF_CHANNELS,
+                                           ss->protocol->type,
+                                           ss->protocol->port, 
+                                           ss->irc_addr);
+                               }
+                       }
+                       nextss = ss->next;
+                       scan_del(ss);
+                       ss = nextss;
+                       continue;
+               }
+               ss = ss->next;
+       }
+}
+
+
+
+/*
+ * Function for handling open HTTP data.
+ *
+ * Return 1 on success.
+ */
+static int scan_w_squid(struct scan_struct *conn)
+{
+       snprintf(SENDBUFF, 128, "CONNECT %s:%d HTTP/1.0\r\n\r\n",
+           CONF_SCANIP, CONF_SCANPORT);
+       send(conn->fd, SENDBUFF, strlen(SENDBUFF), 0);
+
+    return(1);
+}
+
+
+/*
+ * CONNECT request byte order for socks4
+ *  
+ *             +----+----+----+----+----+----+----+----+----+----+....+----+
+ *             | VN | CD | DSTPORT |      DSTIP        | USERID       |NULL|
+ *             +----+----+----+----+----+----+----+----+----+----+....+----+
+ *   # of bytes:  1    1      2              4           variable       1
+ *                                              
+ *  VN = Version, CD = Command Code (1 is connect request)
+ */
+static int scan_w_socks4(struct scan_struct *conn)
+{
+       struct in_addr addr;
+       unsigned long laddr;
+       int len;
+       if (inet_aton(CONF_SCANIP, &addr) == 0) {
+               log("SCAN -> scan_w_socks4 : %s is not a valid IP",
+                   CONF_SCANIP);
+       }
+    
+       laddr = htonl(addr.s_addr);
+       len = snprintf(SENDBUFF, 512, "%c%c%c%c%c%c%c%c%c",  4, 1,
+           (((unsigned short) CONF_SCANPORT) >> 8) & 0xFF,
+           (((unsigned short) CONF_SCANPORT) & 0xff),
+           (char) (laddr >> 24) & 0xFF, (char) (laddr >> 16) & 0xFF,
+           (char) (laddr >> 8) & 0xFF, (char) laddr & 0xFF, 0);
+
+       send(conn->fd, SENDBUFF, len, 0);
+       return(1);
+}
+
+/*
+ * Send version authentication selection message to socks5
+ *
+ *      +----+----------+----------+
+ *      |VER | NMETHODS | METHODS  |
+ *      +----+----------+----------+
+ *      | 1  |    1     | 1 to 255 |
+ *      +----+----------+----------+
+ *                                                                                               
+ *  VER always contains 5, for socks version 5
+ *  Method 0 is 'No authentication required'
+ */
+static int scan_w_socks5(struct scan_struct *conn)
+{
+       int len;
+
+       /* Version 5, 1 number of methods, 0 method (no auth). */
+       len = snprintf(SENDBUFF, 512, "%c%c%c", 5, 1, 0);
+       send(conn->fd, SENDBUFF, len, 0);
+
+       return(1);
+}
+
+/*
+ * Cisco scanning
+ *
+ * Some cisco routers have 'cisco' set as password which allow open telnet
+ * relay. Attempt to connect using cisco as a password, then give command for
+ * telnet to the scanip/scanport
+ */
+static int scan_w_cisco(struct scan_struct *conn)
+{
+       int len;
+
+       len = snprintf(SENDBUFF, 512, "cisco\r\n");
+       send(conn->fd, SENDBUFF, len, 0); 
+
+       len = snprintf(SENDBUFF, 512, "telnet %s %d\r\n", CONF_SCANIP,
+           CONF_SCANPORT);
+       send(conn->fd, SENDBUFF, len, 0);
+
+       return(1);
+}
+
+
+/*
+ * Open wingates require no authentication, they will send a prompt when
+ * connect. No need to send any data.
+ */
+static int scan_w_wingate(struct scan_struct *conn)
+{
+     int len;
+       len = snprintf(SENDBUFF, 512, "%s:%d\r\n", CONF_SCANIP,
+           CONF_SCANPORT);
+       send(conn->fd, SENDBUFF, len, 0);
+
+       return(1);
+}
+
+
+/*
+ * Manually check a host for proxies.
+ */
+void do_manual_check(struct command *c)
+{
+       struct hostent *he;
+       char *ip;
+
+       if (!(he = gethostbyname(c->param))) {
+               switch (h_errno) {
+               case HOST_NOT_FOUND:
+                       irc_send("PRIVMSG %s :Host '%s' is unknown, dummy.",
+                           c->target, c->param);
+                       return;
+               case NO_ADDRESS:
+                       irc_send("PRIVMSG %s :The specified name '%s' "
+                           "exists, but has no address.", c->target,
+                           c->param);
+                       return;
+               case NO_RECOVERY:
+                       irc_send("PRIVMSG %s :An unrecoverable error "
+                           "occured whilst resolving '%s'.", c->target,
+                           c->param);
+                       return;
+               case TRY_AGAIN:
+                       irc_send("PRIVMSG %s :A temporary nameserver "
+                           "error occurred.", c->target);
+                       return;
+               default:
+                       irc_send("PRIVMSG %s :Unknown error resolving "
+                           "'%s' (sorry!)", c->target, c->param);
+                       return;
+               }
+       }
+
+       ip = inet_ntoa(*((struct in_addr *) he->h_addr));
+
+       irc_send("PRIVMSG %s :Checking %s [%s] for open proxies at "
+           "request of %s...", CONF_CHANNELS, c->param, ip, c->nick);
+
+       if(CONF_DNSBL_ZONE)
+               dnsbl_check(ip, "*", "*", c->param);
+
+       /* Scan using verbose. */
+       scan_connect(ip, c->param, "*", "*", 1, 0);
+}
+
diff --git a/src/scan.h b/src/scan.h
new file mode 100644 (file)
index 0000000..07131c2
--- /dev/null
@@ -0,0 +1,51 @@
+#ifndef SCAN_H
+#define SCAN_H
+    
+typedef struct protocol_hash protocol_hash;
+typedef struct scan_struct scan_struct;
+typedef int (*scan_function) (scan_struct *);
+
+#define STATE_UNESTABLISHED 1
+#define STATE_ESTABLISHED   2
+#define STATE_SENT          3
+#define STATE_CLOSED        4   
+struct protocol_hash
+{
+       char *type;                 /* Plaintext name of protocol to scan   */
+       int port;                   /* Port to scan protocol on             */
+       scan_function w_handler;    /* Function to handle specific protocol */
+       unsigned int stat_num;
+       unsigned int stat_numopen;
+};
+
+struct scan_struct
+{
+       scan_struct *next;   
+       char *addr;                  /* Address of remote host (IP)                      */
+       char *irc_addr;              /* Hostname of user on IRC (for kline)              */ 
+       char *irc_nick;              /* Nickname of user on IRC (for logging)            */
+       char *irc_user;              /* Username of user on IRC (for logging)            */
+       char *conn_notice;           /* original server notice for this connect, used
+                                     * for evidence                                     */
+       char *data;                  /* Buffered data                                    */
+       int  datasize;               /* Length of buffered data                          */
+
+       int fd;                      /* File descriptor of socket                        */
+       struct sockaddr_in sockaddr; /* holds information about remote host for socket() */
+       time_t create_time;          /* Creation time, for timeout                       */         
+       int state;                   /* Status of scan                                   */
+       unsigned int bytes_read;     /* Number of bytes received                         */
+       protocol_hash *protocol;     /* Pointer to protocol type                         */
+       int verbose;                 /* report progress to channel verbosely?            */
+};
+
+extern void do_scan_init(void);
+extern void scan_connect(char *addr, char *irc_addr, char *irc_nick,
+    char *irc_user, int verbose, char *conn_notice);
+extern void scan_cycle(void);
+extern void scan_timer(void);    
+extern void do_manual_check(struct command *c);
+
+#endif 
diff --git a/src/setup.h.in b/src/setup.h.in
new file mode 100644 (file)
index 0000000..0173659
--- /dev/null
@@ -0,0 +1,90 @@
+/* src/setup.h.in.  Generated automatically from configure.in by autoheader.  */
+
+/* Define if you have the <fcntl.h> header file. */
+#undef HAVE_FCNTL_H
+
+/* Define if you have the `inet_aton' function. */
+#undef HAVE_INET_ATON
+
+/* Define if you have the <inttypes.h> header file. */
+#undef HAVE_INTTYPES_H
+
+/* Define if you have the <memory.h> header file. */
+#undef HAVE_MEMORY_H
+
+/* Define if you have the `select' function. */
+#undef HAVE_SELECT
+
+/* Define if you have the `socket' function. */
+#undef HAVE_SOCKET
+
+/* Define if you have the <stdint.h> header file. */
+#undef HAVE_STDINT_H
+
+/* Define if you have the <stdlib.h> header file. */
+#undef HAVE_STDLIB_H
+
+/* Define if you have the `strdup' function. */
+#undef HAVE_STRDUP
+
+/* Define if you have the `strftime' function. */
+#undef HAVE_STRFTIME
+
+/* Define if you have the <strings.h> header file. */
+#undef HAVE_STRINGS_H
+
+/* Define if you have the <string.h> header file. */
+#undef HAVE_STRING_H
+
+/* Define if you have the `strstr' function. */
+#undef HAVE_STRSTR
+
+/* Define if you have the <sys/poll.h> header file. */
+#undef HAVE_SYS_POLL_H
+
+/* Define if you have the <sys/stat.h> header file. */
+#undef HAVE_SYS_STAT_H
+
+/* Define if you have the <sys/time.h> header file. */
+#undef HAVE_SYS_TIME_H
+
+/* Define if you have the <sys/types.h> header file. */
+#undef HAVE_SYS_TYPES_H
+
+/* Define if you have the <unistd.h> header file. */
+#undef HAVE_UNISTD_H
+
+/* Name of package */
+#undef PACKAGE
+
+/* Define as the return type of signal handlers (`int' or `void'). */
+#undef RETSIGTYPE
+
+/* Define if you have the ANSI C header files. */
+#undef STDC_HEADERS
+
+/* Define if you can safely include both <sys/time.h> and <time.h>. */
+#undef TIME_WITH_SYS_TIME
+
+/* Define if your <sys/time.h> declares `struct tm'. */
+#undef TM_IN_SYS_TIME
+
+/* Version number of package */
+#undef VERSION
+
+/* Define if you wish to force use of select() even when poll() may be present
+   */
+#undef WITH_SELECT
+
+/* Define if you are using Unreal ircd (any version) */
+#undef WITH_UNREAL
+
+/* Define if your processor stores words with the most significant byte first
+   (like Motorola and SPARC, unlike Intel and VAX). */
+#undef WORDS_BIGENDIAN
+
+/* Define to empty if `const' does not conform to ANSI C. */
+#undef const
+
+/* Define to `unsigned' if <sys/types.h> does not define. */
+#undef size_t
diff --git a/src/stats.c b/src/stats.c
new file mode 100644 (file)
index 0000000..2063b48
--- /dev/null
@@ -0,0 +1,86 @@
+/*
+Copyright (C) 2002  Erik Fears
+
+This program 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.
+
+This program 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 received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+
+      Foundation, Inc.
+      59 Temple Place - Suite 330
+      Boston, MA  02111-1307, USA.
+
+*/
+
+#include "setup.h"
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+
+#include <stdio.h>
+#include <time.h>
+
+#include "irc.h"
+#include "misc.h"
+#include "stats.h"
+#include "config.h"
+#include "extern.h"
+#include "opercmd.h"
+#include "scan.h"
+#include "stats.h"
+
+time_t STAT_START_TIME;
+unsigned int STAT_NUM_CONNECTS;
+unsigned int STAT_DNSBL_MATCHES;
+
+extern protocol_hash SCAN_PROTOCOLS[];
+extern size_t SCAN_NUMPROTOCOLS;
+
+extern unsigned int FD_USE;
+
+void do_stats_init(void)
+{
+       STAT_START_TIME = time(NULL);
+       STAT_NUM_CONNECTS = 0;
+}
+
+void do_stats(const char *target)
+{
+       time_t now, uptime;
+       size_t i;
+
+       now = time(NULL);
+       uptime = now - STAT_START_TIME;
+       irc_send("PRIVMSG %s :Uptime: %s", target, dissect_time(uptime));
+        irc_send("PRIVMSG %s :Using %d/%d file descriptors", target, FD_USE, CONF_FDLIMIT);
+
+       if (CONF_DNSBL_ZONE) {
+               irc_send("PRIVMSG %s :DNSBL: %u successful lookup%s from "
+                   "zone %s", target, STAT_DNSBL_MATCHES,
+                   STAT_DNSBL_MATCHES == 1 ? "" : "s", CONF_DNSBL_ZONE);
+       }
+       
+       for(i = 0; i < SCAN_NUMPROTOCOLS; i++) {
+               irc_send("PRIVMSG %s :Found %u %s (%d), %u open.", target,
+                   SCAN_PROTOCOLS[i].stat_num, SCAN_PROTOCOLS[i].type,
+                   SCAN_PROTOCOLS[i].port,SCAN_PROTOCOLS[i].stat_numopen);
+       }
+
+       irc_send("PRIVMSG %s :Number of connects: %u (%.2f/minute)",
+           target, STAT_NUM_CONNECTS, STAT_NUM_CONNECTS ?
+           (float)STAT_NUM_CONNECTS / ((float)uptime / 60.0) : 0.0);
+
+       return;
+}
diff --git a/src/stats.h b/src/stats.h
new file mode 100644 (file)
index 0000000..e10cda0
--- /dev/null
@@ -0,0 +1,7 @@
+#ifndef STATS_H
+#define STATS_H
+
+extern void do_stats_init(void);
+extern void do_stats(const char *target);
+
+#endif