summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorLibravatarUnit 193 <unit193@ubuntu.com>2019-04-07 00:14:13 -0400
committerLibravatarUnit 193 <unit193@ubuntu.com>2019-04-07 00:14:13 -0400
commit5140318f8f758141b4e350871db1fe869eb858dc (patch)
tree3cf26f4845b2c4674af81f108fbdbf47a996dcff /src
Import Upstream version 1.1.5upstream/1.1.5
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.am46
-rw-r--r--src/Makefile.in870
-rw-r--r--src/compat.c122
-rw-r--r--src/compat.h34
-rw-r--r--src/config-lexer.c2846
-rw-r--r--src/config-lexer.l379
-rw-r--r--src/config-parser.c2538
-rw-r--r--src/config-parser.h209
-rw-r--r--src/config-parser.y684
-rw-r--r--src/config.c107
-rw-r--r--src/config.h153
-rw-r--r--src/dnsbl.c300
-rw-r--r--src/dnsbl.h38
-rw-r--r--src/firedns.c881
-rw-r--r--src/firedns.h86
-rw-r--r--src/irc.c912
-rw-r--r--src/irc.h31
-rw-r--r--src/libopm/COPYING339
-rw-r--r--src/libopm/Makefile.am2
-rw-r--r--src/libopm/Makefile.in632
-rw-r--r--src/libopm/src/Makefile.am18
-rw-r--r--src/libopm/src/Makefile.in617
-rw-r--r--src/libopm/src/config.c249
-rw-r--r--src/libopm/src/config.h19
-rw-r--r--src/libopm/src/libopm.c1343
-rw-r--r--src/libopm/src/libopm.h63
-rw-r--r--src/libopm/src/list.c97
-rw-r--r--src/libopm/src/list.h40
-rw-r--r--src/libopm/src/memory.c73
-rw-r--r--src/libopm/src/memory.h28
-rw-r--r--src/libopm/src/opm.h70
-rw-r--r--src/libopm/src/opm_common.h21
-rw-r--r--src/libopm/src/opm_error.h26
-rw-r--r--src/libopm/src/opm_types.h49
-rw-r--r--src/libopm/src/proxy.c316
-rw-r--r--src/libopm/src/proxy.h15
-rw-r--r--src/list.c93
-rw-r--r--src/list.h56
-rw-r--r--src/log.c92
-rw-r--r--src/log.h35
-rw-r--r--src/main.c283
-rw-r--r--src/main.h26
-rw-r--r--src/match.c156
-rw-r--r--src/match.h33
-rw-r--r--src/memory.c73
-rw-r--r--src/memory.h28
-rw-r--r--src/misc.c96
-rw-r--r--src/misc.h27
-rw-r--r--src/negcache.c125
-rw-r--r--src/negcache.h34
-rw-r--r--src/opercmd.c302
-rw-r--r--src/opercmd.h62
-rw-r--r--src/options.h13
-rw-r--r--src/patchlevel.h8
-rw-r--r--src/patricia.c977
-rw-r--r--src/patricia.h148
-rw-r--r--src/scan.c969
-rw-r--r--src/scan.h63
-rw-r--r--src/serno.h1
-rw-r--r--src/setup.h.in83
-rw-r--r--src/stats.c249
-rw-r--r--src/stats.h39
62 files changed, 18324 insertions, 0 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
new file mode 100644
index 0000000..ec9337c
--- /dev/null
+++ b/src/Makefile.am
@@ -0,0 +1,46 @@
+SUBDIRS = libopm
+bin_PROGRAMS = hopm
+
+AM_CPPFLAGS = -DHOPM_PREFIX="\"$(prefix)\"" -DHOPM_ETCDIR="\"$(sysconfdir)\"" -DHOPM_LOGDIR="\"$(localstatedir)/log\"" -DHOPM_BINPATH="\"$(bindir)/hopm\""
+AM_YFLAGS = -d
+
+hopm_SOURCES = compat.c \
+ compat.h \
+ config-parser.y \
+ config-lexer.l \
+ config.c \
+ config.h \
+ dnsbl.c \
+ dnsbl.h \
+ extern.h \
+ firedns.c \
+ firedns.h \
+ irc.c \
+ irc.h \
+ list.c \
+ list.h \
+ log.c \
+ log.h \
+ main.c \
+ main.h \
+ memory.c \
+ memory.h \
+ match.c \
+ match.h \
+ misc.c \
+ misc.h \
+ negcache.c \
+ negcache.h \
+ opercmd.c \
+ opercmd.h \
+ options.h \
+ patchlevel.h \
+ patricia.c \
+ patricia.h \
+ scan.c \
+ scan.h \
+ serno.h \
+ stats.c \
+ stats.h
+
+hopm_LDADD = libopm/src/.libs/libopm.a @LIBOBJS@
diff --git a/src/Makefile.in b/src/Makefile.in
new file mode 100644
index 0000000..ee9e35a
--- /dev/null
+++ b/src/Makefile.in
@@ -0,0 +1,870 @@
+# Makefile.in generated by automake 1.15.1 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2017 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.
+
+@SET_MAKE@
+
+VPATH = @srcdir@
+am__is_gnu_make = { \
+ if test -z '$(MAKELEVEL)'; then \
+ false; \
+ elif test -n '$(MAKE_HOST)'; then \
+ true; \
+ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+ true; \
+ else \
+ false; \
+ fi; \
+}
+am__make_running_with_option = \
+ case $${target_option-} in \
+ ?) ;; \
+ *) echo "am__make_running_with_option: internal error: invalid" \
+ "target option '$${target_option-}' specified" >&2; \
+ exit 1;; \
+ esac; \
+ has_opt=no; \
+ sane_makeflags=$$MAKEFLAGS; \
+ if $(am__is_gnu_make); then \
+ sane_makeflags=$$MFLAGS; \
+ else \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ bs=\\; \
+ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
+ esac; \
+ fi; \
+ skip_next=no; \
+ strip_trailopt () \
+ { \
+ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+ }; \
+ for flg in $$sane_makeflags; do \
+ test $$skip_next = yes && { skip_next=no; continue; }; \
+ case $$flg in \
+ *=*|--*) continue;; \
+ -*I) strip_trailopt 'I'; skip_next=yes;; \
+ -*I?*) strip_trailopt 'I';; \
+ -*O) strip_trailopt 'O'; skip_next=yes;; \
+ -*O?*) strip_trailopt 'O';; \
+ -*l) strip_trailopt 'l'; skip_next=yes;; \
+ -*l?*) strip_trailopt 'l';; \
+ -[dEDm]) skip_next=yes;; \
+ -[JT]) skip_next=yes;; \
+ esac; \
+ case $$flg in \
+ *$$target_option*) has_opt=yes; break;; \
+ esac; \
+ done; \
+ test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+bin_PROGRAMS = hopm$(EXEEXT)
+subdir = src
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/ax_append_compile_flags.m4 \
+ $(top_srcdir)/m4/ax_append_flag.m4 \
+ $(top_srcdir)/m4/ax_arg_enable_assert.m4 \
+ $(top_srcdir)/m4/ax_arg_enable_efence.m4 \
+ $(top_srcdir)/m4/ax_arg_enable_warnings.m4 \
+ $(top_srcdir)/m4/ax_arg_openssl.m4 \
+ $(top_srcdir)/m4/ax_check_compile_flag.m4 \
+ $(top_srcdir)/m4/ax_gcc_stack_protect.m4 \
+ $(top_srcdir)/m4/ax_library_net.m4 \
+ $(top_srcdir)/m4/ax_require_defined.m4 \
+ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
+ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
+ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
+mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs
+CONFIG_HEADER = setup.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+am__installdirs = "$(DESTDIR)$(bindir)"
+PROGRAMS = $(bin_PROGRAMS)
+am_hopm_OBJECTS = compat.$(OBJEXT) config-parser.$(OBJEXT) \
+ config-lexer.$(OBJEXT) config.$(OBJEXT) dnsbl.$(OBJEXT) \
+ firedns.$(OBJEXT) irc.$(OBJEXT) list.$(OBJEXT) log.$(OBJEXT) \
+ main.$(OBJEXT) memory.$(OBJEXT) match.$(OBJEXT) misc.$(OBJEXT) \
+ negcache.$(OBJEXT) opercmd.$(OBJEXT) patricia.$(OBJEXT) \
+ scan.$(OBJEXT) stats.$(OBJEXT)
+hopm_OBJECTS = $(am_hopm_OBJECTS)
+hopm_DEPENDENCIES = libopm/src/.libs/libopm.a @LIBOBJS@
+AM_V_lt = $(am__v_lt_@AM_V@)
+am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
+am__v_lt_0 = --silent
+am__v_lt_1 =
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo " GEN " $@;
+am__v_GEN_1 =
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 =
+DEFAULT_INCLUDES = -I.@am__isrc@
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__depfiles_maybe = depfiles
+am__mv = mv -f
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_@AM_V@)
+am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
+am__v_CC_0 = @echo " CC " $@;
+am__v_CC_1 =
+CCLD = $(CC)
+LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_@AM_V@)
+am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
+am__v_CCLD_0 = @echo " CCLD " $@;
+am__v_CCLD_1 =
+@MAINTAINER_MODE_FALSE@am__skiplex = test -f $@ ||
+LEXCOMPILE = $(LEX) $(AM_LFLAGS) $(LFLAGS)
+LTLEXCOMPILE = $(LIBTOOL) $(AM_V_lt) $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=compile $(LEX) $(AM_LFLAGS) $(LFLAGS)
+AM_V_LEX = $(am__v_LEX_@AM_V@)
+am__v_LEX_ = $(am__v_LEX_@AM_DEFAULT_V@)
+am__v_LEX_0 = @echo " LEX " $@;
+am__v_LEX_1 =
+YLWRAP = $(top_srcdir)/ylwrap
+@MAINTAINER_MODE_FALSE@am__skipyacc = test -f $@ ||
+am__yacc_c2h = sed -e s/cc$$/hh/ -e s/cpp$$/hpp/ -e s/cxx$$/hxx/ \
+ -e s/c++$$/h++/ -e s/c$$/h/
+YACCCOMPILE = $(YACC) $(AM_YFLAGS) $(YFLAGS)
+LTYACCCOMPILE = $(LIBTOOL) $(AM_V_lt) $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=compile $(YACC) $(AM_YFLAGS) $(YFLAGS)
+AM_V_YACC = $(am__v_YACC_@AM_V@)
+am__v_YACC_ = $(am__v_YACC_@AM_DEFAULT_V@)
+am__v_YACC_0 = @echo " YACC " $@;
+am__v_YACC_1 =
+SOURCES = $(hopm_SOURCES)
+DIST_SOURCES = $(hopm_SOURCES)
+RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \
+ ctags-recursive dvi-recursive html-recursive info-recursive \
+ install-data-recursive install-dvi-recursive \
+ install-exec-recursive install-html-recursive \
+ install-info-recursive install-pdf-recursive \
+ install-ps-recursive install-recursive installcheck-recursive \
+ installdirs-recursive pdf-recursive ps-recursive \
+ tags-recursive uninstall-recursive
+am__can_run_installinfo = \
+ case $$AM_UPDATE_INFO_DIR in \
+ n|no|NO) false;; \
+ *) (install-info --version) >/dev/null 2>&1;; \
+ esac
+RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \
+ distclean-recursive maintainer-clean-recursive
+am__recursive_targets = \
+ $(RECURSIVE_TARGETS) \
+ $(RECURSIVE_CLEAN_TARGETS) \
+ $(am__extra_recursive_targets)
+AM_RECURSIVE_TARGETS = $(am__recursive_targets:-recursive=) TAGS CTAGS \
+ distdir
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) \
+ $(LISP)setup.h.in
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates. Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+ BEGIN { nonempty = 0; } \
+ { items[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique. This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+ list='$(am__tagged_files)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | $(am__uniquify_input)`
+ETAGS = etags
+CTAGS = ctags
+DIST_SUBDIRS = $(SUBDIRS)
+am__DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/setup.h.in \
+ $(top_srcdir)/depcomp $(top_srcdir)/mkinstalldirs \
+ $(top_srcdir)/ylwrap config-lexer.c config-parser.c \
+ config-parser.h
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+am__relativize = \
+ dir0=`pwd`; \
+ sed_first='s,^\([^/]*\)/.*$$,\1,'; \
+ sed_rest='s,^[^/]*/*,,'; \
+ sed_last='s,^.*/\([^/]*\)$$,\1,'; \
+ sed_butlast='s,/*[^/]*$$,,'; \
+ while test -n "$$dir1"; do \
+ first=`echo "$$dir1" | sed -e "$$sed_first"`; \
+ if test "$$first" != "."; then \
+ if test "$$first" = ".."; then \
+ dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \
+ dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \
+ else \
+ first2=`echo "$$dir2" | sed -e "$$sed_first"`; \
+ if test "$$first2" = "$$first"; then \
+ dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \
+ else \
+ dir2="../$$dir2"; \
+ fi; \
+ dir0="$$dir0"/"$$first"; \
+ fi; \
+ fi; \
+ dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \
+ done; \
+ reldir="$$dir2"
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DLLTOOL = @DLLTOOL@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+GREP = @GREP@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LEX = @LEX@
+LEXLIB = @LEXLIB@
+LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+RANLIB = @RANLIB@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+VERSION = @VERSION@
+YACC = @YACC@
+YFLAGS = @YFLAGS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+SUBDIRS = libopm
+AM_CPPFLAGS = -DHOPM_PREFIX="\"$(prefix)\"" -DHOPM_ETCDIR="\"$(sysconfdir)\"" -DHOPM_LOGDIR="\"$(localstatedir)/log\"" -DHOPM_BINPATH="\"$(bindir)/hopm\""
+AM_YFLAGS = -d
+hopm_SOURCES = compat.c \
+ compat.h \
+ config-parser.y \
+ config-lexer.l \
+ config.c \
+ config.h \
+ dnsbl.c \
+ dnsbl.h \
+ extern.h \
+ firedns.c \
+ firedns.h \
+ irc.c \
+ irc.h \
+ list.c \
+ list.h \
+ log.c \
+ log.h \
+ main.c \
+ main.h \
+ memory.c \
+ memory.h \
+ match.c \
+ match.h \
+ misc.c \
+ misc.h \
+ negcache.c \
+ negcache.h \
+ opercmd.c \
+ opercmd.h \
+ options.h \
+ patchlevel.h \
+ patricia.c \
+ patricia.h \
+ scan.c \
+ scan.h \
+ serno.h \
+ stats.c \
+ stats.h
+
+hopm_LDADD = libopm/src/.libs/libopm.a @LIBOBJS@
+all: setup.h
+ $(MAKE) $(AM_MAKEFLAGS) all-recursive
+
+.SUFFIXES:
+.SUFFIXES: .c .l .lo .o .obj .y
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --gnu src/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+setup.h: stamp-h1
+ @test -f $@ || rm -f stamp-h1
+ @test -f $@ || $(MAKE) $(AM_MAKEFLAGS) stamp-h1
+
+stamp-h1: $(srcdir)/setup.h.in $(top_builddir)/config.status
+ @rm -f stamp-h1
+ cd $(top_builddir) && $(SHELL) ./config.status src/setup.h
+$(srcdir)/setup.h.in: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+ ($(am__cd) $(top_srcdir) && $(AUTOHEADER))
+ rm -f stamp-h1
+ touch $@
+
+distclean-hdr:
+ -rm -f setup.h stamp-h1
+install-binPROGRAMS: $(bin_PROGRAMS)
+ @$(NORMAL_INSTALL)
+ @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \
+ if test -n "$$list"; then \
+ echo " $(MKDIR_P) '$(DESTDIR)$(bindir)'"; \
+ $(MKDIR_P) "$(DESTDIR)$(bindir)" || exit 1; \
+ fi; \
+ for p in $$list; do echo "$$p $$p"; done | \
+ sed 's/$(EXEEXT)$$//' | \
+ while read p p1; do if test -f $$p \
+ || test -f $$p1 \
+ ; then echo "$$p"; echo "$$p"; else :; fi; \
+ done | \
+ sed -e 'p;s,.*/,,;n;h' \
+ -e 's|.*|.|' \
+ -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \
+ sed 'N;N;N;s,\n, ,g' | \
+ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \
+ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \
+ if ($$2 == $$4) files[d] = files[d] " " $$1; \
+ else { print "f", $$3 "/" $$4, $$1; } } \
+ END { for (d in files) print "f", d, files[d] }' | \
+ while read type dir files; do \
+ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \
+ test -z "$$files" || { \
+ echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(bindir)$$dir'"; \
+ $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(bindir)$$dir" || exit $$?; \
+ } \
+ ; done
+
+uninstall-binPROGRAMS:
+ @$(NORMAL_UNINSTALL)
+ @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \
+ files=`for p in $$list; do echo "$$p"; done | \
+ sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \
+ -e 's/$$/$(EXEEXT)/' \
+ `; \
+ test -n "$$list" || exit 0; \
+ echo " ( cd '$(DESTDIR)$(bindir)' && rm -f" $$files ")"; \
+ cd "$(DESTDIR)$(bindir)" && rm -f $$files
+
+clean-binPROGRAMS:
+ @list='$(bin_PROGRAMS)'; test -n "$$list" || exit 0; \
+ echo " rm -f" $$list; \
+ rm -f $$list || exit $$?; \
+ test -n "$(EXEEXT)" || exit 0; \
+ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \
+ echo " rm -f" $$list; \
+ rm -f $$list
+config-parser.h: config-parser.c
+ @if test ! -f $@; then rm -f config-parser.c; else :; fi
+ @if test ! -f $@; then $(MAKE) $(AM_MAKEFLAGS) config-parser.c; else :; fi
+
+hopm$(EXEEXT): $(hopm_OBJECTS) $(hopm_DEPENDENCIES) $(EXTRA_hopm_DEPENDENCIES)
+ @rm -f hopm$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(hopm_OBJECTS) $(hopm_LDADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/compat.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/config-lexer.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/config-parser.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/config.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dnsbl.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/firedns.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/irc.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/list.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/log.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/main.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/match.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/memory.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/misc.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/negcache.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/opercmd.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/patricia.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/scan.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stats.Po@am__quote@
+
+.c.o:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $<
+
+.c.obj:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $<
+
+.l.c:
+ $(AM_V_LEX)$(am__skiplex) $(SHELL) $(YLWRAP) $< $(LEX_OUTPUT_ROOT).c $@ -- $(LEXCOMPILE)
+
+.y.c:
+ $(AM_V_YACC)$(am__skipyacc) $(SHELL) $(YLWRAP) $< y.tab.c $@ y.tab.h `echo $@ | $(am__yacc_c2h)` y.output $*.output -- $(YACCCOMPILE)
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+# This directory's subdirectories are mostly independent; you can cd
+# into them and run 'make' without going through this Makefile.
+# To change the values of 'make' variables: instead of editing Makefiles,
+# (1) if the variable is set in 'config.status', edit 'config.status'
+# (which will cause the Makefiles to be regenerated when you run 'make');
+# (2) otherwise, pass the desired values on the 'make' command line.
+$(am__recursive_targets):
+ @fail=; \
+ if $(am__make_keepgoing); then \
+ failcom='fail=yes'; \
+ else \
+ failcom='exit 1'; \
+ fi; \
+ dot_seen=no; \
+ target=`echo $@ | sed s/-recursive//`; \
+ case "$@" in \
+ distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \
+ *) list='$(SUBDIRS)' ;; \
+ esac; \
+ for subdir in $$list; do \
+ echo "Making $$target in $$subdir"; \
+ if test "$$subdir" = "."; then \
+ dot_seen=yes; \
+ local_target="$$target-am"; \
+ else \
+ local_target="$$target"; \
+ fi; \
+ ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \
+ || eval $$failcom; \
+ done; \
+ if test "$$dot_seen" = "no"; then \
+ $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \
+ fi; test -z "$$fail"
+
+ID: $(am__tagged_files)
+ $(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-recursive
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ set x; \
+ here=`pwd`; \
+ if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \
+ include_option=--etags-include; \
+ empty_fix=.; \
+ else \
+ include_option=--include; \
+ empty_fix=; \
+ fi; \
+ list='$(SUBDIRS)'; for subdir in $$list; do \
+ if test "$$subdir" = .; then :; else \
+ test ! -f $$subdir/TAGS || \
+ set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \
+ fi; \
+ done; \
+ $(am__define_uniq_tagged_files); \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: ctags-recursive
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ $(am__define_uniq_tagged_files); \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+cscopelist: cscopelist-recursive
+
+cscopelist-am: $(am__tagged_files)
+ list='$(am__tagged_files)'; \
+ case "$(srcdir)" in \
+ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+ *) sdir=$(subdir)/$(srcdir) ;; \
+ esac; \
+ for i in $$list; do \
+ if test -f "$$i"; then \
+ echo "$(subdir)/$$i"; \
+ else \
+ echo "$$sdir/$$i"; \
+ fi; \
+ done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+ @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \
+ if test "$$subdir" = .; then :; else \
+ $(am__make_dryrun) \
+ || test -d "$(distdir)/$$subdir" \
+ || $(MKDIR_P) "$(distdir)/$$subdir" \
+ || exit 1; \
+ dir1=$$subdir; dir2="$(distdir)/$$subdir"; \
+ $(am__relativize); \
+ new_distdir=$$reldir; \
+ dir1=$$subdir; dir2="$(top_distdir)"; \
+ $(am__relativize); \
+ new_top_distdir=$$reldir; \
+ echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \
+ echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \
+ ($(am__cd) $$subdir && \
+ $(MAKE) $(AM_MAKEFLAGS) \
+ top_distdir="$$new_top_distdir" \
+ distdir="$$new_distdir" \
+ am__remove_distdir=: \
+ am__skip_length_check=: \
+ am__skip_mode_fix=: \
+ distdir) \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-recursive
+all-am: Makefile $(PROGRAMS) setup.h
+installdirs: installdirs-recursive
+installdirs-am:
+ for dir in "$(DESTDIR)$(bindir)"; do \
+ test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+ done
+install: install-recursive
+install-exec: install-exec-recursive
+install-data: install-data-recursive
+uninstall: uninstall-recursive
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-recursive
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+ -rm -f config-lexer.c
+ -rm -f config-parser.c
+ -rm -f config-parser.h
+clean: clean-recursive
+
+clean-am: clean-binPROGRAMS clean-generic clean-libtool mostlyclean-am
+
+distclean: distclean-recursive
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-hdr distclean-tags
+
+dvi: dvi-recursive
+
+dvi-am:
+
+html: html-recursive
+
+html-am:
+
+info: info-recursive
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-recursive
+
+install-dvi-am:
+
+install-exec-am: install-binPROGRAMS
+
+install-html: install-html-recursive
+
+install-html-am:
+
+install-info: install-info-recursive
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-recursive
+
+install-pdf-am:
+
+install-ps: install-ps-recursive
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-recursive
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-recursive
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-recursive
+
+pdf-am:
+
+ps: ps-recursive
+
+ps-am:
+
+uninstall-am: uninstall-binPROGRAMS
+
+.MAKE: $(am__recursive_targets) all install-am install-strip
+
+.PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am check \
+ check-am clean clean-binPROGRAMS clean-generic clean-libtool \
+ cscopelist-am ctags ctags-am distclean distclean-compile \
+ distclean-generic distclean-hdr distclean-libtool \
+ distclean-tags distdir dvi dvi-am html html-am info info-am \
+ install install-am install-binPROGRAMS install-data \
+ install-data-am install-dvi install-dvi-am install-exec \
+ install-exec-am install-html install-html-am install-info \
+ install-info-am install-man install-pdf install-pdf-am \
+ install-ps install-ps-am install-strip installcheck \
+ installcheck-am installdirs installdirs-am maintainer-clean \
+ maintainer-clean-generic mostlyclean mostlyclean-compile \
+ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+ tags tags-am uninstall uninstall-am uninstall-binPROGRAMS
+
+.PRECIOUS: Makefile
+
+
+# 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:
diff --git a/src/compat.c b/src/compat.c
new file mode 100644
index 0000000..82f9583
--- /dev/null
+++ b/src/compat.c
@@ -0,0 +1,122 @@
+/*
+ * Copyright (c) 2002 Andy Smith
+ * Copyright (c) 2014-2018 ircd-hybrid 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 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
+ * USA
+ */
+
+#include "setup.h"
+
+#include <string.h>
+
+#include "compat.h"
+
+/* $OpenBSD: strlcat.c,v 1.18 2016/10/16 17:37:39 dtucker Exp $ */
+/* $OpenBSD: strlcpy.c,v 1.15 2016/10/16 17:37:39 dtucker Exp $ */
+/*
+ * Copyright (c) 1998, 2015 Todd C. Miller <Todd.Miller@courtesan.com>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef HAVE_STRLCAT
+/*
+ * Appends src to string dst of size dsize (unlike strncat, dsize is the
+ * full size of dst, not space left). At most dsize-1 characters
+ * will be copied. Always NUL terminates (unless dsize <= strlen(dst)).
+ * Returns strlen(src) + MIN(dsize, strlen(initial dst)).
+ * If retval >= dsize, truncation occurred.
+ */
+size_t
+strlcat(char *dst, const char *src, size_t dsize)
+{
+ const char *odst = dst;
+ const char *osrc = src;
+ size_t n = dsize;
+ size_t dlen;
+
+ /* Find the end of dst and adjust bytes left but don't go past end. */
+ while (n-- != 0 && *dst != '\0')
+ dst++;
+
+ dlen = dst - odst;
+ n = dsize - dlen;
+
+ if (n-- == 0)
+ return dlen + strlen(src);
+
+ while (*src != '\0')
+ {
+ if (n != 0)
+ {
+ *dst++ = *src;
+ n--;
+ }
+
+ src++;
+ }
+
+ *dst = '\0';
+
+ return dlen + (src - osrc); /* count does not include NUL */
+}
+#endif
+
+#ifndef HAVE_STRLCPY
+/*
+ * Copy string src to buffer dst of size dsize. At most dsize-1
+ * chars will be copied. Always NUL terminates (unless dsize == 0).
+ * Returns strlen(src); if retval >= dsize, truncation occurred.
+ */
+size_t
+strlcpy(char *dst, const char *src, size_t dsize)
+{
+ const char *osrc = src;
+ size_t nleft = dsize;
+
+ /* Copy as many bytes as will fit. */
+ if (nleft != 0)
+ {
+ while (--nleft != 0)
+ {
+ if ((*dst++ = *src++) == '\0')
+ break;
+ }
+ }
+
+ /* Not enough room in dst, add NUL and traverse rest of src. */
+ if (nleft == 0)
+ {
+ if (dsize != 0)
+ *dst = '\0'; /* NUL-terminate dst */
+
+ while (*src++)
+ ;
+ }
+
+ return src - osrc - 1; /* count does not include NUL */
+}
+#endif
diff --git a/src/compat.h b/src/compat.h
new file mode 100644
index 0000000..44284c5
--- /dev/null
+++ b/src/compat.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2002 Andy Smith
+ * Copyright (c) 2014-2018 ircd-hybrid 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 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
+ * USA
+ */
+
+#ifndef COMPAT_H
+#define COMPAT_H
+
+#include "setup.h"
+
+#ifndef HAVE_STRLCPY
+extern size_t strlcpy(char *, const char *, size_t);
+#endif
+
+#ifndef HAVE_STRLCAT
+extern size_t strlcat(char *, const char *, size_t);
+#endif
+
+#endif
diff --git a/src/config-lexer.c b/src/config-lexer.c
new file mode 100644
index 0000000..503fcb5
--- /dev/null
+++ b/src/config-lexer.c
@@ -0,0 +1,2846 @@
+
+#line 2 "config-lexer.c"
+
+#define YY_INT_ALIGNED short int
+
+/* A lexical scanner generated by flex */
+
+#define FLEX_SCANNER
+#define YY_FLEX_MAJOR_VERSION 2
+#define YY_FLEX_MINOR_VERSION 6
+#define YY_FLEX_SUBMINOR_VERSION 4
+#if YY_FLEX_SUBMINOR_VERSION > 0
+#define FLEX_BETA
+#endif
+
+/* First, we deal with platform-specific or compiler-specific issues. */
+
+/* begin standard C headers. */
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <stdlib.h>
+
+/* end standard C headers. */
+
+/* flex integer type definitions */
+
+#ifndef FLEXINT_H
+#define FLEXINT_H
+
+/* C99 systems have <inttypes.h>. Non-C99 systems may or may not. */
+
+#if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
+
+/* C99 says to define __STDC_LIMIT_MACROS before including stdint.h,
+ * if you want the limit (max/min) macros for int types.
+ */
+#ifndef __STDC_LIMIT_MACROS
+#define __STDC_LIMIT_MACROS 1
+#endif
+
+#include <inttypes.h>
+typedef int8_t flex_int8_t;
+typedef uint8_t flex_uint8_t;
+typedef int16_t flex_int16_t;
+typedef uint16_t flex_uint16_t;
+typedef int32_t flex_int32_t;
+typedef uint32_t flex_uint32_t;
+#else
+typedef signed char flex_int8_t;
+typedef short int flex_int16_t;
+typedef int flex_int32_t;
+typedef unsigned char flex_uint8_t;
+typedef unsigned short int flex_uint16_t;
+typedef unsigned int flex_uint32_t;
+
+/* Limits of integral types. */
+#ifndef INT8_MIN
+#define INT8_MIN (-128)
+#endif
+#ifndef INT16_MIN
+#define INT16_MIN (-32767-1)
+#endif
+#ifndef INT32_MIN
+#define INT32_MIN (-2147483647-1)
+#endif
+#ifndef INT8_MAX
+#define INT8_MAX (127)
+#endif
+#ifndef INT16_MAX
+#define INT16_MAX (32767)
+#endif
+#ifndef INT32_MAX
+#define INT32_MAX (2147483647)
+#endif
+#ifndef UINT8_MAX
+#define UINT8_MAX (255U)
+#endif
+#ifndef UINT16_MAX
+#define UINT16_MAX (65535U)
+#endif
+#ifndef UINT32_MAX
+#define UINT32_MAX (4294967295U)
+#endif
+
+#ifndef SIZE_MAX
+#define SIZE_MAX (~(size_t)0)
+#endif
+
+#endif /* ! C99 */
+
+#endif /* ! FLEXINT_H */
+
+/* begin standard C++ headers. */
+
+/* TODO: this is always defined, so inline it */
+#define yyconst const
+
+#if defined(__GNUC__) && __GNUC__ >= 3
+#define yynoreturn __attribute__((__noreturn__))
+#else
+#define yynoreturn
+#endif
+
+/* Returned upon end-of-file. */
+#define YY_NULL 0
+
+/* Promotes a possibly negative, possibly signed char to an
+ * integer in range [0..255] for use as an array index.
+ */
+#define YY_SC_TO_UI(c) ((YY_CHAR) (c))
+
+/* Enter a start condition. This macro really ought to take a parameter,
+ * but we do it the disgusting crufty way forced on us by the ()-less
+ * definition of BEGIN.
+ */
+#define BEGIN (yy_start) = 1 + 2 *
+/* Translate the current start state into a value that can be later handed
+ * to BEGIN to return to the state. The YYSTATE alias is for lex
+ * compatibility.
+ */
+#define YY_START (((yy_start) - 1) / 2)
+#define YYSTATE YY_START
+/* Action number for EOF rule of a given start state. */
+#define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1)
+/* Special action meaning "start processing a new file". */
+#define YY_NEW_FILE yyrestart( yyin )
+#define YY_END_OF_BUFFER_CHAR 0
+
+/* Size of default input buffer. */
+#ifndef YY_BUF_SIZE
+#ifdef __ia64__
+/* On IA-64, the buffer size is 16k, not 8k.
+ * Moreover, YY_BUF_SIZE is 2*YY_READ_BUF_SIZE in the general case.
+ * Ditto for the __ia64__ case accordingly.
+ */
+#define YY_BUF_SIZE 32768
+#else
+#define YY_BUF_SIZE 16384
+#endif /* __ia64__ */
+#endif
+
+/* The state buf must be large enough to hold one state per character in the main buffer.
+ */
+#define YY_STATE_BUF_SIZE ((YY_BUF_SIZE + 2) * sizeof(yy_state_type))
+
+#ifndef YY_TYPEDEF_YY_BUFFER_STATE
+#define YY_TYPEDEF_YY_BUFFER_STATE
+typedef struct yy_buffer_state *YY_BUFFER_STATE;
+#endif
+
+#ifndef YY_TYPEDEF_YY_SIZE_T
+#define YY_TYPEDEF_YY_SIZE_T
+typedef size_t yy_size_t;
+#endif
+
+extern int yyleng;
+
+extern FILE *yyin, *yyout;
+
+#define EOB_ACT_CONTINUE_SCAN 0
+#define EOB_ACT_END_OF_FILE 1
+#define EOB_ACT_LAST_MATCH 2
+
+ #define YY_LESS_LINENO(n)
+ #define YY_LINENO_REWIND_TO(ptr)
+
+/* Return all but the first "n" matched characters back to the input stream. */
+#define yyless(n) \
+ do \
+ { \
+ /* Undo effects of setting up yytext. */ \
+ int yyless_macro_arg = (n); \
+ YY_LESS_LINENO(yyless_macro_arg);\
+ *yy_cp = (yy_hold_char); \
+ YY_RESTORE_YY_MORE_OFFSET \
+ (yy_c_buf_p) = yy_cp = yy_bp + yyless_macro_arg - YY_MORE_ADJ; \
+ YY_DO_BEFORE_ACTION; /* set up yytext again */ \
+ } \
+ while ( 0 )
+#define unput(c) yyunput( c, (yytext_ptr) )
+
+#ifndef YY_STRUCT_YY_BUFFER_STATE
+#define YY_STRUCT_YY_BUFFER_STATE
+struct yy_buffer_state
+ {
+ FILE *yy_input_file;
+
+ char *yy_ch_buf; /* input buffer */
+ char *yy_buf_pos; /* current position in input buffer */
+
+ /* Size of input buffer in bytes, not including room for EOB
+ * characters.
+ */
+ int yy_buf_size;
+
+ /* Number of characters read into yy_ch_buf, not including EOB
+ * characters.
+ */
+ int yy_n_chars;
+
+ /* Whether we "own" the buffer - i.e., we know we created it,
+ * and can realloc() it to grow it, and should free() it to
+ * delete it.
+ */
+ int yy_is_our_buffer;
+
+ /* Whether this is an "interactive" input source; if so, and
+ * if we're using stdio for input, then we want to use getc()
+ * instead of fread(), to make sure we stop fetching input after
+ * each newline.
+ */
+ int yy_is_interactive;
+
+ /* Whether we're considered to be at the beginning of a line.
+ * If so, '^' rules will be active on the next match, otherwise
+ * not.
+ */
+ int yy_at_bol;
+
+ int yy_bs_lineno; /**< The line count. */
+ int yy_bs_column; /**< The column count. */
+
+ /* Whether to try to fill the input buffer when we reach the
+ * end of it.
+ */
+ int yy_fill_buffer;
+
+ int yy_buffer_status;
+
+#define YY_BUFFER_NEW 0
+#define YY_BUFFER_NORMAL 1
+ /* When an EOF's been seen but there's still some text to process
+ * then we mark the buffer as YY_EOF_PENDING, to indicate that we
+ * shouldn't try reading from the input source any more. We might
+ * still have a bunch of tokens to match, though, because of
+ * possible backing-up.
+ *
+ * When we actually see the EOF, we change the status to "new"
+ * (via yyrestart()), so that the user can continue scanning by
+ * just pointing yyin at a new input file.
+ */
+#define YY_BUFFER_EOF_PENDING 2
+
+ };
+#endif /* !YY_STRUCT_YY_BUFFER_STATE */
+
+/* Stack of input buffers. */
+static size_t yy_buffer_stack_top = 0; /**< index of top of stack. */
+static size_t yy_buffer_stack_max = 0; /**< capacity of stack. */
+static YY_BUFFER_STATE * yy_buffer_stack = NULL; /**< Stack as an array. */
+
+/* We provide macros for accessing buffer states in case in the
+ * future we want to put the buffer states in a more general
+ * "scanner state".
+ *
+ * Returns the top of the stack, or NULL.
+ */
+#define YY_CURRENT_BUFFER ( (yy_buffer_stack) \
+ ? (yy_buffer_stack)[(yy_buffer_stack_top)] \
+ : NULL)
+/* Same as previous macro, but useful when we know that the buffer stack is not
+ * NULL or when we need an lvalue. For internal use only.
+ */
+#define YY_CURRENT_BUFFER_LVALUE (yy_buffer_stack)[(yy_buffer_stack_top)]
+
+/* yy_hold_char holds the character lost when yytext is formed. */
+static char yy_hold_char;
+static int yy_n_chars; /* number of characters read into yy_ch_buf */
+int yyleng;
+
+/* Points to current character in buffer. */
+static char *yy_c_buf_p = NULL;
+static int yy_init = 0; /* whether we need to initialize */
+static int yy_start = 0; /* start state number */
+
+/* Flag which is used to allow yywrap()'s to do buffer switches
+ * instead of setting up a fresh yyin. A bit of a hack ...
+ */
+static int yy_did_buffer_switch_on_eof;
+
+void yyrestart ( FILE *input_file );
+void yy_switch_to_buffer ( YY_BUFFER_STATE new_buffer );
+YY_BUFFER_STATE yy_create_buffer ( FILE *file, int size );
+void yy_delete_buffer ( YY_BUFFER_STATE b );
+void yy_flush_buffer ( YY_BUFFER_STATE b );
+void yypush_buffer_state ( YY_BUFFER_STATE new_buffer );
+void yypop_buffer_state ( void );
+
+static void yyensure_buffer_stack ( void );
+static void yy_load_buffer_state ( void );
+static void yy_init_buffer ( YY_BUFFER_STATE b, FILE *file );
+#define YY_FLUSH_BUFFER yy_flush_buffer( YY_CURRENT_BUFFER )
+
+YY_BUFFER_STATE yy_scan_buffer ( char *base, yy_size_t size );
+YY_BUFFER_STATE yy_scan_string ( const char *yy_str );
+YY_BUFFER_STATE yy_scan_bytes ( const char *bytes, int len );
+
+void *yyalloc ( yy_size_t );
+void *yyrealloc ( void *, yy_size_t );
+void yyfree ( void * );
+
+#define yy_new_buffer yy_create_buffer
+#define yy_set_interactive(is_interactive) \
+ { \
+ if ( ! YY_CURRENT_BUFFER ){ \
+ yyensure_buffer_stack (); \
+ YY_CURRENT_BUFFER_LVALUE = \
+ yy_create_buffer( yyin, YY_BUF_SIZE ); \
+ } \
+ YY_CURRENT_BUFFER_LVALUE->yy_is_interactive = is_interactive; \
+ }
+#define yy_set_bol(at_bol) \
+ { \
+ if ( ! YY_CURRENT_BUFFER ){\
+ yyensure_buffer_stack (); \
+ YY_CURRENT_BUFFER_LVALUE = \
+ yy_create_buffer( yyin, YY_BUF_SIZE ); \
+ } \
+ YY_CURRENT_BUFFER_LVALUE->yy_at_bol = at_bol; \
+ }
+#define YY_AT_BOL() (YY_CURRENT_BUFFER_LVALUE->yy_at_bol)
+
+/* Begin user sect3 */
+
+#define yywrap() (/*CONSTCOND*/1)
+#define YY_SKIP_YYWRAP
+typedef flex_uint8_t YY_CHAR;
+
+FILE *yyin = NULL, *yyout = NULL;
+
+typedef int yy_state_type;
+
+extern int yylineno;
+int yylineno = 1;
+
+extern char *yytext;
+#ifdef yytext_ptr
+#undef yytext_ptr
+#endif
+#define yytext_ptr yytext
+
+static yy_state_type yy_get_previous_state ( void );
+static yy_state_type yy_try_NUL_trans ( yy_state_type current_state );
+static int yy_get_next_buffer ( void );
+static void yynoreturn yy_fatal_error ( const char* msg );
+
+/* Done after the current pattern has been matched and before the
+ * corresponding action - sets up yytext.
+ */
+#define YY_DO_BEFORE_ACTION \
+ (yytext_ptr) = yy_bp; \
+ (yytext_ptr) -= (yy_more_len); \
+ yyleng = (int) (yy_cp - (yytext_ptr)); \
+ (yy_hold_char) = *yy_cp; \
+ *yy_cp = '\0'; \
+ (yy_c_buf_p) = yy_cp;
+#define YY_NUM_RULES 108
+#define YY_END_OF_BUFFER 109
+/* This struct is not used in this scanner,
+ but its presence is necessary. */
+struct yy_trans_info
+ {
+ flex_int32_t yy_verify;
+ flex_int32_t yy_nxt;
+ };
+static const flex_int16_t yy_accept[469] =
+ { 0,
+ 7, 7, 0, 0, 109, 107, 7, 6, 107, 8,
+ 107, 107, 9, 107, 107, 107, 107, 107, 107, 107,
+ 107, 107, 107, 107, 107, 107, 107, 107, 107, 107,
+ 107, 107, 107, 3, 4, 3, 7, 6, 0, 10,
+ 8, 0, 1, 8, 9, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 25, 0, 0,
+ 0, 0, 0, 85, 0, 0, 0, 0, 90, 0,
+ 0, 0, 0, 0, 0, 105, 0, 103, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 2,
+
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 72,
+ 0, 0, 0, 0, 0, 0, 0, 0, 29, 0,
+ 31, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 106, 0, 42, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 100, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 102, 0, 0, 12, 0, 0, 80, 0,
+ 0, 0, 71, 0, 0, 0, 0, 0, 74, 91,
+ 0, 27, 28, 0, 0, 0, 32, 0, 0, 0,
+ 0, 34, 0, 35, 0, 38, 0, 41, 0, 0,
+
+ 0, 0, 47, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 101, 61, 62, 0,
+ 70, 0, 66, 0, 0, 0, 0, 79, 0, 0,
+ 0, 0, 0, 0, 0, 0, 104, 73, 0, 93,
+ 0, 84, 0, 30, 0, 89, 0, 0, 68, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 52, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 64, 69, 0, 65, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 24, 0, 0, 26,
+ 83, 0, 0, 88, 0, 76, 67, 0, 0, 40,
+
+ 0, 0, 0, 0, 0, 0, 0, 0, 98, 0,
+ 0, 78, 0, 56, 95, 96, 0, 0, 0, 0,
+ 0, 0, 0, 0, 15, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 75, 0, 0,
+ 43, 0, 45, 46, 0, 0, 0, 0, 53, 54,
+ 77, 0, 0, 60, 0, 97, 0, 0, 0, 0,
+ 0, 0, 0, 23, 0, 0, 99, 92, 0, 82,
+ 33, 87, 36, 39, 44, 48, 0, 50, 0, 55,
+ 0, 0, 0, 63, 0, 0, 0, 0, 0, 14,
+ 0, 0, 0, 19, 0, 0, 0, 94, 81, 86,
+
+ 0, 0, 0, 57, 0, 0, 0, 5, 0, 5,
+ 0, 0, 0, 0, 0, 22, 0, 0, 0, 0,
+ 0, 0, 0, 0, 13, 0, 0, 0, 20, 21,
+ 0, 49, 0, 58, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 59, 11,
+ 0, 0, 0, 0, 0, 0, 0, 18, 0, 0,
+ 16, 0, 37, 0, 0, 51, 17, 0
+ } ;
+
+static const YY_CHAR yy_ec[256] =
+ { 0,
+ 1, 1, 1, 1, 1, 1, 1, 1, 2, 3,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 2, 1, 4, 5, 1, 1, 1, 1, 1,
+ 1, 6, 1, 1, 1, 7, 8, 9, 9, 9,
+ 9, 10, 11, 12, 9, 9, 9, 1, 1, 13,
+ 1, 14, 1, 1, 15, 16, 17, 18, 19, 20,
+ 21, 22, 23, 1, 24, 25, 26, 27, 28, 29,
+ 30, 31, 32, 33, 34, 35, 36, 37, 38, 39,
+ 1, 1, 1, 1, 40, 1, 41, 42, 43, 44,
+
+ 45, 46, 47, 48, 49, 1, 50, 51, 52, 53,
+ 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
+ 64, 65, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1
+ } ;
+
+static const YY_CHAR yy_meta[66] =
+ { 0,
+ 1, 1, 2, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1
+ } ;
+
+static const flex_int16_t yy_base[475] =
+ { 0,
+ 0, 0, 63, 64, 924, 925, 921, 0, 68, 0,
+ 45, 67, 67, 56, 65, 59, 68, 45, 70, 56,
+ 93, 107, 144, 112, 116, 184, 74, 151, 159, 54,
+ 69, 128, 119, 925, 925, 914, 914, 0, 93, 925,
+ 0, 112, 925, 0, 208, 136, 140, 148, 161, 145,
+ 169, 161, 157, 174, 192, 203, 199, 925, 192, 194,
+ 193, 195, 214, 196, 197, 211, 216, 208, 204, 222,
+ 217, 228, 221, 228, 234, 225, 239, 925, 257, 231,
+ 236, 256, 247, 251, 265, 252, 272, 280, 271, 269,
+ 261, 269, 262, 269, 280, 273, 284, 283, 300, 925,
+
+ 302, 295, 290, 874, 313, 312, 307, 309, 311, 307,
+ 326, 328, 318, 314, 316, 319, 326, 132, 925, 317,
+ 925, 323, 326, 331, 872, 326, 347, 329, 348, 338,
+ 359, 363, 358, 360, 925, 353, 925, 363, 355, 370,
+ 371, 359, 361, 377, 368, 373, 366, 373, 373, 385,
+ 370, 383, 925, 390, 395, 396, 400, 392, 398, 408,
+ 413, 404, 925, 411, 419, 925, 405, 418, 411, 417,
+ 431, 416, 925, 423, 430, 425, 423, 434, 422, 452,
+ 424, 925, 925, 440, 450, 448, 925, 440, 456, 466,
+ 453, 925, 465, 925, 473, 458, 474, 925, 466, 459,
+
+ 468, 475, 925, 471, 467, 475, 476, 466, 486, 484,
+ 479, 489, 499, 487, 504, 499, 925, 925, 506, 501,
+ 504, 523, 507, 506, 510, 516, 521, 925, 528, 521,
+ 531, 870, 533, 529, 538, 522, 925, 925, 528, 528,
+ 539, 529, 525, 925, 548, 538, 533, 556, 547, 568,
+ 567, 569, 563, 563, 561, 569, 578, 575, 584, 573,
+ 925, 571, 575, 585, 588, 592, 577, 94, 576, 576,
+ 598, 925, 925, 582, 925, 601, 590, 599, 604, 606,
+ 619, 617, 622, 615, 617, 616, 925, 614, 619, 925,
+ 925, 617, 636, 925, 619, 622, 925, 634, 627, 925,
+
+ 627, 629, 635, 643, 637, 641, 645, 655, 925, 654,
+ 648, 651, 666, 925, 925, 925, 867, 657, 666, 675,
+ 676, 863, 669, 666, 925, 858, 680, 671, 675, 681,
+ 687, 670, 675, 678, 692, 694, 694, 925, 695, 682,
+ 925, 701, 925, 925, 698, 707, 708, 714, 925, 925,
+ 925, 710, 718, 925, 723, 925, 742, 728, 723, 721,
+ 733, 721, 731, 925, 734, 734, 925, 925, 731, 733,
+ 925, 737, 857, 925, 925, 925, 742, 925, 738, 925,
+ 743, 747, 745, 925, 798, 451, 326, 764, 745, 925,
+ 756, 753, 770, 925, 768, 776, 769, 925, 925, 925,
+
+ 775, 774, 787, 925, 781, 783, 260, 188, 177, 127,
+ 789, 789, 784, 799, 795, 925, 789, 790, 805, 793,
+ 800, 795, 807, 808, 925, 814, 801, 818, 925, 925,
+ 823, 925, 812, 925, 819, 826, 824, 839, 832, 828,
+ 845, 845, 829, 833, 97, 835, 847, 842, 925, 925,
+ 859, 843, 843, 853, 844, 855, 859, 925, 865, 870,
+ 925, 848, 925, 864, 872, 925, 925, 925, 917, 133,
+ 919, 132, 100, 97
+ } ;
+
+static const flex_int16_t yy_def[475] =
+ { 0,
+ 468, 1, 469, 469, 468, 468, 468, 470, 471, 472,
+ 468, 468, 468, 468, 468, 468, 468, 468, 468, 468,
+ 468, 468, 468, 468, 468, 468, 468, 468, 468, 468,
+ 468, 468, 468, 468, 468, 468, 468, 470, 471, 468,
+ 472, 468, 468, 472, 468, 468, 468, 468, 468, 468,
+ 468, 468, 468, 468, 468, 468, 468, 468, 468, 468,
+ 468, 468, 468, 468, 468, 468, 468, 468, 468, 468,
+ 468, 468, 468, 468, 468, 468, 468, 468, 468, 468,
+ 468, 468, 468, 468, 468, 468, 468, 468, 468, 468,
+ 468, 468, 468, 468, 468, 468, 468, 468, 468, 468,
+
+ 468, 468, 468, 468, 468, 468, 468, 468, 468, 468,
+ 468, 468, 468, 468, 468, 468, 468, 468, 468, 468,
+ 468, 468, 468, 468, 468, 468, 468, 468, 468, 468,
+ 468, 468, 468, 468, 468, 468, 468, 468, 468, 468,
+ 468, 468, 468, 468, 468, 468, 468, 468, 468, 468,
+ 468, 468, 468, 468, 468, 468, 468, 468, 468, 468,
+ 468, 468, 468, 468, 468, 468, 468, 468, 468, 468,
+ 468, 468, 468, 468, 468, 468, 468, 468, 468, 468,
+ 468, 468, 468, 468, 468, 468, 468, 468, 468, 468,
+ 468, 468, 468, 468, 468, 468, 468, 468, 468, 468,
+
+ 468, 468, 468, 468, 468, 468, 468, 468, 468, 468,
+ 468, 468, 468, 468, 468, 468, 468, 468, 468, 468,
+ 468, 468, 468, 468, 468, 468, 468, 468, 468, 468,
+ 468, 468, 468, 468, 468, 468, 468, 468, 468, 468,
+ 468, 468, 468, 468, 468, 468, 468, 468, 468, 468,
+ 468, 468, 468, 468, 468, 468, 468, 468, 468, 468,
+ 468, 468, 468, 468, 468, 468, 468, 468, 468, 468,
+ 468, 468, 468, 468, 468, 468, 468, 468, 468, 468,
+ 468, 468, 468, 468, 468, 468, 468, 468, 468, 468,
+ 468, 468, 468, 468, 468, 468, 468, 468, 468, 468,
+
+ 468, 468, 468, 468, 468, 468, 468, 468, 468, 468,
+ 468, 468, 468, 468, 468, 468, 468, 468, 468, 468,
+ 468, 468, 468, 468, 468, 468, 468, 468, 468, 468,
+ 468, 468, 468, 468, 468, 468, 468, 468, 468, 468,
+ 468, 468, 468, 468, 468, 468, 468, 468, 468, 468,
+ 468, 468, 468, 468, 468, 468, 468, 468, 468, 468,
+ 468, 468, 468, 468, 468, 468, 468, 468, 468, 468,
+ 468, 468, 468, 468, 468, 468, 468, 468, 468, 468,
+ 468, 468, 468, 468, 468, 473, 474, 468, 468, 468,
+ 468, 468, 468, 468, 468, 468, 468, 468, 468, 468,
+
+ 468, 468, 468, 468, 468, 468, 473, 473, 474, 474,
+ 468, 468, 468, 468, 468, 468, 468, 468, 468, 468,
+ 468, 468, 468, 468, 468, 468, 468, 468, 468, 468,
+ 468, 468, 468, 468, 468, 468, 468, 468, 468, 468,
+ 468, 468, 468, 468, 468, 468, 468, 468, 468, 468,
+ 468, 468, 468, 468, 468, 468, 468, 468, 468, 468,
+ 468, 468, 468, 468, 468, 468, 468, 0, 468, 468,
+ 468, 468, 468, 468
+ } ;
+
+static const flex_int16_t yy_nxt[991] =
+ { 0,
+ 6, 7, 8, 9, 10, 6, 11, 12, 13, 13,
+ 13, 13, 6, 6, 14, 15, 16, 17, 18, 19,
+ 6, 20, 21, 22, 6, 23, 24, 25, 26, 6,
+ 27, 28, 29, 30, 31, 32, 6, 33, 6, 6,
+ 14, 15, 16, 17, 18, 19, 6, 20, 21, 22,
+ 6, 23, 24, 25, 26, 6, 27, 28, 29, 30,
+ 31, 32, 6, 33, 6, 35, 35, 42, 36, 36,
+ 40, 40, 43, 46, 44, 45, 45, 45, 45, 48,
+ 51, 56, 53, 59, 57, 95, 52, 58, 60, 49,
+ 96, 47, 85, 42, 54, 40, 40, 409, 55, 46,
+
+ 407, 86, 50, 315, 316, 48, 51, 56, 53, 59,
+ 57, 95, 52, 58, 60, 49, 96, 47, 85, 61,
+ 54, 62, 64, 63, 55, 65, 73, 86, 50, 66,
+ 74, 67, 41, 38, 75, 77, 452, 99, 101, 76,
+ 410, 182, 78, 183, 79, 61, 97, 62, 64, 63,
+ 98, 65, 73, 102, 103, 66, 74, 67, 68, 69,
+ 75, 77, 70, 99, 101, 76, 71, 87, 78, 88,
+ 79, 72, 97, 91, 104, 105, 98, 106, 89, 102,
+ 103, 92, 90, 107, 68, 69, 108, 109, 70, 93,
+ 410, 408, 71, 87, 110, 88, 94, 72, 80, 91,
+
+ 104, 105, 81, 106, 89, 111, 82, 92, 90, 107,
+ 112, 83, 108, 109, 84, 93, 45, 45, 45, 45,
+ 110, 113, 94, 114, 80, 115, 116, 117, 81, 118,
+ 119, 111, 82, 120, 121, 122, 112, 83, 123, 124,
+ 84, 126, 127, 128, 125, 129, 131, 113, 132, 114,
+ 133, 115, 116, 117, 130, 118, 119, 134, 135, 120,
+ 121, 122, 139, 408, 123, 124, 140, 126, 127, 128,
+ 125, 129, 131, 141, 132, 136, 133, 142, 143, 144,
+ 130, 145, 137, 134, 135, 147, 148, 152, 139, 138,
+ 153, 154, 140, 146, 155, 156, 149, 157, 158, 141,
+
+ 159, 136, 160, 142, 143, 144, 150, 145, 137, 161,
+ 151, 147, 148, 152, 162, 138, 153, 154, 164, 146,
+ 155, 156, 149, 157, 158, 165, 159, 166, 160, 168,
+ 169, 163, 150, 170, 171, 161, 151, 172, 173, 410,
+ 162, 174, 176, 177, 164, 178, 179, 180, 181, 184,
+ 185, 165, 186, 166, 187, 168, 169, 163, 189, 170,
+ 171, 190, 191, 172, 173, 175, 192, 174, 176, 177,
+ 193, 178, 179, 180, 181, 184, 185, 194, 186, 195,
+ 187, 196, 197, 198, 189, 199, 200, 190, 191, 201,
+ 202, 203, 192, 204, 205, 207, 193, 208, 209, 210,
+
+ 211, 206, 212, 194, 213, 195, 214, 196, 197, 198,
+ 215, 199, 200, 216, 217, 201, 202, 203, 218, 204,
+ 205, 207, 219, 208, 209, 210, 211, 206, 212, 220,
+ 213, 221, 214, 222, 223, 224, 215, 225, 226, 216,
+ 217, 227, 228, 229, 218, 230, 231, 232, 219, 233,
+ 235, 236, 237, 238, 408, 220, 241, 221, 242, 222,
+ 223, 224, 234, 225, 226, 243, 244, 227, 228, 229,
+ 245, 230, 231, 232, 246, 233, 235, 236, 237, 238,
+ 239, 247, 241, 240, 242, 248, 249, 250, 234, 251,
+ 252, 243, 244, 253, 254, 255, 245, 256, 257, 258,
+
+ 246, 259, 260, 261, 262, 265, 239, 247, 263, 240,
+ 264, 248, 249, 250, 266, 251, 252, 267, 268, 253,
+ 254, 255, 269, 256, 257, 258, 270, 259, 260, 261,
+ 262, 265, 271, 272, 263, 273, 264, 274, 275, 276,
+ 266, 277, 278, 267, 268, 279, 280, 281, 269, 282,
+ 284, 285, 270, 286, 287, 288, 289, 290, 271, 272,
+ 291, 273, 292, 274, 275, 276, 293, 277, 278, 294,
+ 295, 279, 280, 281, 296, 282, 284, 285, 297, 286,
+ 287, 288, 289, 290, 298, 299, 291, 300, 292, 301,
+ 302, 303, 293, 304, 305, 294, 295, 306, 307, 308,
+
+ 296, 309, 310, 311, 297, 312, 313, 314, 317, 318,
+ 298, 299, 319, 300, 320, 301, 302, 303, 321, 304,
+ 305, 322, 323, 306, 307, 308, 324, 309, 310, 311,
+ 325, 312, 313, 314, 317, 318, 326, 327, 319, 330,
+ 320, 328, 331, 332, 321, 333, 334, 322, 323, 335,
+ 336, 337, 324, 338, 329, 339, 325, 340, 341, 342,
+ 343, 344, 326, 327, 345, 330, 346, 328, 331, 332,
+ 347, 333, 334, 348, 349, 335, 336, 337, 350, 338,
+ 329, 339, 351, 340, 341, 342, 343, 344, 352, 354,
+ 345, 355, 346, 356, 357, 359, 347, 360, 362, 348,
+
+ 349, 363, 364, 365, 350, 366, 367, 368, 351, 369,
+ 370, 371, 372, 373, 352, 354, 374, 355, 375, 356,
+ 357, 359, 376, 360, 362, 377, 378, 363, 364, 365,
+ 379, 366, 367, 368, 380, 369, 370, 371, 372, 373,
+ 381, 384, 374, 385, 375, 386, 382, 388, 376, 383,
+ 389, 377, 378, 390, 387, 391, 379, 394, 395, 396,
+ 380, 397, 392, 398, 399, 393, 381, 384, 400, 402,
+ 403, 404, 382, 388, 405, 383, 389, 406, 411, 390,
+ 412, 391, 413, 394, 395, 396, 414, 397, 392, 398,
+ 399, 393, 415, 416, 400, 402, 403, 404, 417, 385,
+
+ 405, 386, 418, 406, 411, 419, 412, 420, 413, 421,
+ 387, 422, 414, 423, 424, 425, 426, 427, 415, 416,
+ 428, 429, 430, 431, 417, 432, 433, 434, 418, 435,
+ 436, 419, 437, 420, 438, 421, 439, 422, 440, 423,
+ 424, 425, 426, 427, 441, 442, 428, 429, 430, 431,
+ 443, 432, 433, 434, 444, 435, 436, 445, 437, 446,
+ 438, 447, 439, 448, 440, 449, 450, 451, 453, 454,
+ 441, 442, 455, 456, 457, 458, 443, 459, 460, 461,
+ 444, 462, 463, 445, 464, 446, 465, 447, 466, 448,
+ 467, 449, 450, 451, 453, 454, 401, 361, 455, 456,
+
+ 457, 458, 358, 459, 460, 461, 353, 462, 463, 283,
+ 464, 188, 465, 167, 466, 37, 467, 34, 34, 39,
+ 39, 100, 37, 468, 5, 468, 468, 468, 468, 468,
+ 468, 468, 468, 468, 468, 468, 468, 468, 468, 468,
+ 468, 468, 468, 468, 468, 468, 468, 468, 468, 468,
+ 468, 468, 468, 468, 468, 468, 468, 468, 468, 468,
+ 468, 468, 468, 468, 468, 468, 468, 468, 468, 468,
+ 468, 468, 468, 468, 468, 468, 468, 468, 468, 468,
+ 468, 468, 468, 468, 468, 468, 468, 468, 468, 468
+ } ;
+
+static const flex_int16_t yy_chk[991] =
+ { 0,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 3, 4, 11, 3, 4,
+ 9, 9, 12, 14, 12, 13, 13, 13, 13, 15,
+ 16, 18, 17, 20, 19, 30, 16, 19, 20, 15,
+ 31, 14, 27, 11, 17, 39, 39, 474, 17, 14,
+
+ 473, 27, 15, 268, 268, 15, 16, 18, 17, 20,
+ 19, 30, 16, 19, 20, 15, 31, 14, 27, 21,
+ 17, 21, 22, 21, 17, 22, 24, 27, 15, 22,
+ 24, 22, 472, 470, 24, 25, 445, 33, 42, 24,
+ 410, 118, 25, 118, 25, 21, 32, 21, 22, 21,
+ 32, 22, 24, 46, 47, 22, 24, 22, 23, 23,
+ 24, 25, 23, 33, 42, 24, 23, 28, 25, 28,
+ 25, 23, 32, 29, 48, 49, 32, 50, 28, 46,
+ 47, 29, 28, 51, 23, 23, 52, 52, 23, 29,
+ 409, 408, 23, 28, 53, 28, 29, 23, 26, 29,
+
+ 48, 49, 26, 50, 28, 54, 26, 29, 28, 51,
+ 55, 26, 52, 52, 26, 29, 45, 45, 45, 45,
+ 53, 56, 29, 57, 26, 59, 60, 61, 26, 62,
+ 63, 54, 26, 64, 65, 66, 55, 26, 67, 68,
+ 26, 69, 70, 71, 68, 72, 73, 56, 74, 57,
+ 75, 59, 60, 61, 72, 62, 63, 76, 77, 64,
+ 65, 66, 80, 407, 67, 68, 81, 69, 70, 71,
+ 68, 72, 73, 82, 74, 79, 75, 83, 84, 85,
+ 72, 85, 79, 76, 77, 86, 87, 89, 80, 79,
+ 90, 91, 81, 85, 92, 93, 88, 94, 95, 82,
+
+ 96, 79, 97, 83, 84, 85, 88, 85, 79, 98,
+ 88, 86, 87, 89, 99, 79, 90, 91, 101, 85,
+ 92, 93, 88, 94, 95, 102, 96, 103, 97, 105,
+ 106, 99, 88, 107, 108, 98, 88, 109, 110, 387,
+ 99, 111, 112, 113, 101, 114, 115, 116, 117, 120,
+ 122, 102, 123, 103, 124, 105, 106, 99, 126, 107,
+ 108, 127, 128, 109, 110, 111, 129, 111, 112, 113,
+ 130, 114, 115, 116, 117, 120, 122, 131, 123, 132,
+ 124, 133, 134, 136, 126, 138, 139, 127, 128, 140,
+ 141, 142, 129, 143, 144, 145, 130, 146, 147, 148,
+
+ 149, 144, 150, 131, 151, 132, 152, 133, 134, 136,
+ 154, 138, 139, 155, 156, 140, 141, 142, 157, 143,
+ 144, 145, 158, 146, 147, 148, 149, 144, 150, 159,
+ 151, 160, 152, 161, 162, 164, 154, 165, 167, 155,
+ 156, 168, 169, 170, 157, 171, 172, 174, 158, 175,
+ 176, 177, 178, 179, 386, 159, 181, 160, 184, 161,
+ 162, 164, 175, 165, 167, 185, 186, 168, 169, 170,
+ 188, 171, 172, 174, 189, 175, 176, 177, 178, 179,
+ 180, 190, 181, 180, 184, 191, 193, 195, 175, 196,
+ 197, 185, 186, 199, 200, 201, 188, 202, 204, 205,
+
+ 189, 206, 207, 208, 209, 211, 180, 190, 210, 180,
+ 210, 191, 193, 195, 212, 196, 197, 213, 214, 199,
+ 200, 201, 215, 202, 204, 205, 216, 206, 207, 208,
+ 209, 211, 219, 220, 210, 221, 210, 222, 223, 224,
+ 212, 225, 226, 213, 214, 227, 229, 230, 215, 231,
+ 233, 234, 216, 235, 236, 239, 240, 241, 219, 220,
+ 242, 221, 243, 222, 223, 224, 245, 225, 226, 246,
+ 247, 227, 229, 230, 248, 231, 233, 234, 249, 235,
+ 236, 239, 240, 241, 250, 251, 242, 252, 243, 253,
+ 254, 255, 245, 256, 257, 246, 247, 258, 259, 260,
+
+ 248, 262, 263, 264, 249, 265, 266, 267, 269, 270,
+ 250, 251, 271, 252, 274, 253, 254, 255, 276, 256,
+ 257, 277, 278, 258, 259, 260, 279, 262, 263, 264,
+ 280, 265, 266, 267, 269, 270, 281, 282, 271, 284,
+ 274, 283, 285, 286, 276, 288, 289, 277, 278, 292,
+ 293, 295, 279, 296, 283, 298, 280, 299, 301, 302,
+ 303, 304, 281, 282, 305, 284, 306, 283, 285, 286,
+ 307, 288, 289, 308, 310, 292, 293, 295, 311, 296,
+ 283, 298, 312, 299, 301, 302, 303, 304, 313, 318,
+ 305, 319, 306, 320, 321, 323, 307, 324, 327, 308,
+
+ 310, 328, 329, 330, 311, 331, 332, 333, 312, 334,
+ 335, 336, 337, 339, 313, 318, 340, 319, 342, 320,
+ 321, 323, 345, 324, 327, 346, 347, 328, 329, 330,
+ 348, 331, 332, 333, 352, 334, 335, 336, 337, 339,
+ 353, 355, 340, 357, 342, 357, 353, 358, 345, 353,
+ 359, 346, 347, 360, 357, 361, 348, 362, 363, 365,
+ 352, 366, 361, 369, 370, 361, 353, 355, 372, 377,
+ 379, 381, 353, 358, 382, 353, 359, 383, 388, 360,
+ 389, 361, 391, 362, 363, 365, 392, 366, 361, 369,
+ 370, 361, 393, 395, 372, 377, 379, 381, 396, 385,
+
+ 382, 385, 397, 383, 388, 401, 389, 402, 391, 403,
+ 385, 405, 392, 406, 411, 412, 413, 414, 393, 395,
+ 415, 417, 418, 419, 396, 420, 421, 422, 397, 423,
+ 424, 401, 426, 402, 427, 403, 428, 405, 431, 406,
+ 411, 412, 413, 414, 433, 435, 415, 417, 418, 419,
+ 436, 420, 421, 422, 437, 423, 424, 438, 426, 439,
+ 427, 440, 428, 441, 431, 442, 443, 444, 446, 447,
+ 433, 435, 448, 451, 452, 453, 436, 454, 455, 456,
+ 437, 457, 459, 438, 460, 439, 462, 440, 464, 441,
+ 465, 442, 443, 444, 446, 447, 373, 326, 448, 451,
+
+ 452, 453, 322, 454, 455, 456, 317, 457, 459, 232,
+ 460, 125, 462, 104, 464, 37, 465, 469, 469, 471,
+ 471, 36, 7, 5, 468, 468, 468, 468, 468, 468,
+ 468, 468, 468, 468, 468, 468, 468, 468, 468, 468,
+ 468, 468, 468, 468, 468, 468, 468, 468, 468, 468,
+ 468, 468, 468, 468, 468, 468, 468, 468, 468, 468,
+ 468, 468, 468, 468, 468, 468, 468, 468, 468, 468,
+ 468, 468, 468, 468, 468, 468, 468, 468, 468, 468,
+ 468, 468, 468, 468, 468, 468, 468, 468, 468, 468
+ } ;
+
+static yy_state_type yy_last_accepting_state;
+static char *yy_last_accepting_cpos;
+
+extern int yy_flex_debug;
+int yy_flex_debug = 0;
+
+/* The intent behind this definition is that it'll catch
+ * any uses of REJECT which flex missed.
+ */
+#define REJECT reject_used_but_not_detected
+static int yy_more_flag = 0;
+static int yy_more_len = 0;
+#define yymore() ((yy_more_flag) = 1)
+#define YY_MORE_ADJ (yy_more_len)
+#define YY_RESTORE_YY_MORE_OFFSET
+char *yytext;
+#line 1 "config-lexer.l"
+/*
+ * Copyright (c) 2002 Erik Fears
+ * Copyright (c) 2014-2018 ircd-hybrid 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 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
+ * USA
+ */
+#define YY_NO_INPUT 1
+
+#line 30 "config-lexer.l"
+#include <stdio.h>
+#include <string.h>
+
+#include "compat.h"
+#include "config.h"
+#include "config-parser.h" /* autogenerated header file */
+#include "log.h"
+
+/* libopm includes */
+#include "libopm/src/opm_types.h"
+
+#undef YY_FATAL_ERROR
+#define YY_FATAL_ERROR(msg) conf_yy_fatal_error(msg)
+
+#undef YY_INPUT
+#define YY_INPUT(buf,result,max_size) \
+ if (!(result = conf_yy_input(buf, max_size))) \
+ YY_FATAL_ERROR("input in flex scanner failed");
+#define MAX_INCLUDE_DEPTH 10
+
+
+unsigned int lineno = 1;
+char linebuf[512];
+char conffilebuf[512];
+
+static struct included_file
+{
+ YY_BUFFER_STATE state;
+ unsigned int lineno;
+ FILE *file;
+ char conffile[512];
+} include_stack[MAX_INCLUDE_DEPTH];
+
+static unsigned int include_stack_ptr;
+
+
+static void conf_include(void);
+static int conf_eof(void);
+
+static int
+conf_yy_input(char *lbuf, unsigned int max_size)
+{
+ return fgets(lbuf, max_size, conf_file) == NULL ? 0 : strlen(lbuf);
+}
+
+static int
+conf_yy_fatal_error(const char *msg)
+{
+ return 0;
+}
+#line 890 "config-lexer.c"
+#line 891 "config-lexer.c"
+
+#define INITIAL 0
+#define IN_COMMENT 1
+
+#ifndef YY_NO_UNISTD_H
+/* Special case for "unistd.h", since it is non-ANSI. We include it way
+ * down here because we want the user's section 1 to have been scanned first.
+ * The user has a chance to override it with an option.
+ */
+#include <unistd.h>
+#endif
+
+#ifndef YY_EXTRA_TYPE
+#define YY_EXTRA_TYPE void *
+#endif
+
+static int yy_init_globals ( void );
+
+/* Accessor methods to globals.
+ These are made visible to non-reentrant scanners for convenience. */
+
+int yylex_destroy ( void );
+
+int yyget_debug ( void );
+
+void yyset_debug ( int debug_flag );
+
+YY_EXTRA_TYPE yyget_extra ( void );
+
+void yyset_extra ( YY_EXTRA_TYPE user_defined );
+
+FILE *yyget_in ( void );
+
+void yyset_in ( FILE * _in_str );
+
+FILE *yyget_out ( void );
+
+void yyset_out ( FILE * _out_str );
+
+ int yyget_leng ( void );
+
+char *yyget_text ( void );
+
+int yyget_lineno ( void );
+
+void yyset_lineno ( int _line_number );
+
+/* Macros after this point can all be overridden by user definitions in
+ * section 1.
+ */
+
+#ifndef YY_SKIP_YYWRAP
+#ifdef __cplusplus
+extern "C" int yywrap ( void );
+#else
+extern int yywrap ( void );
+#endif
+#endif
+
+#ifndef YY_NO_UNPUT
+
+#endif
+
+#ifndef yytext_ptr
+static void yy_flex_strncpy ( char *, const char *, int );
+#endif
+
+#ifdef YY_NEED_STRLEN
+static int yy_flex_strlen ( const char * );
+#endif
+
+#ifndef YY_NO_INPUT
+#ifdef __cplusplus
+static int yyinput ( void );
+#else
+static int input ( void );
+#endif
+
+#endif
+
+/* Amount of stuff to slurp up with each read. */
+#ifndef YY_READ_BUF_SIZE
+#ifdef __ia64__
+/* On IA-64, the buffer size is 16k, not 8k */
+#define YY_READ_BUF_SIZE 16384
+#else
+#define YY_READ_BUF_SIZE 8192
+#endif /* __ia64__ */
+#endif
+
+/* Copy whatever the last rule matched to the standard output. */
+#ifndef ECHO
+/* This used to be an fputs(), but since the string might contain NUL's,
+ * we now use fwrite().
+ */
+#define ECHO do { if (fwrite( yytext, (size_t) yyleng, 1, yyout )) {} } while (0)
+#endif
+
+/* Gets input and stuffs it into "buf". number of characters read, or YY_NULL,
+ * is returned in "result".
+ */
+#ifndef YY_INPUT
+#define YY_INPUT(buf,result,max_size) \
+ if ( YY_CURRENT_BUFFER_LVALUE->yy_is_interactive ) \
+ { \
+ int c = '*'; \
+ int n; \
+ for ( n = 0; n < max_size && \
+ (c = getc( yyin )) != EOF && c != '\n'; ++n ) \
+ buf[n] = (char) c; \
+ if ( c == '\n' ) \
+ buf[n++] = (char) c; \
+ if ( c == EOF && ferror( yyin ) ) \
+ YY_FATAL_ERROR( "input in flex scanner failed" ); \
+ result = n; \
+ } \
+ else \
+ { \
+ errno=0; \
+ while ( (result = (int) fread(buf, 1, (yy_size_t) max_size, yyin)) == 0 && ferror(yyin)) \
+ { \
+ if( errno != EINTR) \
+ { \
+ YY_FATAL_ERROR( "input in flex scanner failed" ); \
+ break; \
+ } \
+ errno=0; \
+ clearerr(yyin); \
+ } \
+ }\
+\
+
+#endif
+
+/* No semi-colon after return; correct usage is to write "yyterminate();" -
+ * we don't want an extra ';' after the "return" because that will cause
+ * some compilers to complain about unreachable statements.
+ */
+#ifndef yyterminate
+#define yyterminate() return YY_NULL
+#endif
+
+/* Number of entries by which start-condition stack grows. */
+#ifndef YY_START_STACK_INCR
+#define YY_START_STACK_INCR 25
+#endif
+
+/* Report a fatal error. */
+#ifndef YY_FATAL_ERROR
+#define YY_FATAL_ERROR(msg) yy_fatal_error( msg )
+#endif
+
+/* end tables serialization structures and prototypes */
+
+/* Default declaration of generated scanner - a define so the user can
+ * easily add parameters.
+ */
+#ifndef YY_DECL
+#define YY_DECL_IS_OURS 1
+
+extern int yylex (void);
+
+#define YY_DECL int yylex (void)
+#endif /* !YY_DECL */
+
+/* Code executed at the beginning of each rule, after yytext and yyleng
+ * have been set up.
+ */
+#ifndef YY_USER_ACTION
+#define YY_USER_ACTION
+#endif
+
+/* Code executed at the end of each rule. */
+#ifndef YY_BREAK
+#define YY_BREAK /*LINTED*/break;
+#endif
+
+#define YY_RULE_SETUP \
+ YY_USER_ACTION
+
+/** The main scanner function which does all the work.
+ */
+YY_DECL
+{
+ yy_state_type yy_current_state;
+ char *yy_cp, *yy_bp;
+ int yy_act;
+
+ if ( !(yy_init) )
+ {
+ (yy_init) = 1;
+
+#ifdef YY_USER_INIT
+ YY_USER_INIT;
+#endif
+
+ if ( ! (yy_start) )
+ (yy_start) = 1; /* first start state */
+
+ if ( ! yyin )
+ yyin = stdin;
+
+ if ( ! yyout )
+ yyout = stdout;
+
+ if ( ! YY_CURRENT_BUFFER ) {
+ yyensure_buffer_stack ();
+ YY_CURRENT_BUFFER_LVALUE =
+ yy_create_buffer( yyin, YY_BUF_SIZE );
+ }
+
+ yy_load_buffer_state( );
+ }
+
+ {
+#line 88 "config-lexer.l"
+
+
+#line 1110 "config-lexer.c"
+
+ while ( /*CONSTCOND*/1 ) /* loops until end-of-file is reached */
+ {
+ (yy_more_len) = 0;
+ if ( (yy_more_flag) )
+ {
+ (yy_more_len) = (int) ((yy_c_buf_p) - (yytext_ptr));
+ (yy_more_flag) = 0;
+ }
+ yy_cp = (yy_c_buf_p);
+
+ /* Support of yytext. */
+ *yy_cp = (yy_hold_char);
+
+ /* yy_bp points to the position in yy_ch_buf of the start of
+ * the current run.
+ */
+ yy_bp = yy_cp;
+
+ yy_current_state = (yy_start);
+yy_match:
+ do
+ {
+ YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)] ;
+ if ( yy_accept[yy_current_state] )
+ {
+ (yy_last_accepting_state) = yy_current_state;
+ (yy_last_accepting_cpos) = yy_cp;
+ }
+ while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+ {
+ yy_current_state = (int) yy_def[yy_current_state];
+ if ( yy_current_state >= 469 )
+ yy_c = yy_meta[yy_c];
+ }
+ yy_current_state = yy_nxt[yy_base[yy_current_state] + yy_c];
+ ++yy_cp;
+ }
+ while ( yy_current_state != 468 );
+ yy_cp = (yy_last_accepting_cpos);
+ yy_current_state = (yy_last_accepting_state);
+
+yy_find_action:
+ yy_act = yy_accept[yy_current_state];
+
+ YY_DO_BEFORE_ACTION;
+
+do_action: /* This label is used only to access EOF actions. */
+
+ switch ( yy_act )
+ { /* beginning of action switch */
+ case 0: /* must back up */
+ /* undo the effects of YY_DO_BEFORE_ACTION */
+ *yy_cp = (yy_hold_char);
+ yy_cp = (yy_last_accepting_cpos);
+ yy_current_state = (yy_last_accepting_state);
+ goto yy_find_action;
+
+case 1:
+YY_RULE_SETUP
+#line 90 "config-lexer.l"
+{ BEGIN IN_COMMENT; }
+ YY_BREAK
+case 2:
+YY_RULE_SETUP
+#line 91 "config-lexer.l"
+{ BEGIN INITIAL; }
+ YY_BREAK
+case 3:
+YY_RULE_SETUP
+#line 92 "config-lexer.l"
+; /* Eat everything but a newline */
+ YY_BREAK
+case 4:
+/* rule 4 can match eol */
+YY_RULE_SETUP
+#line 93 "config-lexer.l"
+{ ++lineno; }
+ YY_BREAK
+case YY_STATE_EOF(IN_COMMENT):
+#line 94 "config-lexer.l"
+{ BEGIN INITIAL; if (conf_eof()) yyterminate(); }
+ YY_BREAK
+case 5:
+YY_RULE_SETUP
+#line 96 "config-lexer.l"
+{ conf_include(); }
+ YY_BREAK
+case 6:
+/* rule 6 can match eol */
+YY_RULE_SETUP
+#line 97 "config-lexer.l"
+{ strlcpy(linebuf, yytext + 1, sizeof(linebuf)); ++lineno; yyless(1); }
+ YY_BREAK
+case 7:
+YY_RULE_SETUP
+#line 98 "config-lexer.l"
+;
+ YY_BREAK
+case 8:
+YY_RULE_SETUP
+#line 99 "config-lexer.l"
+;
+ YY_BREAK
+case 9:
+YY_RULE_SETUP
+#line 100 "config-lexer.l"
+{ yylval.number = atoi(yytext); return NUMBER; }
+ YY_BREAK
+case 10:
+/* rule 10 can match eol */
+YY_RULE_SETUP
+#line 101 "config-lexer.l"
+{ if (yytext[yyleng - 2] == '\\')
+ {
+ yyless(yyleng - 1); /* Return last quote */
+ yymore(); /* Append next string */
+ }
+ else
+ {
+ yylval.string = yytext + 1;
+
+ if (yylval.string[yyleng - 2] != '"')
+ log_printf("CONFIG ->Unterminated character string");
+ else
+ {
+ unsigned int i = 0, j = 0;
+
+ yylval.string[yyleng - 2] = '\0'; /* Remove close quote */
+
+ for (; yylval.string[i] != '\0'; ++i, ++j)
+ {
+ if (yylval.string[i] != '\\')
+ yylval.string[j] = yylval.string[i];
+ else
+ {
+ ++i;
+
+ if (yylval.string[i] == '\0') /* XXX: should not happen */
+ {
+ log_printf("CONFIG -> Unterminated character string");
+ break;
+ }
+
+ yylval.string[j] = yylval.string[i];
+ }
+ }
+
+ yylval.string[j] = '\0';
+ return STRING;
+ }
+ }
+ }
+ YY_BREAK
+case 11:
+YY_RULE_SETUP
+#line 142 "config-lexer.l"
+{ return ADDRESS_FAMILY; }
+ YY_BREAK
+case 12:
+YY_RULE_SETUP
+#line 143 "config-lexer.l"
+{ return AWAY; }
+ YY_BREAK
+case 13:
+YY_RULE_SETUP
+#line 144 "config-lexer.l"
+{ return BAN_UNKNOWN; }
+ YY_BREAK
+case 14:
+YY_RULE_SETUP
+#line 145 "config-lexer.l"
+{ return BLACKLIST; }
+ YY_BREAK
+case 15:
+YY_RULE_SETUP
+#line 146 "config-lexer.l"
+{ return CHANNEL; }
+ YY_BREAK
+case 16:
+YY_RULE_SETUP
+#line 147 "config-lexer.l"
+{ return COMMAND_INTERVAL; }
+ YY_BREAK
+case 17:
+YY_RULE_SETUP
+#line 148 "config-lexer.l"
+{ return COMMAND_QUEUE_SIZE; }
+ YY_BREAK
+case 18:
+YY_RULE_SETUP
+#line 149 "config-lexer.l"
+{ return COMMAND_TIMEOUT; }
+ YY_BREAK
+case 19:
+YY_RULE_SETUP
+#line 150 "config-lexer.l"
+{ return CONNREGEX; }
+ YY_BREAK
+case 20:
+YY_RULE_SETUP
+#line 151 "config-lexer.l"
+{ return DNS_FDLIMIT; }
+ YY_BREAK
+case 21:
+YY_RULE_SETUP
+#line 152 "config-lexer.l"
+{ return DNS_TIMEOUT; }
+ YY_BREAK
+case 22:
+YY_RULE_SETUP
+#line 153 "config-lexer.l"
+{ return DNSBL_FROM; }
+ YY_BREAK
+case 23:
+YY_RULE_SETUP
+#line 154 "config-lexer.l"
+{ return DNSBL_TO; }
+ YY_BREAK
+case 24:
+YY_RULE_SETUP
+#line 155 "config-lexer.l"
+{ return EXEMPT; }
+ YY_BREAK
+case 25:
+YY_RULE_SETUP
+#line 156 "config-lexer.l"
+{ return FD; }
+ YY_BREAK
+case 26:
+YY_RULE_SETUP
+#line 157 "config-lexer.l"
+{ return INVITE; }
+ YY_BREAK
+case 27:
+YY_RULE_SETUP
+#line 158 "config-lexer.l"
+{ return IPV4; }
+ YY_BREAK
+case 28:
+YY_RULE_SETUP
+#line 159 "config-lexer.l"
+{ return IPV6; }
+ YY_BREAK
+case 29:
+YY_RULE_SETUP
+#line 160 "config-lexer.l"
+{ return IRC; }
+ YY_BREAK
+case 30:
+YY_RULE_SETUP
+#line 161 "config-lexer.l"
+{ return KLINE; }
+ YY_BREAK
+case 31:
+YY_RULE_SETUP
+#line 162 "config-lexer.l"
+{ return KEY; }
+ YY_BREAK
+case 32:
+YY_RULE_SETUP
+#line 163 "config-lexer.l"
+{ return MASK; }
+ YY_BREAK
+case 33:
+YY_RULE_SETUP
+#line 164 "config-lexer.l"
+{ return MAX_READ; }
+ YY_BREAK
+case 34:
+YY_RULE_SETUP
+#line 165 "config-lexer.l"
+{ return MODE; }
+ YY_BREAK
+case 35:
+YY_RULE_SETUP
+#line 166 "config-lexer.l"
+{ return NAME; }
+ YY_BREAK
+case 36:
+YY_RULE_SETUP
+#line 167 "config-lexer.l"
+{ return NEGCACHE; }
+ YY_BREAK
+case 37:
+YY_RULE_SETUP
+#line 168 "config-lexer.l"
+{ return NEGCACHE_REBUILD; }
+ YY_BREAK
+case 38:
+YY_RULE_SETUP
+#line 169 "config-lexer.l"
+{ return NICK; }
+ YY_BREAK
+case 39:
+YY_RULE_SETUP
+#line 170 "config-lexer.l"
+{ return NICKSERV; }
+ YY_BREAK
+case 40:
+YY_RULE_SETUP
+#line 171 "config-lexer.l"
+{ return NOTICE; }
+ YY_BREAK
+case 41:
+YY_RULE_SETUP
+#line 172 "config-lexer.l"
+{ return OPER; }
+ YY_BREAK
+case 42:
+YY_RULE_SETUP
+#line 173 "config-lexer.l"
+{ return OPM; }
+ YY_BREAK
+case 43:
+YY_RULE_SETUP
+#line 174 "config-lexer.l"
+{ return OPTIONS; }
+ YY_BREAK
+case 44:
+YY_RULE_SETUP
+#line 175 "config-lexer.l"
+{ return PASSWORD; }
+ YY_BREAK
+case 45:
+YY_RULE_SETUP
+#line 176 "config-lexer.l"
+{ return PERFORM; }
+ YY_BREAK
+case 46:
+YY_RULE_SETUP
+#line 177 "config-lexer.l"
+{ return PIDFILE; }
+ YY_BREAK
+case 47:
+YY_RULE_SETUP
+#line 178 "config-lexer.l"
+{ return PORT; }
+ YY_BREAK
+case 48:
+YY_RULE_SETUP
+#line 179 "config-lexer.l"
+{ return PROTOCOL; }
+ YY_BREAK
+case 49:
+YY_RULE_SETUP
+#line 180 "config-lexer.l"
+{ return READTIMEOUT; }
+ YY_BREAK
+case 50:
+YY_RULE_SETUP
+#line 181 "config-lexer.l"
+{ return REALNAME; }
+ YY_BREAK
+case 51:
+YY_RULE_SETUP
+#line 182 "config-lexer.l"
+{ return RECONNECTINTERVAL; }
+ YY_BREAK
+case 52:
+YY_RULE_SETUP
+#line 183 "config-lexer.l"
+{ return REPLY; }
+ YY_BREAK
+case 53:
+YY_RULE_SETUP
+#line 184 "config-lexer.l"
+{ return SCANLOG; }
+ YY_BREAK
+case 54:
+YY_RULE_SETUP
+#line 185 "config-lexer.l"
+{ return SCANNER; }
+ YY_BREAK
+case 55:
+YY_RULE_SETUP
+#line 186 "config-lexer.l"
+{ return SENDMAIL; }
+ YY_BREAK
+case 56:
+YY_RULE_SETUP
+#line 187 "config-lexer.l"
+{ return SERVER; }
+ YY_BREAK
+case 57:
+YY_RULE_SETUP
+#line 188 "config-lexer.l"
+{ return TARGET_IP; }
+ YY_BREAK
+case 58:
+YY_RULE_SETUP
+#line 189 "config-lexer.l"
+{ return TARGET_PORT; }
+ YY_BREAK
+case 59:
+YY_RULE_SETUP
+#line 190 "config-lexer.l"
+{ return TARGET_STRING;}
+ YY_BREAK
+case 60:
+YY_RULE_SETUP
+#line 191 "config-lexer.l"
+{ return TIMEOUT; }
+ YY_BREAK
+case 61:
+YY_RULE_SETUP
+#line 192 "config-lexer.l"
+{ return TYPE; }
+ YY_BREAK
+case 62:
+YY_RULE_SETUP
+#line 193 "config-lexer.l"
+{ return USER; }
+ YY_BREAK
+case 63:
+YY_RULE_SETUP
+#line 194 "config-lexer.l"
+{ return USERNAME; }
+ YY_BREAK
+case 64:
+YY_RULE_SETUP
+#line 195 "config-lexer.l"
+{ return VHOST; }
+ YY_BREAK
+case 65:
+YY_RULE_SETUP
+#line 197 "config-lexer.l"
+{ return YEARS; }
+ YY_BREAK
+case 66:
+YY_RULE_SETUP
+#line 198 "config-lexer.l"
+{ return YEARS; }
+ YY_BREAK
+case 67:
+YY_RULE_SETUP
+#line 199 "config-lexer.l"
+{ return MONTHS; }
+ YY_BREAK
+case 68:
+YY_RULE_SETUP
+#line 200 "config-lexer.l"
+{ return MONTHS; }
+ YY_BREAK
+case 69:
+YY_RULE_SETUP
+#line 201 "config-lexer.l"
+{ return WEEKS; }
+ YY_BREAK
+case 70:
+YY_RULE_SETUP
+#line 202 "config-lexer.l"
+{ return WEEKS; }
+ YY_BREAK
+case 71:
+YY_RULE_SETUP
+#line 203 "config-lexer.l"
+{ return DAYS; }
+ YY_BREAK
+case 72:
+YY_RULE_SETUP
+#line 204 "config-lexer.l"
+{ return DAYS; }
+ YY_BREAK
+case 73:
+YY_RULE_SETUP
+#line 205 "config-lexer.l"
+{ return HOURS; }
+ YY_BREAK
+case 74:
+YY_RULE_SETUP
+#line 206 "config-lexer.l"
+{ return HOURS; }
+ YY_BREAK
+case 75:
+YY_RULE_SETUP
+#line 207 "config-lexer.l"
+{ return MINUTES; }
+ YY_BREAK
+case 76:
+YY_RULE_SETUP
+#line 208 "config-lexer.l"
+{ return MINUTES; }
+ YY_BREAK
+case 77:
+YY_RULE_SETUP
+#line 209 "config-lexer.l"
+{ return SECONDS; }
+ YY_BREAK
+case 78:
+YY_RULE_SETUP
+#line 210 "config-lexer.l"
+{ return SECONDS; }
+ YY_BREAK
+case 79:
+YY_RULE_SETUP
+#line 212 "config-lexer.l"
+{ return BYTES; }
+ YY_BREAK
+case 80:
+YY_RULE_SETUP
+#line 213 "config-lexer.l"
+{ return BYTES; }
+ YY_BREAK
+case 81:
+YY_RULE_SETUP
+#line 214 "config-lexer.l"
+{ return KBYTES; }
+ YY_BREAK
+case 82:
+YY_RULE_SETUP
+#line 215 "config-lexer.l"
+{ return KBYTES; }
+ YY_BREAK
+case 83:
+YY_RULE_SETUP
+#line 216 "config-lexer.l"
+{ return KBYTES; }
+ YY_BREAK
+case 84:
+YY_RULE_SETUP
+#line 217 "config-lexer.l"
+{ return KBYTES; }
+ YY_BREAK
+case 85:
+YY_RULE_SETUP
+#line 218 "config-lexer.l"
+{ return KBYTES; }
+ YY_BREAK
+case 86:
+YY_RULE_SETUP
+#line 219 "config-lexer.l"
+{ return MBYTES; }
+ YY_BREAK
+case 87:
+YY_RULE_SETUP
+#line 220 "config-lexer.l"
+{ return MBYTES; }
+ YY_BREAK
+case 88:
+YY_RULE_SETUP
+#line 221 "config-lexer.l"
+{ return MBYTES; }
+ YY_BREAK
+case 89:
+YY_RULE_SETUP
+#line 222 "config-lexer.l"
+{ return MBYTES; }
+ YY_BREAK
+case 90:
+YY_RULE_SETUP
+#line 223 "config-lexer.l"
+{ return MBYTES; }
+ YY_BREAK
+case 91:
+YY_RULE_SETUP
+#line 225 "config-lexer.l"
+{
+ yylval.number = OPM_TYPE_HTTP;
+ return PROTOCOLTYPE;
+ }
+ YY_BREAK
+case 92:
+YY_RULE_SETUP
+#line 230 "config-lexer.l"
+{
+ yylval.number = OPM_TYPE_HTTPPOST;
+ return PROTOCOLTYPE;
+ }
+ YY_BREAK
+case 93:
+YY_RULE_SETUP
+#line 235 "config-lexer.l"
+{
+ yylval.number = OPM_TYPE_HTTPS;
+ return PROTOCOLTYPE;
+ }
+ YY_BREAK
+case 94:
+YY_RULE_SETUP
+#line 240 "config-lexer.l"
+{
+ yylval.number = OPM_TYPE_HTTPSPOST;
+ return PROTOCOLTYPE;
+ }
+ YY_BREAK
+case 95:
+YY_RULE_SETUP
+#line 245 "config-lexer.l"
+{
+ yylval.number = OPM_TYPE_SOCKS4;
+ return PROTOCOLTYPE;
+ }
+ YY_BREAK
+case 96:
+YY_RULE_SETUP
+#line 250 "config-lexer.l"
+{
+ yylval.number = OPM_TYPE_SOCKS5;
+ return PROTOCOLTYPE;
+ }
+ YY_BREAK
+case 97:
+YY_RULE_SETUP
+#line 255 "config-lexer.l"
+{
+ yylval.number = OPM_TYPE_WINGATE;
+ return PROTOCOLTYPE;
+ }
+ YY_BREAK
+case 98:
+YY_RULE_SETUP
+#line 260 "config-lexer.l"
+{
+ yylval.number = OPM_TYPE_ROUTER;
+ return PROTOCOLTYPE;
+ }
+ YY_BREAK
+case 99:
+YY_RULE_SETUP
+#line 265 "config-lexer.l"
+{
+ yylval.number = OPM_TYPE_DREAMBOX;
+ return PROTOCOLTYPE;
+ }
+ YY_BREAK
+case 100:
+YY_RULE_SETUP
+#line 271 "config-lexer.l"
+{
+ yylval.number = OPM_TYPE_SSH;
+ return PROTOCOLTYPE;
+ }
+ YY_BREAK
+case 101:
+YY_RULE_SETUP
+#line 276 "config-lexer.l"
+{
+ yylval.number=1;
+ return NUMBER;
+ }
+ YY_BREAK
+case 102:
+YY_RULE_SETUP
+#line 280 "config-lexer.l"
+{
+ yylval.number=1;
+ return NUMBER;
+ }
+ YY_BREAK
+case 103:
+YY_RULE_SETUP
+#line 284 "config-lexer.l"
+{
+ yylval.number=1;
+ return NUMBER;
+ }
+ YY_BREAK
+case 104:
+YY_RULE_SETUP
+#line 291 "config-lexer.l"
+{
+ yylval.number=0;
+ return NUMBER;
+ }
+ YY_BREAK
+case 105:
+YY_RULE_SETUP
+#line 296 "config-lexer.l"
+{
+ yylval.number=0;
+ return NUMBER;
+ }
+ YY_BREAK
+case 106:
+YY_RULE_SETUP
+#line 301 "config-lexer.l"
+{
+ yylval.number=0;
+ return NUMBER;
+ }
+ YY_BREAK
+case 107:
+YY_RULE_SETUP
+#line 306 "config-lexer.l"
+{ return yytext[0]; }
+ YY_BREAK
+case YY_STATE_EOF(INITIAL):
+#line 307 "config-lexer.l"
+{ if (conf_eof()) yyterminate(); }
+ YY_BREAK
+case 108:
+YY_RULE_SETUP
+#line 309 "config-lexer.l"
+ECHO;
+ YY_BREAK
+#line 1807 "config-lexer.c"
+
+ case YY_END_OF_BUFFER:
+ {
+ /* Amount of text matched not including the EOB char. */
+ int yy_amount_of_matched_text = (int) (yy_cp - (yytext_ptr)) - 1;
+
+ /* Undo the effects of YY_DO_BEFORE_ACTION. */
+ *yy_cp = (yy_hold_char);
+ YY_RESTORE_YY_MORE_OFFSET
+
+ if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_NEW )
+ {
+ /* We're scanning a new file or input source. It's
+ * possible that this happened because the user
+ * just pointed yyin at a new source and called
+ * yylex(). If so, then we have to assure
+ * consistency between YY_CURRENT_BUFFER and our
+ * globals. Here is the right place to do so, because
+ * this is the first action (other than possibly a
+ * back-up) that will match for the new input source.
+ */
+ (yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_n_chars;
+ YY_CURRENT_BUFFER_LVALUE->yy_input_file = yyin;
+ YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = YY_BUFFER_NORMAL;
+ }
+
+ /* Note that here we test for yy_c_buf_p "<=" to the position
+ * of the first EOB in the buffer, since yy_c_buf_p will
+ * already have been incremented past the NUL character
+ * (since all states make transitions on EOB to the
+ * end-of-buffer state). Contrast this with the test
+ * in input().
+ */
+ if ( (yy_c_buf_p) <= &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] )
+ { /* This was really a NUL. */
+ yy_state_type yy_next_state;
+
+ (yy_c_buf_p) = (yytext_ptr) + yy_amount_of_matched_text;
+
+ yy_current_state = yy_get_previous_state( );
+
+ /* Okay, we're now positioned to make the NUL
+ * transition. We couldn't have
+ * yy_get_previous_state() go ahead and do it
+ * for us because it doesn't know how to deal
+ * with the possibility of jamming (and we don't
+ * want to build jamming into it because then it
+ * will run more slowly).
+ */
+
+ yy_next_state = yy_try_NUL_trans( yy_current_state );
+
+ yy_bp = (yytext_ptr) + YY_MORE_ADJ;
+
+ if ( yy_next_state )
+ {
+ /* Consume the NUL. */
+ yy_cp = ++(yy_c_buf_p);
+ yy_current_state = yy_next_state;
+ goto yy_match;
+ }
+
+ else
+ {
+ yy_cp = (yy_last_accepting_cpos);
+ yy_current_state = (yy_last_accepting_state);
+ goto yy_find_action;
+ }
+ }
+
+ else switch ( yy_get_next_buffer( ) )
+ {
+ case EOB_ACT_END_OF_FILE:
+ {
+ (yy_did_buffer_switch_on_eof) = 0;
+
+ if ( yywrap( ) )
+ {
+ /* Note: because we've taken care in
+ * yy_get_next_buffer() to have set up
+ * yytext, we can now set up
+ * yy_c_buf_p so that if some total
+ * hoser (like flex itself) wants to
+ * call the scanner after we return the
+ * YY_NULL, it'll still work - another
+ * YY_NULL will get returned.
+ */
+ (yy_c_buf_p) = (yytext_ptr) + YY_MORE_ADJ;
+
+ yy_act = YY_STATE_EOF(YY_START);
+ goto do_action;
+ }
+
+ else
+ {
+ if ( ! (yy_did_buffer_switch_on_eof) )
+ YY_NEW_FILE;
+ }
+ break;
+ }
+
+ case EOB_ACT_CONTINUE_SCAN:
+ (yy_c_buf_p) =
+ (yytext_ptr) + yy_amount_of_matched_text;
+
+ yy_current_state = yy_get_previous_state( );
+
+ yy_cp = (yy_c_buf_p);
+ yy_bp = (yytext_ptr) + YY_MORE_ADJ;
+ goto yy_match;
+
+ case EOB_ACT_LAST_MATCH:
+ (yy_c_buf_p) =
+ &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)];
+
+ yy_current_state = yy_get_previous_state( );
+
+ yy_cp = (yy_c_buf_p);
+ yy_bp = (yytext_ptr) + YY_MORE_ADJ;
+ goto yy_find_action;
+ }
+ break;
+ }
+
+ default:
+ YY_FATAL_ERROR(
+ "fatal flex scanner internal error--no action found" );
+ } /* end of action switch */
+ } /* end of scanning one token */
+ } /* end of user's declarations */
+} /* end of yylex */
+
+/* yy_get_next_buffer - try to read in a new buffer
+ *
+ * Returns a code representing an action:
+ * EOB_ACT_LAST_MATCH -
+ * EOB_ACT_CONTINUE_SCAN - continue scanning from current position
+ * EOB_ACT_END_OF_FILE - end of file
+ */
+static int yy_get_next_buffer (void)
+{
+ char *dest = YY_CURRENT_BUFFER_LVALUE->yy_ch_buf;
+ char *source = (yytext_ptr);
+ int number_to_move, i;
+ int ret_val;
+
+ if ( (yy_c_buf_p) > &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars) + 1] )
+ YY_FATAL_ERROR(
+ "fatal flex scanner internal error--end of buffer missed" );
+
+ if ( YY_CURRENT_BUFFER_LVALUE->yy_fill_buffer == 0 )
+ { /* Don't try to fill the buffer, so this is an EOF. */
+ if ( (yy_c_buf_p) - (yytext_ptr) - YY_MORE_ADJ == 1 )
+ {
+ /* We matched a single character, the EOB, so
+ * treat this as a final EOF.
+ */
+ return EOB_ACT_END_OF_FILE;
+ }
+
+ else
+ {
+ /* We matched some text prior to the EOB, first
+ * process it.
+ */
+ return EOB_ACT_LAST_MATCH;
+ }
+ }
+
+ /* Try to read more data. */
+
+ /* First move last chars to start of buffer. */
+ number_to_move = (int) ((yy_c_buf_p) - (yytext_ptr) - 1);
+
+ for ( i = 0; i < number_to_move; ++i )
+ *(dest++) = *(source++);
+
+ if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_EOF_PENDING )
+ /* don't do the read, it's not guaranteed to return an EOF,
+ * just force an EOF
+ */
+ YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars) = 0;
+
+ else
+ {
+ int num_to_read =
+ YY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move - 1;
+
+ while ( num_to_read <= 0 )
+ { /* Not enough room in the buffer - grow it. */
+
+ /* just a shorter name for the current buffer */
+ YY_BUFFER_STATE b = YY_CURRENT_BUFFER_LVALUE;
+
+ int yy_c_buf_p_offset =
+ (int) ((yy_c_buf_p) - b->yy_ch_buf);
+
+ if ( b->yy_is_our_buffer )
+ {
+ int new_size = b->yy_buf_size * 2;
+
+ if ( new_size <= 0 )
+ b->yy_buf_size += b->yy_buf_size / 8;
+ else
+ b->yy_buf_size *= 2;
+
+ b->yy_ch_buf = (char *)
+ /* Include room in for 2 EOB chars. */
+ yyrealloc( (void *) b->yy_ch_buf,
+ (yy_size_t) (b->yy_buf_size + 2) );
+ }
+ else
+ /* Can't grow it, we don't own it. */
+ b->yy_ch_buf = NULL;
+
+ if ( ! b->yy_ch_buf )
+ YY_FATAL_ERROR(
+ "fatal error - scanner input buffer overflow" );
+
+ (yy_c_buf_p) = &b->yy_ch_buf[yy_c_buf_p_offset];
+
+ num_to_read = YY_CURRENT_BUFFER_LVALUE->yy_buf_size -
+ number_to_move - 1;
+
+ }
+
+ if ( num_to_read > YY_READ_BUF_SIZE )
+ num_to_read = YY_READ_BUF_SIZE;
+
+ /* Read in more data. */
+ YY_INPUT( (&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]),
+ (yy_n_chars), num_to_read );
+
+ YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars);
+ }
+
+ if ( (yy_n_chars) == 0 )
+ {
+ if ( number_to_move == YY_MORE_ADJ )
+ {
+ ret_val = EOB_ACT_END_OF_FILE;
+ yyrestart( yyin );
+ }
+
+ else
+ {
+ ret_val = EOB_ACT_LAST_MATCH;
+ YY_CURRENT_BUFFER_LVALUE->yy_buffer_status =
+ YY_BUFFER_EOF_PENDING;
+ }
+ }
+
+ else
+ ret_val = EOB_ACT_CONTINUE_SCAN;
+
+ if (((yy_n_chars) + number_to_move) > YY_CURRENT_BUFFER_LVALUE->yy_buf_size) {
+ /* Extend the array by 50%, plus the number we really need. */
+ int new_size = (yy_n_chars) + number_to_move + ((yy_n_chars) >> 1);
+ YY_CURRENT_BUFFER_LVALUE->yy_ch_buf = (char *) yyrealloc(
+ (void *) YY_CURRENT_BUFFER_LVALUE->yy_ch_buf, (yy_size_t) new_size );
+ if ( ! YY_CURRENT_BUFFER_LVALUE->yy_ch_buf )
+ YY_FATAL_ERROR( "out of dynamic memory in yy_get_next_buffer()" );
+ /* "- 2" to take care of EOB's */
+ YY_CURRENT_BUFFER_LVALUE->yy_buf_size = (int) (new_size - 2);
+ }
+
+ (yy_n_chars) += number_to_move;
+ YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] = YY_END_OF_BUFFER_CHAR;
+ YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars) + 1] = YY_END_OF_BUFFER_CHAR;
+
+ (yytext_ptr) = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[0];
+
+ return ret_val;
+}
+
+/* yy_get_previous_state - get the state just before the EOB char was reached */
+
+ static yy_state_type yy_get_previous_state (void)
+{
+ yy_state_type yy_current_state;
+ char *yy_cp;
+
+ yy_current_state = (yy_start);
+
+ for ( yy_cp = (yytext_ptr) + YY_MORE_ADJ; yy_cp < (yy_c_buf_p); ++yy_cp )
+ {
+ YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1);
+ if ( yy_accept[yy_current_state] )
+ {
+ (yy_last_accepting_state) = yy_current_state;
+ (yy_last_accepting_cpos) = yy_cp;
+ }
+ while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+ {
+ yy_current_state = (int) yy_def[yy_current_state];
+ if ( yy_current_state >= 469 )
+ yy_c = yy_meta[yy_c];
+ }
+ yy_current_state = yy_nxt[yy_base[yy_current_state] + yy_c];
+ }
+
+ return yy_current_state;
+}
+
+/* yy_try_NUL_trans - try to make a transition on the NUL character
+ *
+ * synopsis
+ * next_state = yy_try_NUL_trans( current_state );
+ */
+ static yy_state_type yy_try_NUL_trans (yy_state_type yy_current_state )
+{
+ int yy_is_jam;
+ char *yy_cp = (yy_c_buf_p);
+
+ YY_CHAR yy_c = 1;
+ if ( yy_accept[yy_current_state] )
+ {
+ (yy_last_accepting_state) = yy_current_state;
+ (yy_last_accepting_cpos) = yy_cp;
+ }
+ while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+ {
+ yy_current_state = (int) yy_def[yy_current_state];
+ if ( yy_current_state >= 469 )
+ yy_c = yy_meta[yy_c];
+ }
+ yy_current_state = yy_nxt[yy_base[yy_current_state] + yy_c];
+ yy_is_jam = (yy_current_state == 468);
+
+ return yy_is_jam ? 0 : yy_current_state;
+}
+
+#ifndef YY_NO_UNPUT
+
+#endif
+
+#ifndef YY_NO_INPUT
+#ifdef __cplusplus
+ static int yyinput (void)
+#else
+ static int input (void)
+#endif
+
+{
+ int c;
+
+ *(yy_c_buf_p) = (yy_hold_char);
+
+ if ( *(yy_c_buf_p) == YY_END_OF_BUFFER_CHAR )
+ {
+ /* yy_c_buf_p now points to the character we want to return.
+ * If this occurs *before* the EOB characters, then it's a
+ * valid NUL; if not, then we've hit the end of the buffer.
+ */
+ if ( (yy_c_buf_p) < &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] )
+ /* This was really a NUL. */
+ *(yy_c_buf_p) = '\0';
+
+ else
+ { /* need more input */
+ int offset = (int) ((yy_c_buf_p) - (yytext_ptr));
+ ++(yy_c_buf_p);
+
+ switch ( yy_get_next_buffer( ) )
+ {
+ case EOB_ACT_LAST_MATCH:
+ /* This happens because yy_g_n_b()
+ * sees that we've accumulated a
+ * token and flags that we need to
+ * try matching the token before
+ * proceeding. But for input(),
+ * there's no matching to consider.
+ * So convert the EOB_ACT_LAST_MATCH
+ * to EOB_ACT_END_OF_FILE.
+ */
+
+ /* Reset buffer status. */
+ yyrestart( yyin );
+
+ /*FALLTHROUGH*/
+
+ case EOB_ACT_END_OF_FILE:
+ {
+ if ( yywrap( ) )
+ return 0;
+
+ if ( ! (yy_did_buffer_switch_on_eof) )
+ YY_NEW_FILE;
+#ifdef __cplusplus
+ return yyinput();
+#else
+ return input();
+#endif
+ }
+
+ case EOB_ACT_CONTINUE_SCAN:
+ (yy_c_buf_p) = (yytext_ptr) + offset;
+ break;
+ }
+ }
+ }
+
+ c = *(unsigned char *) (yy_c_buf_p); /* cast for 8-bit char's */
+ *(yy_c_buf_p) = '\0'; /* preserve yytext */
+ (yy_hold_char) = *++(yy_c_buf_p);
+
+ return c;
+}
+#endif /* ifndef YY_NO_INPUT */
+
+/** Immediately switch to a different input stream.
+ * @param input_file A readable stream.
+ *
+ * @note This function does not reset the start condition to @c INITIAL .
+ */
+ void yyrestart (FILE * input_file )
+{
+
+ if ( ! YY_CURRENT_BUFFER ){
+ yyensure_buffer_stack ();
+ YY_CURRENT_BUFFER_LVALUE =
+ yy_create_buffer( yyin, YY_BUF_SIZE );
+ }
+
+ yy_init_buffer( YY_CURRENT_BUFFER, input_file );
+ yy_load_buffer_state( );
+}
+
+/** Switch to a different input buffer.
+ * @param new_buffer The new input buffer.
+ *
+ */
+ void yy_switch_to_buffer (YY_BUFFER_STATE new_buffer )
+{
+
+ /* TODO. We should be able to replace this entire function body
+ * with
+ * yypop_buffer_state();
+ * yypush_buffer_state(new_buffer);
+ */
+ yyensure_buffer_stack ();
+ if ( YY_CURRENT_BUFFER == new_buffer )
+ return;
+
+ if ( YY_CURRENT_BUFFER )
+ {
+ /* Flush out information for old buffer. */
+ *(yy_c_buf_p) = (yy_hold_char);
+ YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = (yy_c_buf_p);
+ YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars);
+ }
+
+ YY_CURRENT_BUFFER_LVALUE = new_buffer;
+ yy_load_buffer_state( );
+
+ /* We don't actually know whether we did this switch during
+ * EOF (yywrap()) processing, but the only time this flag
+ * is looked at is after yywrap() is called, so it's safe
+ * to go ahead and always set it.
+ */
+ (yy_did_buffer_switch_on_eof) = 1;
+}
+
+static void yy_load_buffer_state (void)
+{
+ (yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_n_chars;
+ (yytext_ptr) = (yy_c_buf_p) = YY_CURRENT_BUFFER_LVALUE->yy_buf_pos;
+ yyin = YY_CURRENT_BUFFER_LVALUE->yy_input_file;
+ (yy_hold_char) = *(yy_c_buf_p);
+}
+
+/** Allocate and initialize an input buffer state.
+ * @param file A readable stream.
+ * @param size The character buffer size in bytes. When in doubt, use @c YY_BUF_SIZE.
+ *
+ * @return the allocated buffer state.
+ */
+ YY_BUFFER_STATE yy_create_buffer (FILE * file, int size )
+{
+ YY_BUFFER_STATE b;
+
+ b = (YY_BUFFER_STATE) yyalloc( sizeof( struct yy_buffer_state ) );
+ if ( ! b )
+ YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" );
+
+ b->yy_buf_size = size;
+
+ /* yy_ch_buf has to be 2 characters longer than the size given because
+ * we need to put in 2 end-of-buffer characters.
+ */
+ b->yy_ch_buf = (char *) yyalloc( (yy_size_t) (b->yy_buf_size + 2) );
+ if ( ! b->yy_ch_buf )
+ YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" );
+
+ b->yy_is_our_buffer = 1;
+
+ yy_init_buffer( b, file );
+
+ return b;
+}
+
+/** Destroy the buffer.
+ * @param b a buffer created with yy_create_buffer()
+ *
+ */
+ void yy_delete_buffer (YY_BUFFER_STATE b )
+{
+
+ if ( ! b )
+ return;
+
+ if ( b == YY_CURRENT_BUFFER ) /* Not sure if we should pop here. */
+ YY_CURRENT_BUFFER_LVALUE = (YY_BUFFER_STATE) 0;
+
+ if ( b->yy_is_our_buffer )
+ yyfree( (void *) b->yy_ch_buf );
+
+ yyfree( (void *) b );
+}
+
+/* Initializes or reinitializes a buffer.
+ * This function is sometimes called more than once on the same buffer,
+ * such as during a yyrestart() or at EOF.
+ */
+ static void yy_init_buffer (YY_BUFFER_STATE b, FILE * file )
+
+{
+ int oerrno = errno;
+
+ yy_flush_buffer( b );
+
+ b->yy_input_file = file;
+ b->yy_fill_buffer = 1;
+
+ /* If b is the current buffer, then yy_init_buffer was _probably_
+ * called from yyrestart() or through yy_get_next_buffer.
+ * In that case, we don't want to reset the lineno or column.
+ */
+ if (b != YY_CURRENT_BUFFER){
+ b->yy_bs_lineno = 1;
+ b->yy_bs_column = 0;
+ }
+
+ b->yy_is_interactive = 0;
+
+ errno = oerrno;
+}
+
+/** Discard all buffered characters. On the next scan, YY_INPUT will be called.
+ * @param b the buffer state to be flushed, usually @c YY_CURRENT_BUFFER.
+ *
+ */
+ void yy_flush_buffer (YY_BUFFER_STATE b )
+{
+ if ( ! b )
+ return;
+
+ b->yy_n_chars = 0;
+
+ /* We always need two end-of-buffer characters. The first causes
+ * a transition to the end-of-buffer state. The second causes
+ * a jam in that state.
+ */
+ b->yy_ch_buf[0] = YY_END_OF_BUFFER_CHAR;
+ b->yy_ch_buf[1] = YY_END_OF_BUFFER_CHAR;
+
+ b->yy_buf_pos = &b->yy_ch_buf[0];
+
+ b->yy_at_bol = 1;
+ b->yy_buffer_status = YY_BUFFER_NEW;
+
+ if ( b == YY_CURRENT_BUFFER )
+ yy_load_buffer_state( );
+}
+
+/** Pushes the new state onto the stack. The new state becomes
+ * the current state. This function will allocate the stack
+ * if necessary.
+ * @param new_buffer The new state.
+ *
+ */
+void yypush_buffer_state (YY_BUFFER_STATE new_buffer )
+{
+ if (new_buffer == NULL)
+ return;
+
+ yyensure_buffer_stack();
+
+ /* This block is copied from yy_switch_to_buffer. */
+ if ( YY_CURRENT_BUFFER )
+ {
+ /* Flush out information for old buffer. */
+ *(yy_c_buf_p) = (yy_hold_char);
+ YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = (yy_c_buf_p);
+ YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars);
+ }
+
+ /* Only push if top exists. Otherwise, replace top. */
+ if (YY_CURRENT_BUFFER)
+ (yy_buffer_stack_top)++;
+ YY_CURRENT_BUFFER_LVALUE = new_buffer;
+
+ /* copied from yy_switch_to_buffer. */
+ yy_load_buffer_state( );
+ (yy_did_buffer_switch_on_eof) = 1;
+}
+
+/** Removes and deletes the top of the stack, if present.
+ * The next element becomes the new top.
+ *
+ */
+void yypop_buffer_state (void)
+{
+ if (!YY_CURRENT_BUFFER)
+ return;
+
+ yy_delete_buffer(YY_CURRENT_BUFFER );
+ YY_CURRENT_BUFFER_LVALUE = NULL;
+ if ((yy_buffer_stack_top) > 0)
+ --(yy_buffer_stack_top);
+
+ if (YY_CURRENT_BUFFER) {
+ yy_load_buffer_state( );
+ (yy_did_buffer_switch_on_eof) = 1;
+ }
+}
+
+/* Allocates the stack if it does not exist.
+ * Guarantees space for at least one push.
+ */
+static void yyensure_buffer_stack (void)
+{
+ yy_size_t num_to_alloc;
+
+ if (!(yy_buffer_stack)) {
+
+ /* First allocation is just for 2 elements, since we don't know if this
+ * scanner will even need a stack. We use 2 instead of 1 to avoid an
+ * immediate realloc on the next call.
+ */
+ num_to_alloc = 1; /* After all that talk, this was set to 1 anyways... */
+ (yy_buffer_stack) = (struct yy_buffer_state**)yyalloc
+ (num_to_alloc * sizeof(struct yy_buffer_state*)
+ );
+ if ( ! (yy_buffer_stack) )
+ YY_FATAL_ERROR( "out of dynamic memory in yyensure_buffer_stack()" );
+
+ memset((yy_buffer_stack), 0, num_to_alloc * sizeof(struct yy_buffer_state*));
+
+ (yy_buffer_stack_max) = num_to_alloc;
+ (yy_buffer_stack_top) = 0;
+ return;
+ }
+
+ if ((yy_buffer_stack_top) >= ((yy_buffer_stack_max)) - 1){
+
+ /* Increase the buffer to prepare for a possible push. */
+ yy_size_t grow_size = 8 /* arbitrary grow size */;
+
+ num_to_alloc = (yy_buffer_stack_max) + grow_size;
+ (yy_buffer_stack) = (struct yy_buffer_state**)yyrealloc
+ ((yy_buffer_stack),
+ num_to_alloc * sizeof(struct yy_buffer_state*)
+ );
+ if ( ! (yy_buffer_stack) )
+ YY_FATAL_ERROR( "out of dynamic memory in yyensure_buffer_stack()" );
+
+ /* zero only the new slots.*/
+ memset((yy_buffer_stack) + (yy_buffer_stack_max), 0, grow_size * sizeof(struct yy_buffer_state*));
+ (yy_buffer_stack_max) = num_to_alloc;
+ }
+}
+
+/** Setup the input buffer state to scan directly from a user-specified character buffer.
+ * @param base the character buffer
+ * @param size the size in bytes of the character buffer
+ *
+ * @return the newly allocated buffer state object.
+ */
+YY_BUFFER_STATE yy_scan_buffer (char * base, yy_size_t size )
+{
+ YY_BUFFER_STATE b;
+
+ if ( size < 2 ||
+ base[size-2] != YY_END_OF_BUFFER_CHAR ||
+ base[size-1] != YY_END_OF_BUFFER_CHAR )
+ /* They forgot to leave room for the EOB's. */
+ return NULL;
+
+ b = (YY_BUFFER_STATE) yyalloc( sizeof( struct yy_buffer_state ) );
+ if ( ! b )
+ YY_FATAL_ERROR( "out of dynamic memory in yy_scan_buffer()" );
+
+ b->yy_buf_size = (int) (size - 2); /* "- 2" to take care of EOB's */
+ b->yy_buf_pos = b->yy_ch_buf = base;
+ b->yy_is_our_buffer = 0;
+ b->yy_input_file = NULL;
+ b->yy_n_chars = b->yy_buf_size;
+ b->yy_is_interactive = 0;
+ b->yy_at_bol = 1;
+ b->yy_fill_buffer = 0;
+ b->yy_buffer_status = YY_BUFFER_NEW;
+
+ yy_switch_to_buffer( b );
+
+ return b;
+}
+
+/** Setup the input buffer state to scan a string. The next call to yylex() will
+ * scan from a @e copy of @a str.
+ * @param yystr a NUL-terminated string to scan
+ *
+ * @return the newly allocated buffer state object.
+ * @note If you want to scan bytes that may contain NUL values, then use
+ * yy_scan_bytes() instead.
+ */
+YY_BUFFER_STATE yy_scan_string (const char * yystr )
+{
+
+ return yy_scan_bytes( yystr, (int) strlen(yystr) );
+}
+
+/** Setup the input buffer state to scan the given bytes. The next call to yylex() will
+ * scan from a @e copy of @a bytes.
+ * @param yybytes the byte buffer to scan
+ * @param _yybytes_len the number of bytes in the buffer pointed to by @a bytes.
+ *
+ * @return the newly allocated buffer state object.
+ */
+YY_BUFFER_STATE yy_scan_bytes (const char * yybytes, int _yybytes_len )
+{
+ YY_BUFFER_STATE b;
+ char *buf;
+ yy_size_t n;
+ int i;
+
+ /* Get memory for full buffer, including space for trailing EOB's. */
+ n = (yy_size_t) (_yybytes_len + 2);
+ buf = (char *) yyalloc( n );
+ if ( ! buf )
+ YY_FATAL_ERROR( "out of dynamic memory in yy_scan_bytes()" );
+
+ for ( i = 0; i < _yybytes_len; ++i )
+ buf[i] = yybytes[i];
+
+ buf[_yybytes_len] = buf[_yybytes_len+1] = YY_END_OF_BUFFER_CHAR;
+
+ b = yy_scan_buffer( buf, n );
+ if ( ! b )
+ YY_FATAL_ERROR( "bad buffer in yy_scan_bytes()" );
+
+ /* It's okay to grow etc. this buffer, and we should throw it
+ * away when we're done.
+ */
+ b->yy_is_our_buffer = 1;
+
+ return b;
+}
+
+#ifndef YY_EXIT_FAILURE
+#define YY_EXIT_FAILURE 2
+#endif
+
+static void yynoreturn yy_fatal_error (const char* msg )
+{
+ fprintf( stderr, "%s\n", msg );
+ exit( YY_EXIT_FAILURE );
+}
+
+/* Redefine yyless() so it works in section 3 code. */
+
+#undef yyless
+#define yyless(n) \
+ do \
+ { \
+ /* Undo effects of setting up yytext. */ \
+ int yyless_macro_arg = (n); \
+ YY_LESS_LINENO(yyless_macro_arg);\
+ yytext[yyleng] = (yy_hold_char); \
+ (yy_c_buf_p) = yytext + yyless_macro_arg; \
+ (yy_hold_char) = *(yy_c_buf_p); \
+ *(yy_c_buf_p) = '\0'; \
+ yyleng = yyless_macro_arg; \
+ } \
+ while ( 0 )
+
+/* Accessor methods (get/set functions) to struct members. */
+
+/** Get the current line number.
+ *
+ */
+int yyget_lineno (void)
+{
+
+ return yylineno;
+}
+
+/** Get the input stream.
+ *
+ */
+FILE *yyget_in (void)
+{
+ return yyin;
+}
+
+/** Get the output stream.
+ *
+ */
+FILE *yyget_out (void)
+{
+ return yyout;
+}
+
+/** Get the length of the current token.
+ *
+ */
+int yyget_leng (void)
+{
+ return yyleng;
+}
+
+/** Get the current token.
+ *
+ */
+
+char *yyget_text (void)
+{
+ return yytext;
+}
+
+/** Set the current line number.
+ * @param _line_number line number
+ *
+ */
+void yyset_lineno (int _line_number )
+{
+
+ yylineno = _line_number;
+}
+
+/** Set the input stream. This does not discard the current
+ * input buffer.
+ * @param _in_str A readable stream.
+ *
+ * @see yy_switch_to_buffer
+ */
+void yyset_in (FILE * _in_str )
+{
+ yyin = _in_str ;
+}
+
+void yyset_out (FILE * _out_str )
+{
+ yyout = _out_str ;
+}
+
+int yyget_debug (void)
+{
+ return yy_flex_debug;
+}
+
+void yyset_debug (int _bdebug )
+{
+ yy_flex_debug = _bdebug ;
+}
+
+static int yy_init_globals (void)
+{
+ /* Initialization is the same as for the non-reentrant scanner.
+ * This function is called from yylex_destroy(), so don't allocate here.
+ */
+
+ (yy_buffer_stack) = NULL;
+ (yy_buffer_stack_top) = 0;
+ (yy_buffer_stack_max) = 0;
+ (yy_c_buf_p) = NULL;
+ (yy_init) = 0;
+ (yy_start) = 0;
+
+/* Defined in main.c */
+#ifdef YY_STDINIT
+ yyin = stdin;
+ yyout = stdout;
+#else
+ yyin = NULL;
+ yyout = NULL;
+#endif
+
+ /* For future reference: Set errno on error, since we are called by
+ * yylex_init()
+ */
+ return 0;
+}
+
+/* yylex_destroy is for both reentrant and non-reentrant scanners. */
+int yylex_destroy (void)
+{
+
+ /* Pop the buffer stack, destroying each element. */
+ while(YY_CURRENT_BUFFER){
+ yy_delete_buffer( YY_CURRENT_BUFFER );
+ YY_CURRENT_BUFFER_LVALUE = NULL;
+ yypop_buffer_state();
+ }
+
+ /* Destroy the stack itself. */
+ yyfree((yy_buffer_stack) );
+ (yy_buffer_stack) = NULL;
+
+ /* Reset the globals. This is important in a non-reentrant scanner so the next time
+ * yylex() is called, initialization will occur. */
+ yy_init_globals( );
+
+ return 0;
+}
+
+/*
+ * Internal utility routines.
+ */
+
+#ifndef yytext_ptr
+static void yy_flex_strncpy (char* s1, const char * s2, int n )
+{
+
+ int i;
+ for ( i = 0; i < n; ++i )
+ s1[i] = s2[i];
+}
+#endif
+
+#ifdef YY_NEED_STRLEN
+static int yy_flex_strlen (const char * s )
+{
+ int n;
+ for ( n = 0; s[n]; ++n )
+ ;
+
+ return n;
+}
+#endif
+
+void *yyalloc (yy_size_t size )
+{
+ return malloc(size);
+}
+
+void *yyrealloc (void * ptr, yy_size_t size )
+{
+
+ /* The cast to (char *) in the following accommodates both
+ * implementations that use char* generic pointers, and those
+ * that use void* generic pointers. It works with the latter
+ * because both ANSI C and C++ allow castless assignment from
+ * any pointer type to void*, and deal with argument conversions
+ * as though doing an assignment.
+ */
+ return realloc(ptr, size);
+}
+
+void yyfree (void * ptr )
+{
+ free( (char *) ptr ); /* see yyrealloc() for (char *) cast */
+}
+
+#define YYTABLES_NAME "yytables"
+
+#line 309 "config-lexer.l"
+
+
+static void
+conf_include(void)
+{
+ char *p = NULL;
+ char filenamebuf[512];
+
+ if ((p = strchr(yytext, '<')) == NULL)
+ *strchr(p = strchr(yytext, '"') + 1, '"') = '\0';
+ else
+ *strchr(++p, '>') = '\0';
+
+ /* do stacking and co. */
+ if (include_stack_ptr >= MAX_INCLUDE_DEPTH)
+ {
+ log_printf("CONFIG -> Includes nested too deep in %s", p);
+ return;
+ }
+
+ if (*p == '/') /* if it is an absolute path */
+ snprintf(filenamebuf, sizeof(filenamebuf), "%s", p);
+ else
+ snprintf(filenamebuf, sizeof(filenamebuf), "%s/%s", HOPM_ETCDIR, p);
+
+ FILE *tmp_fbfile_in = fopen(filenamebuf, "r");
+ if (!tmp_fbfile_in)
+ {
+ log_printf("CONFIG -> Unable to read configuration file '%s': %s",
+ filenamebuf, strerror(errno));
+ return;
+ }
+
+ struct included_file *file = &include_stack[include_stack_ptr++];
+ file->lineno = lineno;
+ file->file = conf_file;
+ file->state = YY_CURRENT_BUFFER;
+ strlcpy(file->conffile, conffilebuf, sizeof(file->conffile));
+
+ lineno = 1;
+ conf_file = tmp_fbfile_in;
+ strlcpy(conffilebuf, filenamebuf, sizeof(conffilebuf));
+
+ yy_switch_to_buffer(yy_create_buffer(NULL, YY_BUF_SIZE));
+}
+
+static int
+conf_eof(void)
+{
+ if (include_stack_ptr == 0)
+ return 1;
+
+ /* switch buffer */
+ struct included_file *file = &include_stack[--include_stack_ptr];
+
+ /* close current file */
+ fclose(conf_file);
+
+ /* switch buffers */
+ yy_delete_buffer(YY_CURRENT_BUFFER);
+ yy_switch_to_buffer(file->state);
+
+ /* switch lineno */
+ lineno = file->lineno;
+
+ /* switch file */
+ conf_file = file->file;
+
+ strlcpy(conffilebuf, file->conffile, sizeof(conffilebuf));
+ return 0;
+}
+
diff --git a/src/config-lexer.l b/src/config-lexer.l
new file mode 100644
index 0000000..bea9365
--- /dev/null
+++ b/src/config-lexer.l
@@ -0,0 +1,379 @@
+/*
+ * Copyright (c) 2002 Erik Fears
+ * Copyright (c) 2014-2018 ircd-hybrid 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 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
+ * USA
+ */
+
+%option case-insensitive
+%option noyywrap
+%option noinput
+%option nounput
+%option never-interactive
+
+%x IN_COMMENT
+
+%{
+#include <stdio.h>
+#include <string.h>
+
+#include "compat.h"
+#include "config.h"
+#include "config-parser.h" /* autogenerated header file */
+#include "log.h"
+
+/* libopm includes */
+#include "libopm/src/opm_types.h"
+
+#undef YY_FATAL_ERROR
+#define YY_FATAL_ERROR(msg) conf_yy_fatal_error(msg)
+
+#undef YY_INPUT
+#define YY_INPUT(buf,result,max_size) \
+ if (!(result = conf_yy_input(buf, max_size))) \
+ YY_FATAL_ERROR("input in flex scanner failed");
+#define MAX_INCLUDE_DEPTH 10
+
+
+unsigned int lineno = 1;
+char linebuf[512];
+char conffilebuf[512];
+
+static struct included_file
+{
+ YY_BUFFER_STATE state;
+ unsigned int lineno;
+ FILE *file;
+ char conffile[512];
+} include_stack[MAX_INCLUDE_DEPTH];
+
+static unsigned int include_stack_ptr;
+
+
+static void conf_include(void);
+static int conf_eof(void);
+
+static int
+conf_yy_input(char *lbuf, unsigned int max_size)
+{
+ return fgets(lbuf, max_size, conf_file) == NULL ? 0 : strlen(lbuf);
+}
+
+static int
+conf_yy_fatal_error(const char *msg)
+{
+ return 0;
+}
+%}
+
+WS [[:blank:]]*
+DIGIT [[:digit:]]+
+COMMENT ("//"|"#").*
+qstring \"[^\"\n]*[\"\n]
+include \.include{WS}(\<.*\>|\".*\")
+
+%%
+
+"/*" { BEGIN IN_COMMENT; }
+<IN_COMMENT>"*/" { BEGIN INITIAL; }
+<IN_COMMENT>. ; /* Eat everything but a newline */
+<IN_COMMENT>\n { ++lineno; }
+<IN_COMMENT><<EOF>> { BEGIN INITIAL; if (conf_eof()) yyterminate(); }
+
+{include} { conf_include(); }
+\n.* { strlcpy(linebuf, yytext + 1, sizeof(linebuf)); ++lineno; yyless(1); }
+{WS} ;
+{COMMENT} ;
+{DIGIT} { yylval.number = atoi(yytext); return NUMBER; }
+{qstring} { if (yytext[yyleng - 2] == '\\')
+ {
+ yyless(yyleng - 1); /* Return last quote */
+ yymore(); /* Append next string */
+ }
+ else
+ {
+ yylval.string = yytext + 1;
+
+ if (yylval.string[yyleng - 2] != '"')
+ log_printf("CONFIG ->Unterminated character string");
+ else
+ {
+ unsigned int i = 0, j = 0;
+
+ yylval.string[yyleng - 2] = '\0'; /* Remove close quote */
+
+ for (; yylval.string[i] != '\0'; ++i, ++j)
+ {
+ if (yylval.string[i] != '\\')
+ yylval.string[j] = yylval.string[i];
+ else
+ {
+ ++i;
+
+ if (yylval.string[i] == '\0') /* XXX: should not happen */
+ {
+ log_printf("CONFIG -> Unterminated character string");
+ break;
+ }
+
+ yylval.string[j] = yylval.string[i];
+ }
+ }
+
+ yylval.string[j] = '\0';
+ return STRING;
+ }
+ }
+ }
+
+ADDRESS_FAMILY { return ADDRESS_FAMILY; }
+AWAY { return AWAY; }
+BAN_UNKNOWN { return BAN_UNKNOWN; }
+BLACKLIST { return BLACKLIST; }
+CHANNEL { return CHANNEL; }
+COMMAND_INTERVAL { return COMMAND_INTERVAL; }
+COMMAND_QUEUE_SIZE { return COMMAND_QUEUE_SIZE; }
+COMMAND_TIMEOUT { return COMMAND_TIMEOUT; }
+CONNREGEX { return CONNREGEX; }
+DNS_FDLIMIT { return DNS_FDLIMIT; }
+DNS_TIMEOUT { return DNS_TIMEOUT; }
+DNSBL_FROM { return DNSBL_FROM; }
+DNSBL_TO { return DNSBL_TO; }
+EXEMPT { return EXEMPT; }
+FD { return FD; }
+INVITE { return INVITE; }
+IPV4 { return IPV4; }
+IPV6 { return IPV6; }
+IRC { return IRC; }
+KLINE { return KLINE; }
+KEY { return KEY; }
+MASK { return MASK; }
+MAX_READ { return MAX_READ; }
+MODE { return MODE; }
+NAME { return NAME; }
+NEGCACHE { return NEGCACHE; }
+NEGCACHE_REBUILD { return NEGCACHE_REBUILD; }
+NICK { return NICK; }
+NICKSERV { return NICKSERV; }
+NOTICE { return NOTICE; }
+OPER { return OPER; }
+OPM { return OPM; }
+OPTIONS { return OPTIONS; }
+PASSWORD { return PASSWORD; }
+PERFORM { return PERFORM; }
+PIDFILE { return PIDFILE; }
+PORT { return PORT; }
+PROTOCOL { return PROTOCOL; }
+READTIMEOUT { return READTIMEOUT; }
+REALNAME { return REALNAME; }
+RECONNECTINTERVAL { return RECONNECTINTERVAL; }
+REPLY { return REPLY; }
+SCANLOG { return SCANLOG; }
+SCANNER { return SCANNER; }
+SENDMAIL { return SENDMAIL; }
+SERVER { return SERVER; }
+TARGET_IP { return TARGET_IP; }
+TARGET_PORT { return TARGET_PORT; }
+TARGET_STRING { return TARGET_STRING;}
+TIMEOUT { return TIMEOUT; }
+TYPE { return TYPE; }
+USER { return USER; }
+USERNAME { return USERNAME; }
+VHOST { return VHOST; }
+
+years { return YEARS; }
+year { return YEARS; }
+months { return MONTHS; }
+month { return MONTHS; }
+weeks { return WEEKS; }
+week { return WEEKS; }
+days { return DAYS; }
+day { return DAYS; }
+hours { return HOURS; }
+hour { return HOURS; }
+minutes { return MINUTES; }
+minute { return MINUTES; }
+seconds { return SECONDS; }
+second { return SECONDS; }
+
+bytes { return BYTES; }
+byte { return BYTES; }
+kilobytes { return KBYTES; }
+kilobyte { return KBYTES; }
+kbytes { return KBYTES; }
+kbyte { return KBYTES; }
+kb { return KBYTES; }
+megabytes { return MBYTES; }
+megabyte { return MBYTES; }
+mbytes { return MBYTES; }
+mbyte { return MBYTES; }
+mb { return MBYTES; }
+
+HTTP {
+ yylval.number = OPM_TYPE_HTTP;
+ return PROTOCOLTYPE;
+ }
+
+HTTPPOST {
+ yylval.number = OPM_TYPE_HTTPPOST;
+ return PROTOCOLTYPE;
+ }
+
+HTTPS {
+ yylval.number = OPM_TYPE_HTTPS;
+ return PROTOCOLTYPE;
+ }
+
+HTTPSPOST {
+ yylval.number = OPM_TYPE_HTTPSPOST;
+ return PROTOCOLTYPE;
+ }
+
+SOCKS4 {
+ yylval.number = OPM_TYPE_SOCKS4;
+ return PROTOCOLTYPE;
+ }
+
+SOCKS5 {
+ yylval.number = OPM_TYPE_SOCKS5;
+ return PROTOCOLTYPE;
+ }
+
+WINGATE {
+ yylval.number = OPM_TYPE_WINGATE;
+ return PROTOCOLTYPE;
+ }
+
+ROUTER {
+ yylval.number = OPM_TYPE_ROUTER;
+ return PROTOCOLTYPE;
+ }
+
+DREAMBOX {
+ yylval.number = OPM_TYPE_DREAMBOX;
+ return PROTOCOLTYPE;
+ }
+
+
+SSH {
+ yylval.number = OPM_TYPE_SSH;
+ return PROTOCOLTYPE;
+ }
+
+TRUE {
+ yylval.number=1;
+ return NUMBER;
+ }
+YES {
+ yylval.number=1;
+ return NUMBER;
+ }
+ON {
+ yylval.number=1;
+ return NUMBER;
+ }
+
+
+
+FALSE {
+ yylval.number=0;
+ return NUMBER;
+ }
+
+NO {
+ yylval.number=0;
+ return NUMBER;
+ }
+
+OFF {
+ yylval.number=0;
+ return NUMBER;
+ }
+
+. { return yytext[0]; }
+<<EOF>> { if (conf_eof()) yyterminate(); }
+
+%%
+
+static void
+conf_include(void)
+{
+ char *p = NULL;
+ char filenamebuf[512];
+
+ if ((p = strchr(yytext, '<')) == NULL)
+ *strchr(p = strchr(yytext, '"') + 1, '"') = '\0';
+ else
+ *strchr(++p, '>') = '\0';
+
+ /* do stacking and co. */
+ if (include_stack_ptr >= MAX_INCLUDE_DEPTH)
+ {
+ log_printf("CONFIG -> Includes nested too deep in %s", p);
+ return;
+ }
+
+ if (*p == '/') /* if it is an absolute path */
+ snprintf(filenamebuf, sizeof(filenamebuf), "%s", p);
+ else
+ snprintf(filenamebuf, sizeof(filenamebuf), "%s/%s", HOPM_ETCDIR, p);
+
+ FILE *tmp_fbfile_in = fopen(filenamebuf, "r");
+ if (!tmp_fbfile_in)
+ {
+ log_printf("CONFIG -> Unable to read configuration file '%s': %s",
+ filenamebuf, strerror(errno));
+ return;
+ }
+
+ struct included_file *file = &include_stack[include_stack_ptr++];
+ file->lineno = lineno;
+ file->file = conf_file;
+ file->state = YY_CURRENT_BUFFER;
+ strlcpy(file->conffile, conffilebuf, sizeof(file->conffile));
+
+ lineno = 1;
+ conf_file = tmp_fbfile_in;
+ strlcpy(conffilebuf, filenamebuf, sizeof(conffilebuf));
+
+ yy_switch_to_buffer(yy_create_buffer(NULL, YY_BUF_SIZE));
+}
+
+static int
+conf_eof(void)
+{
+ if (include_stack_ptr == 0)
+ return 1;
+
+ /* switch buffer */
+ struct included_file *file = &include_stack[--include_stack_ptr];
+
+ /* close current file */
+ fclose(conf_file);
+
+ /* switch buffers */
+ yy_delete_buffer(YY_CURRENT_BUFFER);
+ yy_switch_to_buffer(file->state);
+
+ /* switch lineno */
+ lineno = file->lineno;
+
+ /* switch file */
+ conf_file = file->file;
+
+ strlcpy(conffilebuf, file->conffile, sizeof(conffilebuf));
+ return 0;
+}
diff --git a/src/config-parser.c b/src/config-parser.c
new file mode 100644
index 0000000..94a8c31
--- /dev/null
+++ b/src/config-parser.c
@@ -0,0 +1,2538 @@
+/* A Bison parser, made by GNU Bison 3.0.4. */
+
+/* Bison implementation for Yacc-like parsers in C
+
+ Copyright (C) 1984, 1989-1990, 2000-2015 Free Software Foundation, Inc.
+
+ 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 3 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, see <http://www.gnu.org/licenses/>. */
+
+/* As a special exception, you may create a larger work that contains
+ part or all of the Bison parser skeleton and distribute that work
+ under terms of your choice, so long as that work isn't itself a
+ parser generator using the skeleton or a modified version thereof
+ as a parser skeleton. Alternatively, if you modify or redistribute
+ the parser skeleton itself, you may (at your option) remove this
+ special exception, which will cause the skeleton and the resulting
+ Bison output files to be licensed under the GNU General Public
+ License without this special exception.
+
+ This special exception was added by the Free Software Foundation in
+ version 2.2 of Bison. */
+
+/* C LALR(1) parser skeleton written by Richard Stallman, by
+ simplifying the original so-called "semantic" parser. */
+
+/* All symbols defined below should begin with yy or YY, to avoid
+ infringing on user name space. This should be done even for local
+ variables, as they might otherwise be expanded by user macros.
+ There are some unavoidable exceptions within include files to
+ define necessary library symbols; they are noted "INFRINGES ON
+ USER NAME SPACE" below. */
+
+/* Identify Bison output. */
+#define YYBISON 1
+
+/* Bison version. */
+#define YYBISON_VERSION "3.0.4"
+
+/* Skeleton name. */
+#define YYSKELETON_NAME "yacc.c"
+
+/* Pure parsers. */
+#define YYPURE 0
+
+/* Push parsers. */
+#define YYPUSH 0
+
+/* Pull parsers. */
+#define YYPULL 1
+
+
+
+
+/* Copy the first part of user declarations. */
+#line 21 "config-parser.y" /* yacc.c:339 */
+
+#include <string.h>
+
+#include "memory.h"
+#include "config.h"
+
+int yylex(void);
+
+static void *tmp; /* Variable to temporarily hold nodes before insertion to list */
+
+
+#line 78 "config-parser.c" /* yacc.c:339 */
+
+# ifndef YY_NULLPTR
+# if defined __cplusplus && 201103L <= __cplusplus
+# define YY_NULLPTR nullptr
+# else
+# define YY_NULLPTR 0
+# endif
+# endif
+
+/* Enabling verbose error messages. */
+#ifdef YYERROR_VERBOSE
+# undef YYERROR_VERBOSE
+# define YYERROR_VERBOSE 1
+#else
+# define YYERROR_VERBOSE 0
+#endif
+
+/* In a future release of Bison, this section will be replaced
+ by #include "y.tab.h". */
+#ifndef YY_YY_CONFIG_PARSER_H_INCLUDED
+# define YY_YY_CONFIG_PARSER_H_INCLUDED
+/* Debug traces. */
+#ifndef YYDEBUG
+# define YYDEBUG 0
+#endif
+#if YYDEBUG
+extern int yydebug;
+#endif
+
+/* Token type. */
+#ifndef YYTOKENTYPE
+# define YYTOKENTYPE
+ enum yytokentype
+ {
+ ADDRESS_FAMILY = 258,
+ AWAY = 259,
+ BAN_UNKNOWN = 260,
+ BLACKLIST = 261,
+ BYTES = 262,
+ KBYTES = 263,
+ MBYTES = 264,
+ CHANNEL = 265,
+ COMMAND_INTERVAL = 266,
+ COMMAND_QUEUE_SIZE = 267,
+ COMMAND_TIMEOUT = 268,
+ CONNREGEX = 269,
+ DNS_FDLIMIT = 270,
+ DNS_TIMEOUT = 271,
+ DNSBL_FROM = 272,
+ DNSBL_TO = 273,
+ EXEMPT = 274,
+ FD = 275,
+ INVITE = 276,
+ IPV4 = 277,
+ IPV6 = 278,
+ IRC = 279,
+ KLINE = 280,
+ KEY = 281,
+ MASK = 282,
+ MAX_READ = 283,
+ MODE = 284,
+ NAME = 285,
+ NEGCACHE = 286,
+ NEGCACHE_REBUILD = 287,
+ NICK = 288,
+ NICKSERV = 289,
+ NOTICE = 290,
+ OPER = 291,
+ OPM = 292,
+ OPTIONS = 293,
+ PASSWORD = 294,
+ PERFORM = 295,
+ PIDFILE = 296,
+ PORT = 297,
+ PROTOCOL = 298,
+ READTIMEOUT = 299,
+ REALNAME = 300,
+ RECONNECTINTERVAL = 301,
+ REPLY = 302,
+ SCANLOG = 303,
+ SCANNER = 304,
+ SECONDS = 305,
+ MINUTES = 306,
+ HOURS = 307,
+ DAYS = 308,
+ WEEKS = 309,
+ MONTHS = 310,
+ YEARS = 311,
+ SENDMAIL = 312,
+ SERVER = 313,
+ TARGET_IP = 314,
+ TARGET_PORT = 315,
+ TARGET_STRING = 316,
+ TIMEOUT = 317,
+ TYPE = 318,
+ USERNAME = 319,
+ USER = 320,
+ VHOST = 321,
+ NUMBER = 322,
+ STRING = 323,
+ PROTOCOLTYPE = 324
+ };
+#endif
+/* Tokens. */
+#define ADDRESS_FAMILY 258
+#define AWAY 259
+#define BAN_UNKNOWN 260
+#define BLACKLIST 261
+#define BYTES 262
+#define KBYTES 263
+#define MBYTES 264
+#define CHANNEL 265
+#define COMMAND_INTERVAL 266
+#define COMMAND_QUEUE_SIZE 267
+#define COMMAND_TIMEOUT 268
+#define CONNREGEX 269
+#define DNS_FDLIMIT 270
+#define DNS_TIMEOUT 271
+#define DNSBL_FROM 272
+#define DNSBL_TO 273
+#define EXEMPT 274
+#define FD 275
+#define INVITE 276
+#define IPV4 277
+#define IPV6 278
+#define IRC 279
+#define KLINE 280
+#define KEY 281
+#define MASK 282
+#define MAX_READ 283
+#define MODE 284
+#define NAME 285
+#define NEGCACHE 286
+#define NEGCACHE_REBUILD 287
+#define NICK 288
+#define NICKSERV 289
+#define NOTICE 290
+#define OPER 291
+#define OPM 292
+#define OPTIONS 293
+#define PASSWORD 294
+#define PERFORM 295
+#define PIDFILE 296
+#define PORT 297
+#define PROTOCOL 298
+#define READTIMEOUT 299
+#define REALNAME 300
+#define RECONNECTINTERVAL 301
+#define REPLY 302
+#define SCANLOG 303
+#define SCANNER 304
+#define SECONDS 305
+#define MINUTES 306
+#define HOURS 307
+#define DAYS 308
+#define WEEKS 309
+#define MONTHS 310
+#define YEARS 311
+#define SENDMAIL 312
+#define SERVER 313
+#define TARGET_IP 314
+#define TARGET_PORT 315
+#define TARGET_STRING 316
+#define TIMEOUT 317
+#define TYPE 318
+#define USERNAME 319
+#define USER 320
+#define VHOST 321
+#define NUMBER 322
+#define STRING 323
+#define PROTOCOLTYPE 324
+
+/* Value type. */
+#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
+
+union YYSTYPE
+{
+#line 91 "config-parser.y" /* yacc.c:355 */
+
+ int number;
+ char *string;
+
+#line 261 "config-parser.c" /* yacc.c:355 */
+};
+
+typedef union YYSTYPE YYSTYPE;
+# define YYSTYPE_IS_TRIVIAL 1
+# define YYSTYPE_IS_DECLARED 1
+#endif
+
+
+extern YYSTYPE yylval;
+
+int yyparse (void);
+
+#endif /* !YY_YY_CONFIG_PARSER_H_INCLUDED */
+
+/* Copy the second part of user declarations. */
+
+#line 278 "config-parser.c" /* yacc.c:358 */
+
+#ifdef short
+# undef short
+#endif
+
+#ifdef YYTYPE_UINT8
+typedef YYTYPE_UINT8 yytype_uint8;
+#else
+typedef unsigned char yytype_uint8;
+#endif
+
+#ifdef YYTYPE_INT8
+typedef YYTYPE_INT8 yytype_int8;
+#else
+typedef signed char yytype_int8;
+#endif
+
+#ifdef YYTYPE_UINT16
+typedef YYTYPE_UINT16 yytype_uint16;
+#else
+typedef unsigned short int yytype_uint16;
+#endif
+
+#ifdef YYTYPE_INT16
+typedef YYTYPE_INT16 yytype_int16;
+#else
+typedef short int yytype_int16;
+#endif
+
+#ifndef YYSIZE_T
+# ifdef __SIZE_TYPE__
+# define YYSIZE_T __SIZE_TYPE__
+# elif defined size_t
+# define YYSIZE_T size_t
+# elif ! defined YYSIZE_T
+# include <stddef.h> /* INFRINGES ON USER NAME SPACE */
+# define YYSIZE_T size_t
+# else
+# define YYSIZE_T unsigned int
+# endif
+#endif
+
+#define YYSIZE_MAXIMUM ((YYSIZE_T) -1)
+
+#ifndef YY_
+# if defined YYENABLE_NLS && YYENABLE_NLS
+# if ENABLE_NLS
+# include <libintl.h> /* INFRINGES ON USER NAME SPACE */
+# define YY_(Msgid) dgettext ("bison-runtime", Msgid)
+# endif
+# endif
+# ifndef YY_
+# define YY_(Msgid) Msgid
+# endif
+#endif
+
+#ifndef YY_ATTRIBUTE
+# if (defined __GNUC__ \
+ && (2 < __GNUC__ || (__GNUC__ == 2 && 96 <= __GNUC_MINOR__))) \
+ || defined __SUNPRO_C && 0x5110 <= __SUNPRO_C
+# define YY_ATTRIBUTE(Spec) __attribute__(Spec)
+# else
+# define YY_ATTRIBUTE(Spec) /* empty */
+# endif
+#endif
+
+#ifndef YY_ATTRIBUTE_PURE
+# define YY_ATTRIBUTE_PURE YY_ATTRIBUTE ((__pure__))
+#endif
+
+#ifndef YY_ATTRIBUTE_UNUSED
+# define YY_ATTRIBUTE_UNUSED YY_ATTRIBUTE ((__unused__))
+#endif
+
+#if !defined _Noreturn \
+ && (!defined __STDC_VERSION__ || __STDC_VERSION__ < 201112)
+# if defined _MSC_VER && 1200 <= _MSC_VER
+# define _Noreturn __declspec (noreturn)
+# else
+# define _Noreturn YY_ATTRIBUTE ((__noreturn__))
+# endif
+#endif
+
+/* Suppress unused-variable warnings by "using" E. */
+#if ! defined lint || defined __GNUC__
+# define YYUSE(E) ((void) (E))
+#else
+# define YYUSE(E) /* empty */
+#endif
+
+#if defined __GNUC__ && 407 <= __GNUC__ * 100 + __GNUC_MINOR__
+/* Suppress an incorrect diagnostic about yylval being uninitialized. */
+# define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN \
+ _Pragma ("GCC diagnostic push") \
+ _Pragma ("GCC diagnostic ignored \"-Wuninitialized\"")\
+ _Pragma ("GCC diagnostic ignored \"-Wmaybe-uninitialized\"")
+# define YY_IGNORE_MAYBE_UNINITIALIZED_END \
+ _Pragma ("GCC diagnostic pop")
+#else
+# define YY_INITIAL_VALUE(Value) Value
+#endif
+#ifndef YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
+# define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
+# define YY_IGNORE_MAYBE_UNINITIALIZED_END
+#endif
+#ifndef YY_INITIAL_VALUE
+# define YY_INITIAL_VALUE(Value) /* Nothing. */
+#endif
+
+
+#if ! defined yyoverflow || YYERROR_VERBOSE
+
+/* The parser invokes alloca or malloc; define the necessary symbols. */
+
+# ifdef YYSTACK_USE_ALLOCA
+# if YYSTACK_USE_ALLOCA
+# ifdef __GNUC__
+# define YYSTACK_ALLOC __builtin_alloca
+# elif defined __BUILTIN_VA_ARG_INCR
+# include <alloca.h> /* INFRINGES ON USER NAME SPACE */
+# elif defined _AIX
+# define YYSTACK_ALLOC __alloca
+# elif defined _MSC_VER
+# include <malloc.h> /* INFRINGES ON USER NAME SPACE */
+# define alloca _alloca
+# else
+# define YYSTACK_ALLOC alloca
+# if ! defined _ALLOCA_H && ! defined EXIT_SUCCESS
+# include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
+ /* Use EXIT_SUCCESS as a witness for stdlib.h. */
+# ifndef EXIT_SUCCESS
+# define EXIT_SUCCESS 0
+# endif
+# endif
+# endif
+# endif
+# endif
+
+# ifdef YYSTACK_ALLOC
+ /* Pacify GCC's 'empty if-body' warning. */
+# define YYSTACK_FREE(Ptr) do { /* empty */; } while (0)
+# ifndef YYSTACK_ALLOC_MAXIMUM
+ /* The OS might guarantee only one guard page at the bottom of the stack,
+ and a page size can be as small as 4096 bytes. So we cannot safely
+ invoke alloca (N) if N exceeds 4096. Use a slightly smaller number
+ to allow for a few compiler-allocated temporary stack slots. */
+# define YYSTACK_ALLOC_MAXIMUM 4032 /* reasonable circa 2006 */
+# endif
+# else
+# define YYSTACK_ALLOC YYMALLOC
+# define YYSTACK_FREE YYFREE
+# ifndef YYSTACK_ALLOC_MAXIMUM
+# define YYSTACK_ALLOC_MAXIMUM YYSIZE_MAXIMUM
+# endif
+# if (defined __cplusplus && ! defined EXIT_SUCCESS \
+ && ! ((defined YYMALLOC || defined malloc) \
+ && (defined YYFREE || defined free)))
+# include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
+# ifndef EXIT_SUCCESS
+# define EXIT_SUCCESS 0
+# endif
+# endif
+# ifndef YYMALLOC
+# define YYMALLOC malloc
+# if ! defined malloc && ! defined EXIT_SUCCESS
+void *malloc (YYSIZE_T); /* INFRINGES ON USER NAME SPACE */
+# endif
+# endif
+# ifndef YYFREE
+# define YYFREE free
+# if ! defined free && ! defined EXIT_SUCCESS
+void free (void *); /* INFRINGES ON USER NAME SPACE */
+# endif
+# endif
+# endif
+#endif /* ! defined yyoverflow || YYERROR_VERBOSE */
+
+
+#if (! defined yyoverflow \
+ && (! defined __cplusplus \
+ || (defined YYSTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL)))
+
+/* A type that is properly aligned for any stack member. */
+union yyalloc
+{
+ yytype_int16 yyss_alloc;
+ YYSTYPE yyvs_alloc;
+};
+
+/* The size of the maximum gap between one aligned stack and the next. */
+# define YYSTACK_GAP_MAXIMUM (sizeof (union yyalloc) - 1)
+
+/* The size of an array large to enough to hold all stacks, each with
+ N elements. */
+# define YYSTACK_BYTES(N) \
+ ((N) * (sizeof (yytype_int16) + sizeof (YYSTYPE)) \
+ + YYSTACK_GAP_MAXIMUM)
+
+# define YYCOPY_NEEDED 1
+
+/* Relocate STACK from its old location to the new one. The
+ local variables YYSIZE and YYSTACKSIZE give the old and new number of
+ elements in the stack, and YYPTR gives the new location of the
+ stack. Advance YYPTR to a properly aligned location for the next
+ stack. */
+# define YYSTACK_RELOCATE(Stack_alloc, Stack) \
+ do \
+ { \
+ YYSIZE_T yynewbytes; \
+ YYCOPY (&yyptr->Stack_alloc, Stack, yysize); \
+ Stack = &yyptr->Stack_alloc; \
+ yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \
+ yyptr += yynewbytes / sizeof (*yyptr); \
+ } \
+ while (0)
+
+#endif
+
+#if defined YYCOPY_NEEDED && YYCOPY_NEEDED
+/* Copy COUNT objects from SRC to DST. The source and destination do
+ not overlap. */
+# ifndef YYCOPY
+# if defined __GNUC__ && 1 < __GNUC__
+# define YYCOPY(Dst, Src, Count) \
+ __builtin_memcpy (Dst, Src, (Count) * sizeof (*(Src)))
+# else
+# define YYCOPY(Dst, Src, Count) \
+ do \
+ { \
+ YYSIZE_T yyi; \
+ for (yyi = 0; yyi < (Count); yyi++) \
+ (Dst)[yyi] = (Src)[yyi]; \
+ } \
+ while (0)
+# endif
+# endif
+#endif /* !YYCOPY_NEEDED */
+
+/* YYFINAL -- State number of the termination state. */
+#define YYFINAL 2
+/* YYLAST -- Last index in YYTABLE. */
+#define YYLAST 346
+
+/* YYNTOKENS -- Number of terminals. */
+#define YYNTOKENS 76
+/* YYNNTS -- Number of nonterminals. */
+#define YYNNTS 90
+/* YYNRULES -- Number of rules. */
+#define YYNRULES 170
+/* YYNSTATES -- Number of states. */
+#define YYNSTATES 370
+
+/* YYTRANSLATE[YYX] -- Symbol number corresponding to YYX as returned
+ by yylex, with out-of-bounds checking. */
+#define YYUNDEFTOK 2
+#define YYMAXUTOK 324
+
+#define YYTRANSLATE(YYX) \
+ ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK)
+
+/* YYTRANSLATE[TOKEN-NUM] -- Symbol number corresponding to TOKEN-NUM
+ as returned by yylex, without out-of-bounds checking. */
+static const yytype_uint8 yytranslate[] =
+{
+ 0, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 75, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 74, 72,
+ 2, 73, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 70, 2, 71, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 1, 2, 3, 4,
+ 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
+ 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
+ 25, 26, 27, 28, 29, 30, 31, 32, 33, 34,
+ 35, 36, 37, 38, 39, 40, 41, 42, 43, 44,
+ 45, 46, 47, 48, 49, 50, 51, 52, 53, 54,
+ 55, 56, 57, 58, 59, 60, 61, 62, 63, 64,
+ 65, 66, 67, 68, 69
+};
+
+#if YYDEBUG
+ /* YYRLINE[YYN] -- Source line where rule number YYN was defined. */
+static const yytype_uint16 yyrline[] =
+{
+ 0, 106, 106, 107, 110, 111, 112, 113, 114, 115,
+ 117, 117, 118, 119, 120, 121, 122, 123, 124, 125,
+ 128, 128, 129, 130, 131, 132, 137, 139, 140, 142,
+ 143, 144, 145, 146, 147, 148, 149, 150, 151, 153,
+ 158, 163, 169, 174, 179, 185, 190, 195, 202, 204,
+ 205, 207, 208, 209, 210, 211, 212, 213, 214, 215,
+ 216, 217, 218, 219, 220, 221, 222, 223, 224, 225,
+ 227, 233, 239, 245, 251, 257, 263, 269, 274, 279,
+ 284, 289, 294, 300, 306, 312, 318, 327, 327, 340,
+ 341, 343, 344, 345, 347, 355, 363, 374, 374, 384,
+ 385, 387, 388, 389, 391, 398, 408, 408, 445, 446,
+ 448, 449, 450, 451, 452, 453, 454, 455, 456, 457,
+ 459, 467, 475, 483, 493, 500, 507, 514, 521, 537,
+ 539, 540, 542, 543, 544, 545, 546, 548, 554, 560,
+ 569, 569, 585, 586, 588, 589, 590, 591, 592, 593,
+ 594, 596, 605, 604, 612, 612, 613, 618, 625, 633,
+ 645, 652, 654, 655, 657, 671, 673, 674, 676, 677,
+ 679
+};
+#endif
+
+#if YYDEBUG || YYERROR_VERBOSE || 0
+/* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM.
+ First, the terminals, then, starting at YYNTOKENS, nonterminals. */
+static const char *const yytname[] =
+{
+ "$end", "error", "$undefined", "ADDRESS_FAMILY", "AWAY", "BAN_UNKNOWN",
+ "BLACKLIST", "BYTES", "KBYTES", "MBYTES", "CHANNEL", "COMMAND_INTERVAL",
+ "COMMAND_QUEUE_SIZE", "COMMAND_TIMEOUT", "CONNREGEX", "DNS_FDLIMIT",
+ "DNS_TIMEOUT", "DNSBL_FROM", "DNSBL_TO", "EXEMPT", "FD", "INVITE",
+ "IPV4", "IPV6", "IRC", "KLINE", "KEY", "MASK", "MAX_READ", "MODE",
+ "NAME", "NEGCACHE", "NEGCACHE_REBUILD", "NICK", "NICKSERV", "NOTICE",
+ "OPER", "OPM", "OPTIONS", "PASSWORD", "PERFORM", "PIDFILE", "PORT",
+ "PROTOCOL", "READTIMEOUT", "REALNAME", "RECONNECTINTERVAL", "REPLY",
+ "SCANLOG", "SCANNER", "SECONDS", "MINUTES", "HOURS", "DAYS", "WEEKS",
+ "MONTHS", "YEARS", "SENDMAIL", "SERVER", "TARGET_IP", "TARGET_PORT",
+ "TARGET_STRING", "TIMEOUT", "TYPE", "USERNAME", "USER", "VHOST",
+ "NUMBER", "STRING", "PROTOCOLTYPE", "'{'", "'}'", "';'", "'='", "':'",
+ "','", "$accept", "config", "config_items", "timespec_", "timespec",
+ "sizespec_", "sizespec", "options_entry", "options_items",
+ "options_item", "options_negcache", "options_negcache_rebuild",
+ "options_pidfile", "options_dns_fdlimit", "options_dns_timeout",
+ "options_scanlog", "options_command_queue_size",
+ "options_command_interval", "options_command_timeout", "irc_entry",
+ "irc_items", "irc_item", "irc_away", "irc_kline", "irc_mode", "irc_nick",
+ "irc_nickserv", "irc_oper", "irc_password", "irc_perform", "irc_notice",
+ "irc_port", "irc_readtimeout", "irc_reconnectinterval", "irc_realname",
+ "irc_server", "irc_username", "irc_vhost", "irc_connregex",
+ "channel_entry", "$@1", "channel_items", "channel_item", "channel_name",
+ "channel_key", "channel_invite", "user_entry", "$@2", "user_items",
+ "user_item", "user_mask", "user_scanner", "scanner_entry", "$@3",
+ "scanner_items", "scanner_item", "scanner_name", "scanner_vhost",
+ "scanner_target_ip", "scanner_target_string", "scanner_fd",
+ "scanner_target_port", "scanner_timeout", "scanner_max_read",
+ "scanner_protocol", "opm_entry", "opm_items", "opm_item",
+ "opm_dnsbl_from", "opm_dnsbl_to", "opm_sendmail", "opm_blacklist_entry",
+ "$@4", "blacklist_items", "blacklist_item", "blacklist_name",
+ "blacklist_address_family", "$@5", "blacklist_address_family_items",
+ "blacklist_address_family_item", "blacklist_kline", "blacklist_type",
+ "blacklist_ban_unknown", "blacklist_reply", "blacklist_reply_items",
+ "blacklist_reply_item", "exempt_entry", "exempt_items", "exempt_item",
+ "exempt_mask", YY_NULLPTR
+};
+#endif
+
+# ifdef YYPRINT
+/* YYTOKNUM[NUM] -- (External) token number corresponding to the
+ (internal) symbol number NUM (which must be that of a token). */
+static const yytype_uint16 yytoknum[] =
+{
+ 0, 256, 257, 258, 259, 260, 261, 262, 263, 264,
+ 265, 266, 267, 268, 269, 270, 271, 272, 273, 274,
+ 275, 276, 277, 278, 279, 280, 281, 282, 283, 284,
+ 285, 286, 287, 288, 289, 290, 291, 292, 293, 294,
+ 295, 296, 297, 298, 299, 300, 301, 302, 303, 304,
+ 305, 306, 307, 308, 309, 310, 311, 312, 313, 314,
+ 315, 316, 317, 318, 319, 320, 321, 322, 323, 324,
+ 123, 125, 59, 61, 58, 44
+};
+# endif
+
+#define YYPACT_NINF -294
+
+#define yypact_value_is_default(Yystate) \
+ (!!((Yystate) == (-294)))
+
+#define YYTABLE_NINF -141
+
+#define yytable_value_is_error(Yytable_value) \
+ 0
+
+ /* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing
+ STATE-NUM. */
+static const yytype_int16 yypact[] =
+{
+ -294, 138, -294, -63, -54, -52, -38, -294, -294, -294,
+ -294, -24, -294, 14, -294, -294, 23, 95, 37, 181,
+ 9, 13, -294, -3, 4, -294, -294, -294, 12, 18,
+ 19, 20, 24, 31, 33, 35, 42, 44, 48, 49,
+ 53, 59, 60, 63, 70, 0, -294, -294, -294, -294,
+ -294, -294, -294, -294, -294, -294, -294, -294, -294, -294,
+ -294, -294, -294, -294, -294, 77, -294, 73, 78, 82,
+ 5, -294, -294, -294, -294, -294, 150, -294, 85, 87,
+ 90, 92, 93, 97, 98, 99, 100, 36, -294, -294,
+ -294, -294, -294, -294, -294, -294, -294, -294, 115, 124,
+ 109, 96, -294, 110, 111, 112, 113, 120, 121, 127,
+ 137, 140, 141, 83, 139, 142, 139, 143, 146, 149,
+ 147, -294, 151, 152, 155, 156, 153, -294, 157, 139,
+ 159, 139, 161, 139, 139, 139, 169, 170, 167, -294,
+ -294, 145, 168, 29, -294, -294, -294, -294, 171, 172,
+ 173, 174, 175, 176, 177, 178, 179, 52, -294, -294,
+ -294, -294, -294, -294, -294, -294, -294, -294, 182, -294,
+ 183, 184, 185, 186, 187, 188, 189, 190, 191, 192,
+ 193, 148, 194, 195, 196, 197, 198, 199, -294, -18,
+ 200, 201, 202, -294, 144, 203, 204, 205, 206, 207,
+ 208, 209, 210, 211, -294, 216, 217, 214, -294, 220,
+ 221, 222, 223, 225, 224, 226, 139, 227, 228, -294,
+ -294, -294, -294, -294, -294, -294, -294, -294, -294, -294,
+ -294, -294, 139, 139, 139, 139, 139, 139, 139, -294,
+ -294, -294, -294, -294, -294, -294, -294, 180, 229, 230,
+ 39, -294, -294, -294, -294, -294, -294, -294, -294, -294,
+ 231, 232, 233, 219, 234, 56, -294, -294, -294, -294,
+ -294, -294, -294, -294, -294, -294, -294, -294, -294, -294,
+ -294, -294, 236, 237, -294, 238, 81, 239, 240, 166,
+ 241, 242, 243, 244, 245, -294, -294, -294, -294, -294,
+ -294, -294, -294, 250, 251, 252, 249, -294, 253, 255,
+ 256, 257, 260, 261, 258, -294, -294, -294, -294, 221,
+ 221, 221, -294, -294, -294, -294, 264, -294, -294, -294,
+ -294, -294, 262, 263, 265, -294, 51, 266, 267, 268,
+ 259, -58, -294, 269, -294, -294, -294, -294, 270, -294,
+ -294, -294, -294, -294, 26, -294, -294, -294, -294, 275,
+ 272, -294, -294, -294, -294, 51, 273, -294, -294, -294
+};
+
+ /* YYDEFACT[STATE-NUM] -- Default reduction number in state STATE-NUM.
+ Performed when YYTABLE does not specify something else to do. Zero
+ means the default is an error. */
+static const yytype_uint8 yydefact[] =
+{
+ 2, 97, 1, 0, 0, 0, 0, 3, 5, 4,
+ 7, 0, 8, 0, 6, 9, 0, 0, 0, 0,
+ 0, 0, 169, 0, 0, 167, 168, 69, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 50, 51, 53, 56,
+ 54, 55, 57, 58, 66, 67, 59, 60, 61, 62,
+ 63, 64, 65, 52, 68, 0, 136, 0, 0, 0,
+ 0, 131, 132, 133, 134, 135, 0, 38, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 28, 29,
+ 30, 31, 32, 33, 34, 35, 36, 37, 0, 0,
+ 0, 0, 166, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 49, 0, 0, 0, 0, 0, 130, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 27,
+ 103, 0, 0, 0, 100, 101, 102, 119, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 109, 110,
+ 111, 113, 115, 112, 114, 117, 118, 116, 0, 165,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 10, 0, 0, 0, 0, 0, 0, 48, 0,
+ 0, 0, 0, 129, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 26, 0, 0, 0, 99, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 108,
+ 170, 70, 86, 71, 72, 73, 74, 78, 75, 76,
+ 77, 79, 10, 10, 10, 10, 10, 10, 10, 12,
+ 11, 80, 82, 81, 83, 84, 85, 0, 0, 0,
+ 0, 90, 91, 92, 93, 137, 138, 139, 150, 152,
+ 0, 0, 0, 0, 0, 0, 143, 144, 145, 147,
+ 146, 148, 149, 46, 45, 47, 42, 43, 39, 40,
+ 41, 44, 0, 0, 98, 0, 20, 0, 0, 0,
+ 0, 0, 0, 0, 0, 107, 13, 14, 15, 16,
+ 17, 18, 19, 0, 0, 0, 0, 89, 0, 0,
+ 0, 0, 0, 0, 0, 142, 104, 105, 124, 20,
+ 20, 20, 22, 21, 127, 120, 0, 122, 125, 123,
+ 126, 121, 0, 0, 0, 88, 0, 0, 0, 0,
+ 0, 0, 163, 0, 141, 23, 24, 25, 0, 96,
+ 95, 94, 156, 157, 0, 155, 160, 158, 151, 0,
+ 0, 162, 159, 128, 153, 0, 0, 161, 154, 164
+};
+
+ /* YYPGOTO[NTERM-NUM]. */
+static const yytype_int16 yypgoto[] =
+{
+ -294, -294, -294, -2, -114, -293, 6, -294, -294, 212,
+ -294, -294, -294, -294, -294, -294, -294, -294, -294, -294,
+ -294, 278, -294, -294, -294, -294, -294, -294, -294, -294,
+ -294, -294, -294, -294, -294, -294, -294, -294, -294, -294,
+ -294, -294, -8, -294, -294, -294, -294, -294, -294, 154,
+ -294, -294, -294, -294, -294, 86, -294, -294, -294, -294,
+ -294, -294, -294, -294, -294, -294, -294, 276, -294, -294,
+ -294, -294, -294, -294, 68, -294, -294, -294, -294, -69,
+ -294, -294, -294, -294, -294, -43, -294, -294, 277, -294
+};
+
+ /* YYDEFGOTO[NTERM-NUM]. */
+static const yytype_int16 yydefgoto[] =
+{
+ -1, 1, 7, 239, 240, 322, 323, 8, 87, 88,
+ 89, 90, 91, 92, 93, 94, 95, 96, 97, 9,
+ 45, 46, 47, 48, 49, 50, 51, 52, 53, 54,
+ 55, 56, 57, 58, 59, 60, 61, 62, 63, 64,
+ 65, 250, 251, 252, 253, 254, 10, 11, 143, 144,
+ 145, 146, 12, 13, 157, 158, 159, 160, 161, 162,
+ 163, 164, 165, 166, 167, 14, 70, 71, 72, 73,
+ 74, 75, 76, 265, 266, 267, 268, 308, 354, 355,
+ 269, 270, 271, 272, 341, 342, 15, 24, 25, 26
+};
+
+ /* YYTABLE[YYPACT[STATE-NUM]] -- What to do in state STATE-NUM. If
+ positive, shift that token. If negative, reduce the rule whose
+ number is the opposite. If YYTABLE_NINF, syntax error. */
+static const yytype_int16 yytable[] =
+{
+ 182, 27, 184, 247, 28, 22, 66, 16, 248, 340,
+ -87, -140, 249, 360, 29, 195, 17, 197, 18, 199,
+ 200, 201, 67, 68, 22, 30, 345, 346, 347, 31,
+ 140, 23, 19, 32, 33, 34, 35, 77, 66, 36,
+ 37, 20, 38, -140, 39, 40, 41, 78, 79, 80,
+ 23, 81, 82, 147, 67, 68, 141, 258, 42, 259,
+ 247, 260, 69, 21, 43, 248, 44, 83, 84, 249,
+ 100, 120, 148, 352, 353, 101, 126, 85, 142, 98,
+ 149, 261, 150, 99, 86, 103, 262, 122, 319, 320,
+ 321, 104, 105, 106, 69, 151, 27, 107, 364, 28,
+ 207, 365, 293, 263, 108, -87, 109, 138, 110, 29,
+ 306, 152, 153, 154, 155, 111, 140, 112, 156, 264,
+ 30, 113, 114, 218, 31, 147, 115, 314, 32, 33,
+ 34, 35, 116, 117, 36, 37, 118, 38, 2, 39,
+ 40, 41, 141, 119, 148, 258, 123, 259, 286, 260,
+ 180, 124, 149, 42, 150, 125, 128, 3, 129, 43,
+ 130, 44, 4, 131, 142, 132, 133, 151, 169, 261,
+ 134, 135, 136, 137, 262, 5, 6, 168, 170, 171,
+ 172, 173, 77, 152, 153, 154, 155, -106, 174, 175,
+ 156, 263, 78, 79, 80, 176, 81, 82, 232, 233,
+ 234, 235, 236, 237, 238, 177, 181, 264, 178, 179,
+ 183, 185, 83, 84, 186, 181, 287, 187, 205, 188,
+ 190, 189, 85, 191, 192, 193, 196, 194, 198, 86,
+ 296, 297, 298, 299, 300, 301, 302, 202, 203, 204,
+ 326, 206, 307, 219, 209, 210, 211, 212, 213, 214,
+ 215, 216, 217, 303, 220, 221, 222, 223, 224, 225,
+ 226, 227, 228, 229, 230, 231, 241, 242, 243, 244,
+ 245, 246, 255, 256, 257, 273, 274, 275, 276, 277,
+ 278, 279, 280, 281, 282, 283, 284, 285, 286, 312,
+ 288, 291, 289, 290, 292, 294, 368, 208, 361, 139,
+ 295, 102, 304, 305, 309, 310, 311, 313, 316, 317,
+ 318, 324, 325, 327, 328, 329, 330, 331, 332, 333,
+ 334, 335, 337, 121, 338, 339, 336, 340, 0, 343,
+ 344, 348, 359, 315, 349, 350, 0, 351, 356, 357,
+ 358, 362, 363, 366, 367, 369, 127
+};
+
+static const yytype_int16 yycheck[] =
+{
+ 114, 1, 116, 21, 4, 1, 1, 70, 26, 67,
+ 10, 6, 30, 71, 14, 129, 70, 131, 70, 133,
+ 134, 135, 17, 18, 1, 25, 319, 320, 321, 29,
+ 1, 27, 70, 33, 34, 35, 36, 1, 1, 39,
+ 40, 65, 42, 6, 44, 45, 46, 11, 12, 13,
+ 27, 15, 16, 1, 17, 18, 27, 1, 58, 3,
+ 21, 5, 57, 49, 64, 26, 66, 31, 32, 30,
+ 73, 71, 20, 22, 23, 71, 71, 41, 49, 70,
+ 28, 25, 30, 70, 48, 73, 30, 10, 7, 8,
+ 9, 73, 73, 73, 57, 43, 1, 73, 72, 4,
+ 71, 75, 216, 47, 73, 10, 73, 71, 73, 14,
+ 71, 59, 60, 61, 62, 73, 1, 73, 66, 63,
+ 25, 73, 73, 71, 29, 1, 73, 71, 33, 34,
+ 35, 36, 73, 73, 39, 40, 73, 42, 0, 44,
+ 45, 46, 27, 73, 20, 1, 73, 3, 67, 5,
+ 67, 73, 28, 58, 30, 73, 6, 19, 73, 64,
+ 73, 66, 24, 73, 49, 73, 73, 43, 72, 25,
+ 73, 73, 73, 73, 30, 37, 38, 68, 68, 68,
+ 68, 68, 1, 59, 60, 61, 62, 49, 68, 68,
+ 66, 47, 11, 12, 13, 68, 15, 16, 50, 51,
+ 52, 53, 54, 55, 56, 68, 67, 63, 68, 68,
+ 68, 68, 31, 32, 68, 67, 210, 68, 73, 72,
+ 68, 70, 41, 68, 68, 72, 67, 70, 67, 48,
+ 232, 233, 234, 235, 236, 237, 238, 68, 68, 72,
+ 74, 73, 250, 157, 73, 73, 73, 73, 73, 73,
+ 73, 73, 73, 73, 72, 72, 72, 72, 72, 72,
+ 72, 72, 72, 72, 72, 72, 72, 72, 72, 72,
+ 72, 72, 72, 72, 72, 72, 72, 72, 72, 72,
+ 72, 72, 72, 72, 68, 68, 72, 67, 67, 70,
+ 68, 67, 69, 68, 68, 68, 365, 143, 341, 87,
+ 72, 24, 73, 73, 73, 73, 73, 73, 72, 72,
+ 72, 72, 72, 72, 72, 72, 72, 72, 68, 68,
+ 68, 72, 67, 45, 68, 68, 73, 67, -1, 68,
+ 72, 67, 73, 265, 72, 72, -1, 72, 72, 72,
+ 72, 72, 72, 68, 72, 72, 70
+};
+
+ /* YYSTOS[STATE-NUM] -- The (internal number of the) accessing
+ symbol of state STATE-NUM. */
+static const yytype_uint8 yystos[] =
+{
+ 0, 77, 0, 19, 24, 37, 38, 78, 83, 95,
+ 122, 123, 128, 129, 141, 162, 70, 70, 70, 70,
+ 65, 49, 1, 27, 163, 164, 165, 1, 4, 14,
+ 25, 29, 33, 34, 35, 36, 39, 40, 42, 44,
+ 45, 46, 58, 64, 66, 96, 97, 98, 99, 100,
+ 101, 102, 103, 104, 105, 106, 107, 108, 109, 110,
+ 111, 112, 113, 114, 115, 116, 1, 17, 18, 57,
+ 142, 143, 144, 145, 146, 147, 148, 1, 11, 12,
+ 13, 15, 16, 31, 32, 41, 48, 84, 85, 86,
+ 87, 88, 89, 90, 91, 92, 93, 94, 70, 70,
+ 73, 71, 164, 73, 73, 73, 73, 73, 73, 73,
+ 73, 73, 73, 73, 73, 73, 73, 73, 73, 73,
+ 71, 97, 10, 73, 73, 73, 71, 143, 6, 73,
+ 73, 73, 73, 73, 73, 73, 73, 73, 71, 85,
+ 1, 27, 49, 124, 125, 126, 127, 1, 20, 28,
+ 30, 43, 59, 60, 61, 62, 66, 130, 131, 132,
+ 133, 134, 135, 136, 137, 138, 139, 140, 68, 72,
+ 68, 68, 68, 68, 68, 68, 68, 68, 68, 68,
+ 67, 67, 80, 68, 80, 68, 68, 68, 72, 70,
+ 68, 68, 68, 72, 70, 80, 67, 80, 67, 80,
+ 80, 80, 68, 68, 72, 73, 73, 71, 125, 73,
+ 73, 73, 73, 73, 73, 73, 73, 73, 71, 131,
+ 72, 72, 72, 72, 72, 72, 72, 72, 72, 72,
+ 72, 72, 50, 51, 52, 53, 54, 55, 56, 79,
+ 80, 72, 72, 72, 72, 72, 72, 21, 26, 30,
+ 117, 118, 119, 120, 121, 72, 72, 72, 1, 3,
+ 5, 25, 30, 47, 63, 149, 150, 151, 152, 156,
+ 157, 158, 159, 72, 72, 72, 72, 72, 72, 72,
+ 72, 72, 68, 68, 72, 67, 67, 82, 68, 69,
+ 68, 67, 68, 80, 68, 72, 79, 79, 79, 79,
+ 79, 79, 79, 73, 73, 73, 71, 118, 153, 73,
+ 73, 73, 70, 73, 71, 150, 72, 72, 72, 7,
+ 8, 9, 81, 82, 72, 72, 74, 72, 72, 72,
+ 72, 72, 68, 68, 68, 72, 73, 67, 68, 68,
+ 67, 160, 161, 68, 72, 81, 81, 81, 67, 72,
+ 72, 72, 22, 23, 154, 155, 72, 72, 72, 73,
+ 71, 161, 72, 72, 72, 75, 68, 72, 155, 72
+};
+
+ /* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */
+static const yytype_uint8 yyr1[] =
+{
+ 0, 76, 77, 77, 78, 78, 78, 78, 78, 78,
+ 79, 79, 80, 80, 80, 80, 80, 80, 80, 80,
+ 81, 81, 82, 82, 82, 82, 83, 84, 84, 85,
+ 85, 85, 85, 85, 85, 85, 85, 85, 85, 86,
+ 87, 88, 89, 90, 91, 92, 93, 94, 95, 96,
+ 96, 97, 97, 97, 97, 97, 97, 97, 97, 97,
+ 97, 97, 97, 97, 97, 97, 97, 97, 97, 97,
+ 98, 99, 100, 101, 102, 103, 104, 105, 106, 107,
+ 108, 109, 110, 111, 112, 113, 114, 116, 115, 117,
+ 117, 118, 118, 118, 119, 120, 121, 123, 122, 124,
+ 124, 125, 125, 125, 126, 127, 129, 128, 130, 130,
+ 131, 131, 131, 131, 131, 131, 131, 131, 131, 131,
+ 132, 133, 134, 135, 136, 137, 138, 139, 140, 141,
+ 142, 142, 143, 143, 143, 143, 143, 144, 145, 146,
+ 148, 147, 149, 149, 150, 150, 150, 150, 150, 150,
+ 150, 151, 153, 152, 154, 154, 155, 155, 156, 157,
+ 158, 159, 160, 160, 161, 162, 163, 163, 164, 164,
+ 165
+};
+
+ /* YYR2[YYN] -- Number of symbols on the right hand side of rule YYN. */
+static const yytype_uint8 yyr2[] =
+{
+ 0, 2, 0, 2, 1, 1, 1, 1, 1, 1,
+ 0, 1, 2, 3, 3, 3, 3, 3, 3, 3,
+ 0, 1, 2, 3, 3, 3, 5, 2, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4, 5, 2,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 0, 6, 2,
+ 1, 1, 1, 1, 4, 4, 4, 0, 6, 2,
+ 1, 1, 1, 1, 4, 4, 0, 6, 2, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 4, 4, 4, 4, 4, 4, 4, 4, 6, 5,
+ 2, 1, 1, 1, 1, 1, 1, 4, 4, 4,
+ 0, 6, 2, 1, 1, 1, 1, 1, 1, 1,
+ 1, 4, 0, 5, 3, 1, 1, 1, 4, 4,
+ 4, 5, 2, 1, 4, 5, 2, 1, 1, 1,
+ 4
+};
+
+
+#define yyerrok (yyerrstatus = 0)
+#define yyclearin (yychar = YYEMPTY)
+#define YYEMPTY (-2)
+#define YYEOF 0
+
+#define YYACCEPT goto yyacceptlab
+#define YYABORT goto yyabortlab
+#define YYERROR goto yyerrorlab
+
+
+#define YYRECOVERING() (!!yyerrstatus)
+
+#define YYBACKUP(Token, Value) \
+do \
+ if (yychar == YYEMPTY) \
+ { \
+ yychar = (Token); \
+ yylval = (Value); \
+ YYPOPSTACK (yylen); \
+ yystate = *yyssp; \
+ goto yybackup; \
+ } \
+ else \
+ { \
+ yyerror (YY_("syntax error: cannot back up")); \
+ YYERROR; \
+ } \
+while (0)
+
+/* Error token number */
+#define YYTERROR 1
+#define YYERRCODE 256
+
+
+
+/* Enable debugging if requested. */
+#if YYDEBUG
+
+# ifndef YYFPRINTF
+# include <stdio.h> /* INFRINGES ON USER NAME SPACE */
+# define YYFPRINTF fprintf
+# endif
+
+# define YYDPRINTF(Args) \
+do { \
+ if (yydebug) \
+ YYFPRINTF Args; \
+} while (0)
+
+/* This macro is provided for backward compatibility. */
+#ifndef YY_LOCATION_PRINT
+# define YY_LOCATION_PRINT(File, Loc) ((void) 0)
+#endif
+
+
+# define YY_SYMBOL_PRINT(Title, Type, Value, Location) \
+do { \
+ if (yydebug) \
+ { \
+ YYFPRINTF (stderr, "%s ", Title); \
+ yy_symbol_print (stderr, \
+ Type, Value); \
+ YYFPRINTF (stderr, "\n"); \
+ } \
+} while (0)
+
+
+/*----------------------------------------.
+| Print this symbol's value on YYOUTPUT. |
+`----------------------------------------*/
+
+static void
+yy_symbol_value_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep)
+{
+ FILE *yyo = yyoutput;
+ YYUSE (yyo);
+ if (!yyvaluep)
+ return;
+# ifdef YYPRINT
+ if (yytype < YYNTOKENS)
+ YYPRINT (yyoutput, yytoknum[yytype], *yyvaluep);
+# endif
+ YYUSE (yytype);
+}
+
+
+/*--------------------------------.
+| Print this symbol on YYOUTPUT. |
+`--------------------------------*/
+
+static void
+yy_symbol_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep)
+{
+ YYFPRINTF (yyoutput, "%s %s (",
+ yytype < YYNTOKENS ? "token" : "nterm", yytname[yytype]);
+
+ yy_symbol_value_print (yyoutput, yytype, yyvaluep);
+ YYFPRINTF (yyoutput, ")");
+}
+
+/*------------------------------------------------------------------.
+| yy_stack_print -- Print the state stack from its BOTTOM up to its |
+| TOP (included). |
+`------------------------------------------------------------------*/
+
+static void
+yy_stack_print (yytype_int16 *yybottom, yytype_int16 *yytop)
+{
+ YYFPRINTF (stderr, "Stack now");
+ for (; yybottom <= yytop; yybottom++)
+ {
+ int yybot = *yybottom;
+ YYFPRINTF (stderr, " %d", yybot);
+ }
+ YYFPRINTF (stderr, "\n");
+}
+
+# define YY_STACK_PRINT(Bottom, Top) \
+do { \
+ if (yydebug) \
+ yy_stack_print ((Bottom), (Top)); \
+} while (0)
+
+
+/*------------------------------------------------.
+| Report that the YYRULE is going to be reduced. |
+`------------------------------------------------*/
+
+static void
+yy_reduce_print (yytype_int16 *yyssp, YYSTYPE *yyvsp, int yyrule)
+{
+ unsigned long int yylno = yyrline[yyrule];
+ int yynrhs = yyr2[yyrule];
+ int yyi;
+ YYFPRINTF (stderr, "Reducing stack by rule %d (line %lu):\n",
+ yyrule - 1, yylno);
+ /* The symbols being reduced. */
+ for (yyi = 0; yyi < yynrhs; yyi++)
+ {
+ YYFPRINTF (stderr, " $%d = ", yyi + 1);
+ yy_symbol_print (stderr,
+ yystos[yyssp[yyi + 1 - yynrhs]],
+ &(yyvsp[(yyi + 1) - (yynrhs)])
+ );
+ YYFPRINTF (stderr, "\n");
+ }
+}
+
+# define YY_REDUCE_PRINT(Rule) \
+do { \
+ if (yydebug) \
+ yy_reduce_print (yyssp, yyvsp, Rule); \
+} while (0)
+
+/* Nonzero means print parse trace. It is left uninitialized so that
+ multiple parsers can coexist. */
+int yydebug;
+#else /* !YYDEBUG */
+# define YYDPRINTF(Args)
+# define YY_SYMBOL_PRINT(Title, Type, Value, Location)
+# define YY_STACK_PRINT(Bottom, Top)
+# define YY_REDUCE_PRINT(Rule)
+#endif /* !YYDEBUG */
+
+
+/* YYINITDEPTH -- initial size of the parser's stacks. */
+#ifndef YYINITDEPTH
+# define YYINITDEPTH 200
+#endif
+
+/* YYMAXDEPTH -- maximum size the stacks can grow to (effective only
+ if the built-in stack extension method is used).
+
+ Do not make this value too large; the results are undefined if
+ YYSTACK_ALLOC_MAXIMUM < YYSTACK_BYTES (YYMAXDEPTH)
+ evaluated with infinite-precision integer arithmetic. */
+
+#ifndef YYMAXDEPTH
+# define YYMAXDEPTH 10000
+#endif
+
+
+#if YYERROR_VERBOSE
+
+# ifndef yystrlen
+# if defined __GLIBC__ && defined _STRING_H
+# define yystrlen strlen
+# else
+/* Return the length of YYSTR. */
+static YYSIZE_T
+yystrlen (const char *yystr)
+{
+ YYSIZE_T yylen;
+ for (yylen = 0; yystr[yylen]; yylen++)
+ continue;
+ return yylen;
+}
+# endif
+# endif
+
+# ifndef yystpcpy
+# if defined __GLIBC__ && defined _STRING_H && defined _GNU_SOURCE
+# define yystpcpy stpcpy
+# else
+/* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in
+ YYDEST. */
+static char *
+yystpcpy (char *yydest, const char *yysrc)
+{
+ char *yyd = yydest;
+ const char *yys = yysrc;
+
+ while ((*yyd++ = *yys++) != '\0')
+ continue;
+
+ return yyd - 1;
+}
+# endif
+# endif
+
+# ifndef yytnamerr
+/* Copy to YYRES the contents of YYSTR after stripping away unnecessary
+ quotes and backslashes, so that it's suitable for yyerror. The
+ heuristic is that double-quoting is unnecessary unless the string
+ contains an apostrophe, a comma, or backslash (other than
+ backslash-backslash). YYSTR is taken from yytname. If YYRES is
+ null, do not copy; instead, return the length of what the result
+ would have been. */
+static YYSIZE_T
+yytnamerr (char *yyres, const char *yystr)
+{
+ if (*yystr == '"')
+ {
+ YYSIZE_T yyn = 0;
+ char const *yyp = yystr;
+
+ for (;;)
+ switch (*++yyp)
+ {
+ case '\'':
+ case ',':
+ goto do_not_strip_quotes;
+
+ case '\\':
+ if (*++yyp != '\\')
+ goto do_not_strip_quotes;
+ /* Fall through. */
+ default:
+ if (yyres)
+ yyres[yyn] = *yyp;
+ yyn++;
+ break;
+
+ case '"':
+ if (yyres)
+ yyres[yyn] = '\0';
+ return yyn;
+ }
+ do_not_strip_quotes: ;
+ }
+
+ if (! yyres)
+ return yystrlen (yystr);
+
+ return yystpcpy (yyres, yystr) - yyres;
+}
+# endif
+
+/* Copy into *YYMSG, which is of size *YYMSG_ALLOC, an error message
+ about the unexpected token YYTOKEN for the state stack whose top is
+ YYSSP.
+
+ Return 0 if *YYMSG was successfully written. Return 1 if *YYMSG is
+ not large enough to hold the message. In that case, also set
+ *YYMSG_ALLOC to the required number of bytes. Return 2 if the
+ required number of bytes is too large to store. */
+static int
+yysyntax_error (YYSIZE_T *yymsg_alloc, char **yymsg,
+ yytype_int16 *yyssp, int yytoken)
+{
+ YYSIZE_T yysize0 = yytnamerr (YY_NULLPTR, yytname[yytoken]);
+ YYSIZE_T yysize = yysize0;
+ enum { YYERROR_VERBOSE_ARGS_MAXIMUM = 5 };
+ /* Internationalized format string. */
+ const char *yyformat = YY_NULLPTR;
+ /* Arguments of yyformat. */
+ char const *yyarg[YYERROR_VERBOSE_ARGS_MAXIMUM];
+ /* Number of reported tokens (one for the "unexpected", one per
+ "expected"). */
+ int yycount = 0;
+
+ /* There are many possibilities here to consider:
+ - If this state is a consistent state with a default action, then
+ the only way this function was invoked is if the default action
+ is an error action. In that case, don't check for expected
+ tokens because there are none.
+ - The only way there can be no lookahead present (in yychar) is if
+ this state is a consistent state with a default action. Thus,
+ detecting the absence of a lookahead is sufficient to determine
+ that there is no unexpected or expected token to report. In that
+ case, just report a simple "syntax error".
+ - Don't assume there isn't a lookahead just because this state is a
+ consistent state with a default action. There might have been a
+ previous inconsistent state, consistent state with a non-default
+ action, or user semantic action that manipulated yychar.
+ - Of course, the expected token list depends on states to have
+ correct lookahead information, and it depends on the parser not
+ to perform extra reductions after fetching a lookahead from the
+ scanner and before detecting a syntax error. Thus, state merging
+ (from LALR or IELR) and default reductions corrupt the expected
+ token list. However, the list is correct for canonical LR with
+ one exception: it will still contain any token that will not be
+ accepted due to an error action in a later state.
+ */
+ if (yytoken != YYEMPTY)
+ {
+ int yyn = yypact[*yyssp];
+ yyarg[yycount++] = yytname[yytoken];
+ if (!yypact_value_is_default (yyn))
+ {
+ /* Start YYX at -YYN if negative to avoid negative indexes in
+ YYCHECK. In other words, skip the first -YYN actions for
+ this state because they are default actions. */
+ int yyxbegin = yyn < 0 ? -yyn : 0;
+ /* Stay within bounds of both yycheck and yytname. */
+ int yychecklim = YYLAST - yyn + 1;
+ int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS;
+ int yyx;
+
+ for (yyx = yyxbegin; yyx < yyxend; ++yyx)
+ if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR
+ && !yytable_value_is_error (yytable[yyx + yyn]))
+ {
+ if (yycount == YYERROR_VERBOSE_ARGS_MAXIMUM)
+ {
+ yycount = 1;
+ yysize = yysize0;
+ break;
+ }
+ yyarg[yycount++] = yytname[yyx];
+ {
+ YYSIZE_T yysize1 = yysize + yytnamerr (YY_NULLPTR, yytname[yyx]);
+ if (! (yysize <= yysize1
+ && yysize1 <= YYSTACK_ALLOC_MAXIMUM))
+ return 2;
+ yysize = yysize1;
+ }
+ }
+ }
+ }
+
+ switch (yycount)
+ {
+# define YYCASE_(N, S) \
+ case N: \
+ yyformat = S; \
+ break
+ YYCASE_(0, YY_("syntax error"));
+ YYCASE_(1, YY_("syntax error, unexpected %s"));
+ YYCASE_(2, YY_("syntax error, unexpected %s, expecting %s"));
+ YYCASE_(3, YY_("syntax error, unexpected %s, expecting %s or %s"));
+ YYCASE_(4, YY_("syntax error, unexpected %s, expecting %s or %s or %s"));
+ YYCASE_(5, YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s"));
+# undef YYCASE_
+ }
+
+ {
+ YYSIZE_T yysize1 = yysize + yystrlen (yyformat);
+ if (! (yysize <= yysize1 && yysize1 <= YYSTACK_ALLOC_MAXIMUM))
+ return 2;
+ yysize = yysize1;
+ }
+
+ if (*yymsg_alloc < yysize)
+ {
+ *yymsg_alloc = 2 * yysize;
+ if (! (yysize <= *yymsg_alloc
+ && *yymsg_alloc <= YYSTACK_ALLOC_MAXIMUM))
+ *yymsg_alloc = YYSTACK_ALLOC_MAXIMUM;
+ return 1;
+ }
+
+ /* Avoid sprintf, as that infringes on the user's name space.
+ Don't have undefined behavior even if the translation
+ produced a string with the wrong number of "%s"s. */
+ {
+ char *yyp = *yymsg;
+ int yyi = 0;
+ while ((*yyp = *yyformat) != '\0')
+ if (*yyp == '%' && yyformat[1] == 's' && yyi < yycount)
+ {
+ yyp += yytnamerr (yyp, yyarg[yyi++]);
+ yyformat += 2;
+ }
+ else
+ {
+ yyp++;
+ yyformat++;
+ }
+ }
+ return 0;
+}
+#endif /* YYERROR_VERBOSE */
+
+/*-----------------------------------------------.
+| Release the memory associated to this symbol. |
+`-----------------------------------------------*/
+
+static void
+yydestruct (const char *yymsg, int yytype, YYSTYPE *yyvaluep)
+{
+ YYUSE (yyvaluep);
+ if (!yymsg)
+ yymsg = "Deleting";
+ YY_SYMBOL_PRINT (yymsg, yytype, yyvaluep, yylocationp);
+
+ YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
+ YYUSE (yytype);
+ YY_IGNORE_MAYBE_UNINITIALIZED_END
+}
+
+
+
+
+/* The lookahead symbol. */
+int yychar;
+
+/* The semantic value of the lookahead symbol. */
+YYSTYPE yylval;
+/* Number of syntax errors so far. */
+int yynerrs;
+
+
+/*----------.
+| yyparse. |
+`----------*/
+
+int
+yyparse (void)
+{
+ int yystate;
+ /* Number of tokens to shift before error messages enabled. */
+ int yyerrstatus;
+
+ /* The stacks and their tools:
+ 'yyss': related to states.
+ 'yyvs': related to semantic values.
+
+ Refer to the stacks through separate pointers, to allow yyoverflow
+ to reallocate them elsewhere. */
+
+ /* The state stack. */
+ yytype_int16 yyssa[YYINITDEPTH];
+ yytype_int16 *yyss;
+ yytype_int16 *yyssp;
+
+ /* The semantic value stack. */
+ YYSTYPE yyvsa[YYINITDEPTH];
+ YYSTYPE *yyvs;
+ YYSTYPE *yyvsp;
+
+ YYSIZE_T yystacksize;
+
+ int yyn;
+ int yyresult;
+ /* Lookahead token as an internal (translated) token number. */
+ int yytoken = 0;
+ /* The variables used to return semantic value and location from the
+ action routines. */
+ YYSTYPE yyval;
+
+#if YYERROR_VERBOSE
+ /* Buffer for error messages, and its allocated size. */
+ char yymsgbuf[128];
+ char *yymsg = yymsgbuf;
+ YYSIZE_T yymsg_alloc = sizeof yymsgbuf;
+#endif
+
+#define YYPOPSTACK(N) (yyvsp -= (N), yyssp -= (N))
+
+ /* The number of symbols on the RHS of the reduced rule.
+ Keep to zero when no symbol should be popped. */
+ int yylen = 0;
+
+ yyssp = yyss = yyssa;
+ yyvsp = yyvs = yyvsa;
+ yystacksize = YYINITDEPTH;
+
+ YYDPRINTF ((stderr, "Starting parse\n"));
+
+ yystate = 0;
+ yyerrstatus = 0;
+ yynerrs = 0;
+ yychar = YYEMPTY; /* Cause a token to be read. */
+ goto yysetstate;
+
+/*------------------------------------------------------------.
+| yynewstate -- Push a new state, which is found in yystate. |
+`------------------------------------------------------------*/
+ yynewstate:
+ /* In all cases, when you get here, the value and location stacks
+ have just been pushed. So pushing a state here evens the stacks. */
+ yyssp++;
+
+ yysetstate:
+ *yyssp = yystate;
+
+ if (yyss + yystacksize - 1 <= yyssp)
+ {
+ /* Get the current used size of the three stacks, in elements. */
+ YYSIZE_T yysize = yyssp - yyss + 1;
+
+#ifdef yyoverflow
+ {
+ /* Give user a chance to reallocate the stack. Use copies of
+ these so that the &'s don't force the real ones into
+ memory. */
+ YYSTYPE *yyvs1 = yyvs;
+ yytype_int16 *yyss1 = yyss;
+
+ /* Each stack pointer address is followed by the size of the
+ data in use in that stack, in bytes. This used to be a
+ conditional around just the two extra args, but that might
+ be undefined if yyoverflow is a macro. */
+ yyoverflow (YY_("memory exhausted"),
+ &yyss1, yysize * sizeof (*yyssp),
+ &yyvs1, yysize * sizeof (*yyvsp),
+ &yystacksize);
+
+ yyss = yyss1;
+ yyvs = yyvs1;
+ }
+#else /* no yyoverflow */
+# ifndef YYSTACK_RELOCATE
+ goto yyexhaustedlab;
+# else
+ /* Extend the stack our own way. */
+ if (YYMAXDEPTH <= yystacksize)
+ goto yyexhaustedlab;
+ yystacksize *= 2;
+ if (YYMAXDEPTH < yystacksize)
+ yystacksize = YYMAXDEPTH;
+
+ {
+ yytype_int16 *yyss1 = yyss;
+ union yyalloc *yyptr =
+ (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize));
+ if (! yyptr)
+ goto yyexhaustedlab;
+ YYSTACK_RELOCATE (yyss_alloc, yyss);
+ YYSTACK_RELOCATE (yyvs_alloc, yyvs);
+# undef YYSTACK_RELOCATE
+ if (yyss1 != yyssa)
+ YYSTACK_FREE (yyss1);
+ }
+# endif
+#endif /* no yyoverflow */
+
+ yyssp = yyss + yysize - 1;
+ yyvsp = yyvs + yysize - 1;
+
+ YYDPRINTF ((stderr, "Stack size increased to %lu\n",
+ (unsigned long int) yystacksize));
+
+ if (yyss + yystacksize - 1 <= yyssp)
+ YYABORT;
+ }
+
+ YYDPRINTF ((stderr, "Entering state %d\n", yystate));
+
+ if (yystate == YYFINAL)
+ YYACCEPT;
+
+ goto yybackup;
+
+/*-----------.
+| yybackup. |
+`-----------*/
+yybackup:
+
+ /* Do appropriate processing given the current state. Read a
+ lookahead token if we need one and don't already have one. */
+
+ /* First try to decide what to do without reference to lookahead token. */
+ yyn = yypact[yystate];
+ if (yypact_value_is_default (yyn))
+ goto yydefault;
+
+ /* Not known => get a lookahead token if don't already have one. */
+
+ /* YYCHAR is either YYEMPTY or YYEOF or a valid lookahead symbol. */
+ if (yychar == YYEMPTY)
+ {
+ YYDPRINTF ((stderr, "Reading a token: "));
+ yychar = yylex ();
+ }
+
+ if (yychar <= YYEOF)
+ {
+ yychar = yytoken = YYEOF;
+ YYDPRINTF ((stderr, "Now at end of input.\n"));
+ }
+ else
+ {
+ yytoken = YYTRANSLATE (yychar);
+ YY_SYMBOL_PRINT ("Next token is", yytoken, &yylval, &yylloc);
+ }
+
+ /* If the proper action on seeing token YYTOKEN is to reduce or to
+ detect an error, take that action. */
+ yyn += yytoken;
+ if (yyn < 0 || YYLAST < yyn || yycheck[yyn] != yytoken)
+ goto yydefault;
+ yyn = yytable[yyn];
+ if (yyn <= 0)
+ {
+ if (yytable_value_is_error (yyn))
+ goto yyerrlab;
+ yyn = -yyn;
+ goto yyreduce;
+ }
+
+ /* Count tokens shifted since error; after three, turn off error
+ status. */
+ if (yyerrstatus)
+ yyerrstatus--;
+
+ /* Shift the lookahead token. */
+ YY_SYMBOL_PRINT ("Shifting", yytoken, &yylval, &yylloc);
+
+ /* Discard the shifted token. */
+ yychar = YYEMPTY;
+
+ yystate = yyn;
+ YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
+ *++yyvsp = yylval;
+ YY_IGNORE_MAYBE_UNINITIALIZED_END
+
+ goto yynewstate;
+
+
+/*-----------------------------------------------------------.
+| yydefault -- do the default action for the current state. |
+`-----------------------------------------------------------*/
+yydefault:
+ yyn = yydefact[yystate];
+ if (yyn == 0)
+ goto yyerrlab;
+ goto yyreduce;
+
+
+/*-----------------------------.
+| yyreduce -- Do a reduction. |
+`-----------------------------*/
+yyreduce:
+ /* yyn is the number of a rule to reduce with. */
+ yylen = yyr2[yyn];
+
+ /* If YYLEN is nonzero, implement the default value of the action:
+ '$$ = $1'.
+
+ Otherwise, the following line sets YYVAL to garbage.
+ This behavior is undocumented and Bison
+ users should not rely upon it. Assigning to YYVAL
+ unconditionally makes the parser a bit smaller, and it avoids a
+ GCC warning that YYVAL may be used uninitialized. */
+ yyval = yyvsp[1-yylen];
+
+
+ YY_REDUCE_PRINT (yyn);
+ switch (yyn)
+ {
+ case 10:
+#line 117 "config-parser.y" /* yacc.c:1646 */
+ { (yyval.number) = 0; }
+#line 1634 "config-parser.c" /* yacc.c:1646 */
+ break;
+
+ case 12:
+#line 118 "config-parser.y" /* yacc.c:1646 */
+ { (yyval.number) = (yyvsp[-1].number) + (yyvsp[0].number); }
+#line 1640 "config-parser.c" /* yacc.c:1646 */
+ break;
+
+ case 13:
+#line 119 "config-parser.y" /* yacc.c:1646 */
+ { (yyval.number) = (yyvsp[-2].number) + (yyvsp[0].number); }
+#line 1646 "config-parser.c" /* yacc.c:1646 */
+ break;
+
+ case 14:
+#line 120 "config-parser.y" /* yacc.c:1646 */
+ { (yyval.number) = (yyvsp[-2].number) * 60 + (yyvsp[0].number); }
+#line 1652 "config-parser.c" /* yacc.c:1646 */
+ break;
+
+ case 15:
+#line 121 "config-parser.y" /* yacc.c:1646 */
+ { (yyval.number) = (yyvsp[-2].number) * 60 * 60 + (yyvsp[0].number); }
+#line 1658 "config-parser.c" /* yacc.c:1646 */
+ break;
+
+ case 16:
+#line 122 "config-parser.y" /* yacc.c:1646 */
+ { (yyval.number) = (yyvsp[-2].number) * 60 * 60 * 24 + (yyvsp[0].number); }
+#line 1664 "config-parser.c" /* yacc.c:1646 */
+ break;
+
+ case 17:
+#line 123 "config-parser.y" /* yacc.c:1646 */
+ { (yyval.number) = (yyvsp[-2].number) * 60 * 60 * 24 * 7 + (yyvsp[0].number); }
+#line 1670 "config-parser.c" /* yacc.c:1646 */
+ break;
+
+ case 18:
+#line 124 "config-parser.y" /* yacc.c:1646 */
+ { (yyval.number) = (yyvsp[-2].number) * 60 * 60 * 24 * 7 * 4 + (yyvsp[0].number); }
+#line 1676 "config-parser.c" /* yacc.c:1646 */
+ break;
+
+ case 19:
+#line 125 "config-parser.y" /* yacc.c:1646 */
+ { (yyval.number) = (yyvsp[-2].number) * 60 * 60 * 24 * 365 + (yyvsp[0].number); }
+#line 1682 "config-parser.c" /* yacc.c:1646 */
+ break;
+
+ case 20:
+#line 128 "config-parser.y" /* yacc.c:1646 */
+ { (yyval.number) = 0; }
+#line 1688 "config-parser.c" /* yacc.c:1646 */
+ break;
+
+ case 22:
+#line 129 "config-parser.y" /* yacc.c:1646 */
+ { (yyval.number) = (yyvsp[-1].number) + (yyvsp[0].number); }
+#line 1694 "config-parser.c" /* yacc.c:1646 */
+ break;
+
+ case 23:
+#line 130 "config-parser.y" /* yacc.c:1646 */
+ { (yyval.number) = (yyvsp[-2].number) + (yyvsp[0].number); }
+#line 1700 "config-parser.c" /* yacc.c:1646 */
+ break;
+
+ case 24:
+#line 131 "config-parser.y" /* yacc.c:1646 */
+ { (yyval.number) = (yyvsp[-2].number) * 1024 + (yyvsp[0].number); }
+#line 1706 "config-parser.c" /* yacc.c:1646 */
+ break;
+
+ case 25:
+#line 132 "config-parser.y" /* yacc.c:1646 */
+ { (yyval.number) = (yyvsp[-2].number) * 1024 * 1024 + (yyvsp[0].number); }
+#line 1712 "config-parser.c" /* yacc.c:1646 */
+ break;
+
+ case 39:
+#line 154 "config-parser.y" /* yacc.c:1646 */
+ {
+ OptionsItem.negcache = (yyvsp[-1].number);
+}
+#line 1720 "config-parser.c" /* yacc.c:1646 */
+ break;
+
+ case 40:
+#line 159 "config-parser.y" /* yacc.c:1646 */
+ {
+ OptionsItem.negcache_rebuild = (yyvsp[-1].number);
+}
+#line 1728 "config-parser.c" /* yacc.c:1646 */
+ break;
+
+ case 41:
+#line 164 "config-parser.y" /* yacc.c:1646 */
+ {
+ xfree(OptionsItem.pidfile);
+ OptionsItem.pidfile = xstrdup((yyvsp[-1].string));
+}
+#line 1737 "config-parser.c" /* yacc.c:1646 */
+ break;
+
+ case 42:
+#line 170 "config-parser.y" /* yacc.c:1646 */
+ {
+ OptionsItem.dns_fdlimit = (yyvsp[-1].number);
+}
+#line 1745 "config-parser.c" /* yacc.c:1646 */
+ break;
+
+ case 43:
+#line 175 "config-parser.y" /* yacc.c:1646 */
+ {
+ OptionsItem.dns_timeout = (yyvsp[-1].number);
+}
+#line 1753 "config-parser.c" /* yacc.c:1646 */
+ break;
+
+ case 44:
+#line 180 "config-parser.y" /* yacc.c:1646 */
+ {
+ xfree(OptionsItem.scanlog);
+ OptionsItem.scanlog = xstrdup((yyvsp[-1].string));
+}
+#line 1762 "config-parser.c" /* yacc.c:1646 */
+ break;
+
+ case 45:
+#line 186 "config-parser.y" /* yacc.c:1646 */
+ {
+ OptionsItem.command_queue_size = (yyvsp[-1].number);
+}
+#line 1770 "config-parser.c" /* yacc.c:1646 */
+ break;
+
+ case 46:
+#line 191 "config-parser.y" /* yacc.c:1646 */
+ {
+ OptionsItem.command_interval = (yyvsp[-1].number);
+}
+#line 1778 "config-parser.c" /* yacc.c:1646 */
+ break;
+
+ case 47:
+#line 196 "config-parser.y" /* yacc.c:1646 */
+ {
+ OptionsItem.command_timeout = (yyvsp[-1].number);
+}
+#line 1786 "config-parser.c" /* yacc.c:1646 */
+ break;
+
+ case 70:
+#line 228 "config-parser.y" /* yacc.c:1646 */
+ {
+ xfree(IRCItem.away);
+ IRCItem.away = xstrdup((yyvsp[-1].string));
+}
+#line 1795 "config-parser.c" /* yacc.c:1646 */
+ break;
+
+ case 71:
+#line 234 "config-parser.y" /* yacc.c:1646 */
+ {
+ xfree(IRCItem.kline);
+ IRCItem.kline = xstrdup((yyvsp[-1].string));
+}
+#line 1804 "config-parser.c" /* yacc.c:1646 */
+ break;
+
+ case 72:
+#line 240 "config-parser.y" /* yacc.c:1646 */
+ {
+ xfree(IRCItem.mode);
+ IRCItem.mode = xstrdup((yyvsp[-1].string));
+}
+#line 1813 "config-parser.c" /* yacc.c:1646 */
+ break;
+
+ case 73:
+#line 246 "config-parser.y" /* yacc.c:1646 */
+ {
+ xfree(IRCItem.nick);
+ IRCItem.nick = xstrdup((yyvsp[-1].string));
+}
+#line 1822 "config-parser.c" /* yacc.c:1646 */
+ break;
+
+ case 74:
+#line 252 "config-parser.y" /* yacc.c:1646 */
+ {
+ xfree(IRCItem.nickserv);
+ IRCItem.nickserv = xstrdup((yyvsp[-1].string));
+}
+#line 1831 "config-parser.c" /* yacc.c:1646 */
+ break;
+
+ case 75:
+#line 258 "config-parser.y" /* yacc.c:1646 */
+ {
+ xfree(IRCItem.oper);
+ IRCItem.oper = xstrdup((yyvsp[-1].string));
+}
+#line 1840 "config-parser.c" /* yacc.c:1646 */
+ break;
+
+ case 76:
+#line 264 "config-parser.y" /* yacc.c:1646 */
+ {
+ xfree(IRCItem.password);
+ IRCItem.password = xstrdup((yyvsp[-1].string));
+}
+#line 1849 "config-parser.c" /* yacc.c:1646 */
+ break;
+
+ case 77:
+#line 270 "config-parser.y" /* yacc.c:1646 */
+ {
+ list_add(xstrdup((yyvsp[-1].string)), node_create(), &IRCItem.performs);
+}
+#line 1857 "config-parser.c" /* yacc.c:1646 */
+ break;
+
+ case 78:
+#line 275 "config-parser.y" /* yacc.c:1646 */
+ {
+ list_add(xstrdup((yyvsp[-1].string)), node_create(), &IRCItem.notices);
+}
+#line 1865 "config-parser.c" /* yacc.c:1646 */
+ break;
+
+ case 79:
+#line 280 "config-parser.y" /* yacc.c:1646 */
+ {
+ IRCItem.port = (yyvsp[-1].number);
+}
+#line 1873 "config-parser.c" /* yacc.c:1646 */
+ break;
+
+ case 80:
+#line 285 "config-parser.y" /* yacc.c:1646 */
+ {
+ IRCItem.readtimeout = (yyvsp[-1].number);
+}
+#line 1881 "config-parser.c" /* yacc.c:1646 */
+ break;
+
+ case 81:
+#line 290 "config-parser.y" /* yacc.c:1646 */
+ {
+ IRCItem.reconnectinterval = (yyvsp[-1].number);
+}
+#line 1889 "config-parser.c" /* yacc.c:1646 */
+ break;
+
+ case 82:
+#line 295 "config-parser.y" /* yacc.c:1646 */
+ {
+ xfree(IRCItem.realname);
+ IRCItem.realname = xstrdup((yyvsp[-1].string));
+}
+#line 1898 "config-parser.c" /* yacc.c:1646 */
+ break;
+
+ case 83:
+#line 301 "config-parser.y" /* yacc.c:1646 */
+ {
+ xfree(IRCItem.server);
+ IRCItem.server = xstrdup((yyvsp[-1].string));
+}
+#line 1907 "config-parser.c" /* yacc.c:1646 */
+ break;
+
+ case 84:
+#line 307 "config-parser.y" /* yacc.c:1646 */
+ {
+ xfree(IRCItem.username);
+ IRCItem.username = xstrdup((yyvsp[-1].string));
+}
+#line 1916 "config-parser.c" /* yacc.c:1646 */
+ break;
+
+ case 85:
+#line 313 "config-parser.y" /* yacc.c:1646 */
+ {
+ xfree(IRCItem.vhost);
+ IRCItem.vhost = xstrdup((yyvsp[-1].string));
+}
+#line 1925 "config-parser.c" /* yacc.c:1646 */
+ break;
+
+ case 86:
+#line 319 "config-parser.y" /* yacc.c:1646 */
+ {
+ xfree(IRCItem.connregex);
+ IRCItem.connregex = xstrdup((yyvsp[-1].string));
+}
+#line 1934 "config-parser.c" /* yacc.c:1646 */
+ break;
+
+ case 87:
+#line 327 "config-parser.y" /* yacc.c:1646 */
+ {
+ struct ChannelConf *item;
+
+ item = xcalloc(sizeof(*item));
+ item->name = xstrdup("");
+ item->key = xstrdup("");
+ item->invite = xstrdup("");
+
+ list_add(item, &item->node, &IRCItem.channels);
+ tmp = item;
+}
+#line 1950 "config-parser.c" /* yacc.c:1646 */
+ break;
+
+ case 94:
+#line 348 "config-parser.y" /* yacc.c:1646 */
+ {
+ struct ChannelConf *item = tmp;
+
+ xfree(item->name);
+ item->name = xstrdup((yyvsp[-1].string));
+}
+#line 1961 "config-parser.c" /* yacc.c:1646 */
+ break;
+
+ case 95:
+#line 356 "config-parser.y" /* yacc.c:1646 */
+ {
+ struct ChannelConf *item = tmp;
+
+ xfree(item->key);
+ item->key = xstrdup((yyvsp[-1].string));
+}
+#line 1972 "config-parser.c" /* yacc.c:1646 */
+ break;
+
+ case 96:
+#line 364 "config-parser.y" /* yacc.c:1646 */
+ {
+ struct ChannelConf *item = tmp;
+
+ xfree(item->invite);
+ item->invite = xstrdup((yyvsp[-1].string));
+}
+#line 1983 "config-parser.c" /* yacc.c:1646 */
+ break;
+
+ case 97:
+#line 374 "config-parser.y" /* yacc.c:1646 */
+ {
+ struct UserConf *item;
+
+ item = xcalloc(sizeof(*item));
+
+ list_add(item, &item->node, &UserItemList);
+ tmp = item;
+}
+#line 1996 "config-parser.c" /* yacc.c:1646 */
+ break;
+
+ case 104:
+#line 392 "config-parser.y" /* yacc.c:1646 */
+ {
+ struct UserConf *item = tmp;
+
+ list_add(xstrdup((yyvsp[-1].string)), node_create(), &item->masks);
+}
+#line 2006 "config-parser.c" /* yacc.c:1646 */
+ break;
+
+ case 105:
+#line 399 "config-parser.y" /* yacc.c:1646 */
+ {
+ struct UserConf *item = tmp;
+
+ list_add(xstrdup((yyvsp[-1].string)), node_create(), &item->scanners);
+}
+#line 2016 "config-parser.c" /* yacc.c:1646 */
+ break;
+
+ case 106:
+#line 408 "config-parser.y" /* yacc.c:1646 */
+ {
+ struct ScannerConf *item, *olditem;
+
+ item = xcalloc(sizeof(*item));
+
+ /* Setup ScannerConf defaults */
+ item->name = xstrdup("undefined");
+
+ if (LIST_SIZE(&ScannerItemList))
+ {
+ olditem = ScannerItemList.tail->data;
+
+ item->vhost = xstrdup(olditem->vhost);
+ item->fd = olditem->fd;
+ item->target_ip = xstrdup(olditem->target_ip);
+ item->target_port = olditem->target_port;
+ item->timeout = olditem->timeout;
+ item->max_read = olditem->max_read;
+ item->target_string_created = 0;
+ memcpy(&item->target_string, &olditem->target_string, sizeof(item->target_string));
+ }
+ else
+ {
+ item->vhost = xstrdup("0.0.0.0");
+ item->fd = 512;
+ item->target_ip = xstrdup("127.0.0.1");
+ item->target_port = 6667;
+ item->timeout = 30;
+ item->max_read = 4096;
+ item->target_string_created = 1;
+ }
+
+ list_add(item, &item->node, &ScannerItemList);
+ tmp = item;
+}
+#line 2056 "config-parser.c" /* yacc.c:1646 */
+ break;
+
+ case 120:
+#line 460 "config-parser.y" /* yacc.c:1646 */
+ {
+ struct ScannerConf *item = tmp;
+
+ xfree(item->name);
+ item->name = xstrdup((yyvsp[-1].string));
+}
+#line 2067 "config-parser.c" /* yacc.c:1646 */
+ break;
+
+ case 121:
+#line 468 "config-parser.y" /* yacc.c:1646 */
+ {
+ struct ScannerConf *item = tmp;
+
+ xfree(item->vhost);
+ item->vhost = xstrdup((yyvsp[-1].string));
+}
+#line 2078 "config-parser.c" /* yacc.c:1646 */
+ break;
+
+ case 122:
+#line 476 "config-parser.y" /* yacc.c:1646 */
+ {
+ struct ScannerConf *item = tmp;
+
+ xfree(item->target_ip);
+ item->target_ip = xstrdup((yyvsp[-1].string));
+}
+#line 2089 "config-parser.c" /* yacc.c:1646 */
+ break;
+
+ case 123:
+#line 484 "config-parser.y" /* yacc.c:1646 */
+ {
+ struct ScannerConf *item = tmp;
+
+ if (item->target_string_created == 0)
+ memset(&item->target_string, 0, sizeof(item->target_string));
+
+ list_add(xstrdup((yyvsp[-1].string)), node_create(), &item->target_string);
+}
+#line 2102 "config-parser.c" /* yacc.c:1646 */
+ break;
+
+ case 124:
+#line 494 "config-parser.y" /* yacc.c:1646 */
+ {
+ struct ScannerConf *item = tmp;
+
+ item->fd = (yyvsp[-1].number);
+}
+#line 2112 "config-parser.c" /* yacc.c:1646 */
+ break;
+
+ case 125:
+#line 501 "config-parser.y" /* yacc.c:1646 */
+ {
+ struct ScannerConf *item = tmp;
+
+ item->target_port = (yyvsp[-1].number);
+}
+#line 2122 "config-parser.c" /* yacc.c:1646 */
+ break;
+
+ case 126:
+#line 508 "config-parser.y" /* yacc.c:1646 */
+ {
+ struct ScannerConf *item = tmp;
+
+ item->timeout = (yyvsp[-1].number);
+}
+#line 2132 "config-parser.c" /* yacc.c:1646 */
+ break;
+
+ case 127:
+#line 515 "config-parser.y" /* yacc.c:1646 */
+ {
+ struct ScannerConf *item = tmp;
+
+ item->max_read = (yyvsp[-1].number);
+}
+#line 2142 "config-parser.c" /* yacc.c:1646 */
+ break;
+
+ case 128:
+#line 522 "config-parser.y" /* yacc.c:1646 */
+ {
+ struct ProtocolConf *item;
+ struct ScannerConf *item2;
+
+ item = xcalloc(sizeof(*item));
+ item->type = (yyvsp[-3].number);
+ item->port = (yyvsp[-1].number);
+
+ item2 = tmp;
+
+ list_add(item, node_create(), &item2->protocols);
+}
+#line 2159 "config-parser.c" /* yacc.c:1646 */
+ break;
+
+ case 137:
+#line 549 "config-parser.y" /* yacc.c:1646 */
+ {
+ xfree(OpmItem.dnsbl_from);
+ OpmItem.dnsbl_from = xstrdup((yyvsp[-1].string));
+}
+#line 2168 "config-parser.c" /* yacc.c:1646 */
+ break;
+
+ case 138:
+#line 555 "config-parser.y" /* yacc.c:1646 */
+ {
+ xfree(OpmItem.dnsbl_to);
+ OpmItem.dnsbl_to = xstrdup((yyvsp[-1].string));
+}
+#line 2177 "config-parser.c" /* yacc.c:1646 */
+ break;
+
+ case 139:
+#line 561 "config-parser.y" /* yacc.c:1646 */
+ {
+ xfree(OpmItem.sendmail);
+ OpmItem.sendmail = xstrdup((yyvsp[-1].string));
+}
+#line 2186 "config-parser.c" /* yacc.c:1646 */
+ break;
+
+ case 140:
+#line 569 "config-parser.y" /* yacc.c:1646 */
+ {
+ struct BlacklistConf *item;
+
+ item = xcalloc(sizeof(*item));
+ item->name = xstrdup("");
+ item->kline = xstrdup("");
+ item->ipv4 = 1;
+ item->ban_unknown = 0;
+ item->type = A_BITMASK;
+
+ list_add(item, node_create(), &OpmItem.blacklists);
+
+ tmp = item;
+}
+#line 2205 "config-parser.c" /* yacc.c:1646 */
+ break;
+
+ case 151:
+#line 597 "config-parser.y" /* yacc.c:1646 */
+ {
+ struct BlacklistConf *item = tmp;
+
+ xfree(item->name);
+ item->name = xstrdup((yyvsp[-1].string));
+}
+#line 2216 "config-parser.c" /* yacc.c:1646 */
+ break;
+
+ case 152:
+#line 605 "config-parser.y" /* yacc.c:1646 */
+ {
+ struct BlacklistConf *item = tmp;
+
+ item->ipv4 = 0;
+ item->ipv6 = 0;
+}
+#line 2227 "config-parser.c" /* yacc.c:1646 */
+ break;
+
+ case 156:
+#line 614 "config-parser.y" /* yacc.c:1646 */
+ {
+ struct BlacklistConf *item = tmp;
+
+ item->ipv4 = 1;
+}
+#line 2237 "config-parser.c" /* yacc.c:1646 */
+ break;
+
+ case 157:
+#line 619 "config-parser.y" /* yacc.c:1646 */
+ {
+ struct BlacklistConf *item = tmp;
+
+ item->ipv6 = 1;
+}
+#line 2247 "config-parser.c" /* yacc.c:1646 */
+ break;
+
+ case 158:
+#line 626 "config-parser.y" /* yacc.c:1646 */
+ {
+ struct BlacklistConf *item = tmp;
+
+ xfree(item->kline);
+ item->kline = xstrdup((yyvsp[-1].string));
+}
+#line 2258 "config-parser.c" /* yacc.c:1646 */
+ break;
+
+ case 159:
+#line 634 "config-parser.y" /* yacc.c:1646 */
+ {
+ struct BlacklistConf *item = tmp;
+
+ if (strcmp("A record bitmask", (yyvsp[-1].string)) == 0)
+ item->type = A_BITMASK;
+ else if (strcmp("A record reply", (yyvsp[-1].string)) == 0)
+ item->type = A_REPLY;
+ else
+ yyerror("Unknown blacklist type defined");
+}
+#line 2273 "config-parser.c" /* yacc.c:1646 */
+ break;
+
+ case 160:
+#line 646 "config-parser.y" /* yacc.c:1646 */
+ {
+ struct BlacklistConf *item = tmp;
+
+ item->ban_unknown = (yyvsp[-1].number);
+}
+#line 2283 "config-parser.c" /* yacc.c:1646 */
+ break;
+
+ case 164:
+#line 658 "config-parser.y" /* yacc.c:1646 */
+ {
+ struct BlacklistReplyConf *item;
+ struct BlacklistConf *blacklist = tmp;
+
+ item = xcalloc(sizeof(*item));
+ item->number = (yyvsp[-3].number);
+ item->type = xstrdup((yyvsp[-1].string));
+
+ list_add(item, node_create(), &blacklist->reply);
+}
+#line 2298 "config-parser.c" /* yacc.c:1646 */
+ break;
+
+ case 170:
+#line 680 "config-parser.y" /* yacc.c:1646 */
+ {
+ list_add(xstrdup((yyvsp[-1].string)), node_create(), &ExemptItem.masks);
+}
+#line 2306 "config-parser.c" /* yacc.c:1646 */
+ break;
+
+
+#line 2310 "config-parser.c" /* yacc.c:1646 */
+ default: break;
+ }
+ /* User semantic actions sometimes alter yychar, and that requires
+ that yytoken be updated with the new translation. We take the
+ approach of translating immediately before every use of yytoken.
+ One alternative is translating here after every semantic action,
+ but that translation would be missed if the semantic action invokes
+ YYABORT, YYACCEPT, or YYERROR immediately after altering yychar or
+ if it invokes YYBACKUP. In the case of YYABORT or YYACCEPT, an
+ incorrect destructor might then be invoked immediately. In the
+ case of YYERROR or YYBACKUP, subsequent parser actions might lead
+ to an incorrect destructor call or verbose syntax error message
+ before the lookahead is translated. */
+ YY_SYMBOL_PRINT ("-> $$ =", yyr1[yyn], &yyval, &yyloc);
+
+ YYPOPSTACK (yylen);
+ yylen = 0;
+ YY_STACK_PRINT (yyss, yyssp);
+
+ *++yyvsp = yyval;
+
+ /* Now 'shift' the result of the reduction. Determine what state
+ that goes to, based on the state we popped back to and the rule
+ number reduced by. */
+
+ yyn = yyr1[yyn];
+
+ yystate = yypgoto[yyn - YYNTOKENS] + *yyssp;
+ if (0 <= yystate && yystate <= YYLAST && yycheck[yystate] == *yyssp)
+ yystate = yytable[yystate];
+ else
+ yystate = yydefgoto[yyn - YYNTOKENS];
+
+ goto yynewstate;
+
+
+/*--------------------------------------.
+| yyerrlab -- here on detecting error. |
+`--------------------------------------*/
+yyerrlab:
+ /* Make sure we have latest lookahead translation. See comments at
+ user semantic actions for why this is necessary. */
+ yytoken = yychar == YYEMPTY ? YYEMPTY : YYTRANSLATE (yychar);
+
+ /* If not already recovering from an error, report this error. */
+ if (!yyerrstatus)
+ {
+ ++yynerrs;
+#if ! YYERROR_VERBOSE
+ yyerror (YY_("syntax error"));
+#else
+# define YYSYNTAX_ERROR yysyntax_error (&yymsg_alloc, &yymsg, \
+ yyssp, yytoken)
+ {
+ char const *yymsgp = YY_("syntax error");
+ int yysyntax_error_status;
+ yysyntax_error_status = YYSYNTAX_ERROR;
+ if (yysyntax_error_status == 0)
+ yymsgp = yymsg;
+ else if (yysyntax_error_status == 1)
+ {
+ if (yymsg != yymsgbuf)
+ YYSTACK_FREE (yymsg);
+ yymsg = (char *) YYSTACK_ALLOC (yymsg_alloc);
+ if (!yymsg)
+ {
+ yymsg = yymsgbuf;
+ yymsg_alloc = sizeof yymsgbuf;
+ yysyntax_error_status = 2;
+ }
+ else
+ {
+ yysyntax_error_status = YYSYNTAX_ERROR;
+ yymsgp = yymsg;
+ }
+ }
+ yyerror (yymsgp);
+ if (yysyntax_error_status == 2)
+ goto yyexhaustedlab;
+ }
+# undef YYSYNTAX_ERROR
+#endif
+ }
+
+
+
+ if (yyerrstatus == 3)
+ {
+ /* If just tried and failed to reuse lookahead token after an
+ error, discard it. */
+
+ if (yychar <= YYEOF)
+ {
+ /* Return failure if at end of input. */
+ if (yychar == YYEOF)
+ YYABORT;
+ }
+ else
+ {
+ yydestruct ("Error: discarding",
+ yytoken, &yylval);
+ yychar = YYEMPTY;
+ }
+ }
+
+ /* Else will try to reuse lookahead token after shifting the error
+ token. */
+ goto yyerrlab1;
+
+
+/*---------------------------------------------------.
+| yyerrorlab -- error raised explicitly by YYERROR. |
+`---------------------------------------------------*/
+yyerrorlab:
+
+ /* Pacify compilers like GCC when the user code never invokes
+ YYERROR and the label yyerrorlab therefore never appears in user
+ code. */
+ if (/*CONSTCOND*/ 0)
+ goto yyerrorlab;
+
+ /* Do not reclaim the symbols of the rule whose action triggered
+ this YYERROR. */
+ YYPOPSTACK (yylen);
+ yylen = 0;
+ YY_STACK_PRINT (yyss, yyssp);
+ yystate = *yyssp;
+ goto yyerrlab1;
+
+
+/*-------------------------------------------------------------.
+| yyerrlab1 -- common code for both syntax error and YYERROR. |
+`-------------------------------------------------------------*/
+yyerrlab1:
+ yyerrstatus = 3; /* Each real token shifted decrements this. */
+
+ for (;;)
+ {
+ yyn = yypact[yystate];
+ if (!yypact_value_is_default (yyn))
+ {
+ yyn += YYTERROR;
+ if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR)
+ {
+ yyn = yytable[yyn];
+ if (0 < yyn)
+ break;
+ }
+ }
+
+ /* Pop the current state because it cannot handle the error token. */
+ if (yyssp == yyss)
+ YYABORT;
+
+
+ yydestruct ("Error: popping",
+ yystos[yystate], yyvsp);
+ YYPOPSTACK (1);
+ yystate = *yyssp;
+ YY_STACK_PRINT (yyss, yyssp);
+ }
+
+ YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
+ *++yyvsp = yylval;
+ YY_IGNORE_MAYBE_UNINITIALIZED_END
+
+
+ /* Shift the error token. */
+ YY_SYMBOL_PRINT ("Shifting", yystos[yyn], yyvsp, yylsp);
+
+ yystate = yyn;
+ goto yynewstate;
+
+
+/*-------------------------------------.
+| yyacceptlab -- YYACCEPT comes here. |
+`-------------------------------------*/
+yyacceptlab:
+ yyresult = 0;
+ goto yyreturn;
+
+/*-----------------------------------.
+| yyabortlab -- YYABORT comes here. |
+`-----------------------------------*/
+yyabortlab:
+ yyresult = 1;
+ goto yyreturn;
+
+#if !defined yyoverflow || YYERROR_VERBOSE
+/*-------------------------------------------------.
+| yyexhaustedlab -- memory exhaustion comes here. |
+`-------------------------------------------------*/
+yyexhaustedlab:
+ yyerror (YY_("memory exhausted"));
+ yyresult = 2;
+ /* Fall through. */
+#endif
+
+yyreturn:
+ if (yychar != YYEMPTY)
+ {
+ /* Make sure we have latest lookahead translation. See comments at
+ user semantic actions for why this is necessary. */
+ yytoken = YYTRANSLATE (yychar);
+ yydestruct ("Cleanup: discarding lookahead",
+ yytoken, &yylval);
+ }
+ /* Do not reclaim the symbols of the rule whose action triggered
+ this YYABORT or YYACCEPT. */
+ YYPOPSTACK (yylen);
+ YY_STACK_PRINT (yyss, yyssp);
+ while (yyssp != yyss)
+ {
+ yydestruct ("Cleanup: popping",
+ yystos[*yyssp], yyvsp);
+ YYPOPSTACK (1);
+ }
+#ifndef yyoverflow
+ if (yyss != yyssa)
+ YYSTACK_FREE (yyss);
+#endif
+#if YYERROR_VERBOSE
+ if (yymsg != yymsgbuf)
+ YYSTACK_FREE (yymsg);
+#endif
+ return yyresult;
+}
+#line 684 "config-parser.y" /* yacc.c:1906 */
+
diff --git a/src/config-parser.h b/src/config-parser.h
new file mode 100644
index 0000000..8a02091
--- /dev/null
+++ b/src/config-parser.h
@@ -0,0 +1,209 @@
+/* A Bison parser, made by GNU Bison 3.0.4. */
+
+/* Bison interface for Yacc-like parsers in C
+
+ Copyright (C) 1984, 1989-1990, 2000-2015 Free Software Foundation, Inc.
+
+ 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 3 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, see <http://www.gnu.org/licenses/>. */
+
+/* As a special exception, you may create a larger work that contains
+ part or all of the Bison parser skeleton and distribute that work
+ under terms of your choice, so long as that work isn't itself a
+ parser generator using the skeleton or a modified version thereof
+ as a parser skeleton. Alternatively, if you modify or redistribute
+ the parser skeleton itself, you may (at your option) remove this
+ special exception, which will cause the skeleton and the resulting
+ Bison output files to be licensed under the GNU General Public
+ License without this special exception.
+
+ This special exception was added by the Free Software Foundation in
+ version 2.2 of Bison. */
+
+#ifndef YY_YY_CONFIG_PARSER_H_INCLUDED
+# define YY_YY_CONFIG_PARSER_H_INCLUDED
+/* Debug traces. */
+#ifndef YYDEBUG
+# define YYDEBUG 0
+#endif
+#if YYDEBUG
+extern int yydebug;
+#endif
+
+/* Token type. */
+#ifndef YYTOKENTYPE
+# define YYTOKENTYPE
+ enum yytokentype
+ {
+ ADDRESS_FAMILY = 258,
+ AWAY = 259,
+ BAN_UNKNOWN = 260,
+ BLACKLIST = 261,
+ BYTES = 262,
+ KBYTES = 263,
+ MBYTES = 264,
+ CHANNEL = 265,
+ COMMAND_INTERVAL = 266,
+ COMMAND_QUEUE_SIZE = 267,
+ COMMAND_TIMEOUT = 268,
+ CONNREGEX = 269,
+ DNS_FDLIMIT = 270,
+ DNS_TIMEOUT = 271,
+ DNSBL_FROM = 272,
+ DNSBL_TO = 273,
+ EXEMPT = 274,
+ FD = 275,
+ INVITE = 276,
+ IPV4 = 277,
+ IPV6 = 278,
+ IRC = 279,
+ KLINE = 280,
+ KEY = 281,
+ MASK = 282,
+ MAX_READ = 283,
+ MODE = 284,
+ NAME = 285,
+ NEGCACHE = 286,
+ NEGCACHE_REBUILD = 287,
+ NICK = 288,
+ NICKSERV = 289,
+ NOTICE = 290,
+ OPER = 291,
+ OPM = 292,
+ OPTIONS = 293,
+ PASSWORD = 294,
+ PERFORM = 295,
+ PIDFILE = 296,
+ PORT = 297,
+ PROTOCOL = 298,
+ READTIMEOUT = 299,
+ REALNAME = 300,
+ RECONNECTINTERVAL = 301,
+ REPLY = 302,
+ SCANLOG = 303,
+ SCANNER = 304,
+ SECONDS = 305,
+ MINUTES = 306,
+ HOURS = 307,
+ DAYS = 308,
+ WEEKS = 309,
+ MONTHS = 310,
+ YEARS = 311,
+ SENDMAIL = 312,
+ SERVER = 313,
+ TARGET_IP = 314,
+ TARGET_PORT = 315,
+ TARGET_STRING = 316,
+ TIMEOUT = 317,
+ TYPE = 318,
+ USERNAME = 319,
+ USER = 320,
+ VHOST = 321,
+ NUMBER = 322,
+ STRING = 323,
+ PROTOCOLTYPE = 324
+ };
+#endif
+/* Tokens. */
+#define ADDRESS_FAMILY 258
+#define AWAY 259
+#define BAN_UNKNOWN 260
+#define BLACKLIST 261
+#define BYTES 262
+#define KBYTES 263
+#define MBYTES 264
+#define CHANNEL 265
+#define COMMAND_INTERVAL 266
+#define COMMAND_QUEUE_SIZE 267
+#define COMMAND_TIMEOUT 268
+#define CONNREGEX 269
+#define DNS_FDLIMIT 270
+#define DNS_TIMEOUT 271
+#define DNSBL_FROM 272
+#define DNSBL_TO 273
+#define EXEMPT 274
+#define FD 275
+#define INVITE 276
+#define IPV4 277
+#define IPV6 278
+#define IRC 279
+#define KLINE 280
+#define KEY 281
+#define MASK 282
+#define MAX_READ 283
+#define MODE 284
+#define NAME 285
+#define NEGCACHE 286
+#define NEGCACHE_REBUILD 287
+#define NICK 288
+#define NICKSERV 289
+#define NOTICE 290
+#define OPER 291
+#define OPM 292
+#define OPTIONS 293
+#define PASSWORD 294
+#define PERFORM 295
+#define PIDFILE 296
+#define PORT 297
+#define PROTOCOL 298
+#define READTIMEOUT 299
+#define REALNAME 300
+#define RECONNECTINTERVAL 301
+#define REPLY 302
+#define SCANLOG 303
+#define SCANNER 304
+#define SECONDS 305
+#define MINUTES 306
+#define HOURS 307
+#define DAYS 308
+#define WEEKS 309
+#define MONTHS 310
+#define YEARS 311
+#define SENDMAIL 312
+#define SERVER 313
+#define TARGET_IP 314
+#define TARGET_PORT 315
+#define TARGET_STRING 316
+#define TIMEOUT 317
+#define TYPE 318
+#define USERNAME 319
+#define USER 320
+#define VHOST 321
+#define NUMBER 322
+#define STRING 323
+#define PROTOCOLTYPE 324
+
+/* Value type. */
+#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
+
+union YYSTYPE
+{
+#line 91 "config-parser.y" /* yacc.c:1909 */
+
+ int number;
+ char *string;
+
+#line 197 "config-parser.h" /* yacc.c:1909 */
+};
+
+typedef union YYSTYPE YYSTYPE;
+# define YYSTYPE_IS_TRIVIAL 1
+# define YYSTYPE_IS_DECLARED 1
+#endif
+
+
+extern YYSTYPE yylval;
+
+int yyparse (void);
+
+#endif /* !YY_YY_CONFIG_PARSER_H_INCLUDED */
diff --git a/src/config-parser.y b/src/config-parser.y
new file mode 100644
index 0000000..f1c04db
--- /dev/null
+++ b/src/config-parser.y
@@ -0,0 +1,684 @@
+/*
+ * Copyright (c) 2002-2003 Erik Fears
+ * Copyright (c) 2014-2018 ircd-hybrid 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 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
+ * USA
+ */
+
+%{
+#include <string.h>
+
+#include "memory.h"
+#include "config.h"
+
+int yylex(void);
+
+static void *tmp; /* Variable to temporarily hold nodes before insertion to list */
+
+%}
+
+%token ADDRESS_FAMILY
+%token AWAY
+%token BAN_UNKNOWN
+%token BLACKLIST
+%token BYTES KBYTES MBYTES
+%token CHANNEL
+%token COMMAND_INTERVAL
+%token COMMAND_QUEUE_SIZE
+%token COMMAND_TIMEOUT
+%token CONNREGEX
+%token DNS_FDLIMIT
+%token DNS_TIMEOUT
+%token DNSBL_FROM
+%token DNSBL_TO
+%token EXEMPT
+%token FD
+%token INVITE
+%token IPV4
+%token IPV6
+%token IRC
+%token KLINE
+%token KEY
+%token MASK
+%token MAX_READ
+%token MODE
+%token NAME
+%token NEGCACHE
+%token NEGCACHE_REBUILD
+%token NICK
+%token NICKSERV
+%token NOTICE
+%token OPER
+%token OPM
+%token OPTIONS
+%token PASSWORD
+%token PERFORM
+%token PIDFILE
+%token PORT
+%token PROTOCOL
+%token READTIMEOUT
+%token REALNAME
+%token RECONNECTINTERVAL
+%token REPLY
+%token SCANLOG
+%token SCANNER
+%token SECONDS MINUTES HOURS DAYS WEEKS MONTHS YEARS
+%token SENDMAIL
+%token SERVER
+%token TARGET_IP
+%token TARGET_PORT
+%token TARGET_STRING
+%token TIMEOUT
+%token TYPE
+%token USERNAME
+%token USER
+%token VHOST
+
+%union
+{
+ int number;
+ char *string;
+}
+
+%token <number> NUMBER
+%token <string> STRING
+%token <number> PROTOCOLTYPE
+%type <number> timespec
+%type <number> timespec_
+%type <number> sizespec
+%type <number> sizespec_
+
+%%
+
+config:
+ | config config_items
+ ;
+
+config_items: irc_entry |
+ options_entry |
+ opm_entry |
+ user_entry |
+ scanner_entry |
+ exempt_entry;
+
+timespec_: { $$ = 0; } | timespec;
+timespec: NUMBER timespec_ { $$ = $1 + $2; } |
+ NUMBER SECONDS timespec_ { $$ = $1 + $3; } |
+ NUMBER MINUTES timespec_ { $$ = $1 * 60 + $3; } |
+ NUMBER HOURS timespec_ { $$ = $1 * 60 * 60 + $3; } |
+ NUMBER DAYS timespec_ { $$ = $1 * 60 * 60 * 24 + $3; } |
+ NUMBER WEEKS timespec_ { $$ = $1 * 60 * 60 * 24 * 7 + $3; } |
+ NUMBER MONTHS timespec_ { $$ = $1 * 60 * 60 * 24 * 7 * 4 + $3; } |
+ NUMBER YEARS timespec_ { $$ = $1 * 60 * 60 * 24 * 365 + $3; }
+ ;
+
+sizespec_: { $$ = 0; } | sizespec;
+sizespec: NUMBER sizespec_ { $$ = $1 + $2; } |
+ NUMBER BYTES sizespec_ { $$ = $1 + $3; } |
+ NUMBER KBYTES sizespec_ { $$ = $1 * 1024 + $3; } |
+ NUMBER MBYTES sizespec_ { $$ = $1 * 1024 * 1024 + $3; }
+ ;
+
+
+/*************************** OPTIONS BLOCK ***********************/
+options_entry: OPTIONS '{' options_items '}' ';';
+
+options_items: options_items options_item |
+ options_item;
+
+options_item: options_negcache |
+ options_negcache_rebuild |
+ options_pidfile |
+ options_dns_fdlimit |
+ options_dns_timeout |
+ options_scanlog |
+ options_command_queue_size |
+ options_command_interval |
+ options_command_timeout |
+ error;
+
+options_negcache: NEGCACHE '=' timespec ';'
+{
+ OptionsItem.negcache = $3;
+};
+
+options_negcache_rebuild: NEGCACHE_REBUILD '=' timespec ';'
+{
+ OptionsItem.negcache_rebuild = $3;
+};
+
+options_pidfile: PIDFILE '=' STRING ';'
+{
+ xfree(OptionsItem.pidfile);
+ OptionsItem.pidfile = xstrdup($3);
+};
+
+options_dns_fdlimit: DNS_FDLIMIT '=' NUMBER ';'
+{
+ OptionsItem.dns_fdlimit = $3;
+};
+
+options_dns_timeout: DNS_TIMEOUT '=' timespec ';'
+{
+ OptionsItem.dns_timeout = $3;
+};
+
+options_scanlog: SCANLOG '=' STRING ';'
+{
+ xfree(OptionsItem.scanlog);
+ OptionsItem.scanlog = xstrdup($3);
+};
+
+options_command_queue_size: COMMAND_QUEUE_SIZE '=' NUMBER ';'
+{
+ OptionsItem.command_queue_size = $3;
+};
+
+options_command_interval: COMMAND_INTERVAL '=' timespec ';'
+{
+ OptionsItem.command_interval = $3;
+};
+
+options_command_timeout: COMMAND_TIMEOUT '=' timespec ';'
+{
+ OptionsItem.command_timeout = $3;
+};
+
+
+/*************************** IRC BLOCK ***************************/
+irc_entry: IRC '{' irc_items '}' ';';
+
+irc_items: irc_items irc_item |
+ irc_item;
+
+irc_item: irc_away |
+ irc_connregex |
+ irc_kline |
+ irc_nick |
+ irc_nickserv |
+ irc_mode |
+ irc_oper |
+ irc_password |
+ irc_port |
+ irc_readtimeout |
+ irc_reconnectinterval |
+ irc_realname |
+ irc_server |
+ irc_username |
+ irc_vhost |
+ irc_perform |
+ irc_notice |
+ channel_entry |
+ error;
+
+irc_away: AWAY '=' STRING ';'
+{
+ xfree(IRCItem.away);
+ IRCItem.away = xstrdup($3);
+};
+
+irc_kline: KLINE '=' STRING ';'
+{
+ xfree(IRCItem.kline);
+ IRCItem.kline = xstrdup($3);
+};
+
+irc_mode: MODE '=' STRING ';'
+{
+ xfree(IRCItem.mode);
+ IRCItem.mode = xstrdup($3);
+};
+
+irc_nick: NICK '=' STRING ';'
+{
+ xfree(IRCItem.nick);
+ IRCItem.nick = xstrdup($3);
+};
+
+irc_nickserv: NICKSERV '=' STRING ';'
+{
+ xfree(IRCItem.nickserv);
+ IRCItem.nickserv = xstrdup($3);
+};
+
+irc_oper: OPER '=' STRING ';'
+{
+ xfree(IRCItem.oper);
+ IRCItem.oper = xstrdup($3);
+};
+
+irc_password: PASSWORD '=' STRING ';'
+{
+ xfree(IRCItem.password);
+ IRCItem.password = xstrdup($3);
+};
+
+irc_perform: PERFORM '=' STRING ';'
+{
+ list_add(xstrdup($3), node_create(), &IRCItem.performs);
+};
+
+irc_notice: NOTICE '=' STRING ';'
+{
+ list_add(xstrdup($3), node_create(), &IRCItem.notices);
+};
+
+irc_port: PORT '=' NUMBER ';'
+{
+ IRCItem.port = $3;
+};
+
+irc_readtimeout: READTIMEOUT '=' timespec ';'
+{
+ IRCItem.readtimeout = $3;
+};
+
+irc_reconnectinterval: RECONNECTINTERVAL '=' timespec ';'
+{
+ IRCItem.reconnectinterval = $3;
+};
+
+irc_realname: REALNAME '=' STRING ';'
+{
+ xfree(IRCItem.realname);
+ IRCItem.realname = xstrdup($3);
+};
+
+irc_server: SERVER '=' STRING ';'
+{
+ xfree(IRCItem.server);
+ IRCItem.server = xstrdup($3);
+};
+
+irc_username: USERNAME '=' STRING ';'
+{
+ xfree(IRCItem.username);
+ IRCItem.username = xstrdup($3);
+};
+
+irc_vhost: VHOST '=' STRING ';'
+{
+ xfree(IRCItem.vhost);
+ IRCItem.vhost = xstrdup($3);
+};
+
+irc_connregex: CONNREGEX '=' STRING ';'
+{
+ xfree(IRCItem.connregex);
+ IRCItem.connregex = xstrdup($3);
+};
+
+
+/************************** CHANNEL BLOCK *************************/
+channel_entry:
+{
+ struct ChannelConf *item;
+
+ item = xcalloc(sizeof(*item));
+ item->name = xstrdup("");
+ item->key = xstrdup("");
+ item->invite = xstrdup("");
+
+ list_add(item, &item->node, &IRCItem.channels);
+ tmp = item;
+}
+CHANNEL '{' channel_items '}' ';';
+
+channel_items: channel_items channel_item |
+ channel_item;
+
+channel_item: channel_name |
+ channel_key |
+ channel_invite;
+
+channel_name: NAME '=' STRING ';'
+{
+ struct ChannelConf *item = tmp;
+
+ xfree(item->name);
+ item->name = xstrdup($3);
+};
+
+channel_key: KEY '=' STRING ';'
+{
+ struct ChannelConf *item = tmp;
+
+ xfree(item->key);
+ item->key = xstrdup($3);
+};
+
+channel_invite: INVITE '=' STRING ';'
+{
+ struct ChannelConf *item = tmp;
+
+ xfree(item->invite);
+ item->invite = xstrdup($3);
+};
+
+
+/*************************** USER BLOCK ***************************/
+user_entry:
+{
+ struct UserConf *item;
+
+ item = xcalloc(sizeof(*item));
+
+ list_add(item, &item->node, &UserItemList);
+ tmp = item;
+}
+USER '{' user_items '}' ';' ;
+
+user_items: user_items user_item |
+ user_item;
+
+user_item: user_mask |
+ user_scanner |
+ error;
+
+user_mask: MASK '=' STRING ';'
+{
+ struct UserConf *item = tmp;
+
+ list_add(xstrdup($3), node_create(), &item->masks);
+};
+
+user_scanner: SCANNER '=' STRING ';'
+{
+ struct UserConf *item = tmp;
+
+ list_add(xstrdup($3), node_create(), &item->scanners);
+};
+
+
+/*************************** SCANNER BLOCK ***************************/
+scanner_entry:
+{
+ struct ScannerConf *item, *olditem;
+
+ item = xcalloc(sizeof(*item));
+
+ /* Setup ScannerConf defaults */
+ item->name = xstrdup("undefined");
+
+ if (LIST_SIZE(&ScannerItemList))
+ {
+ olditem = ScannerItemList.tail->data;
+
+ item->vhost = xstrdup(olditem->vhost);
+ item->fd = olditem->fd;
+ item->target_ip = xstrdup(olditem->target_ip);
+ item->target_port = olditem->target_port;
+ item->timeout = olditem->timeout;
+ item->max_read = olditem->max_read;
+ item->target_string_created = 0;
+ memcpy(&item->target_string, &olditem->target_string, sizeof(item->target_string));
+ }
+ else
+ {
+ item->vhost = xstrdup("0.0.0.0");
+ item->fd = 512;
+ item->target_ip = xstrdup("127.0.0.1");
+ item->target_port = 6667;
+ item->timeout = 30;
+ item->max_read = 4096;
+ item->target_string_created = 1;
+ }
+
+ list_add(item, &item->node, &ScannerItemList);
+ tmp = item;
+}
+SCANNER '{' scanner_items '}' ';' ;
+
+scanner_items: scanner_items scanner_item |
+ scanner_item;
+
+scanner_item: scanner_name |
+ scanner_vhost |
+ scanner_fd |
+ scanner_target_ip |
+ scanner_target_port |
+ scanner_target_string |
+ scanner_protocol |
+ scanner_timeout |
+ scanner_max_read |
+ error;
+
+scanner_name: NAME '=' STRING ';'
+{
+ struct ScannerConf *item = tmp;
+
+ xfree(item->name);
+ item->name = xstrdup($3);
+};
+
+scanner_vhost: VHOST '=' STRING ';'
+{
+ struct ScannerConf *item = tmp;
+
+ xfree(item->vhost);
+ item->vhost = xstrdup($3);
+};
+
+scanner_target_ip: TARGET_IP '=' STRING ';'
+{
+ struct ScannerConf *item = tmp;
+
+ xfree(item->target_ip);
+ item->target_ip = xstrdup($3);
+};
+
+scanner_target_string: TARGET_STRING '=' STRING ';'
+{
+ struct ScannerConf *item = tmp;
+
+ if (item->target_string_created == 0)
+ memset(&item->target_string, 0, sizeof(item->target_string));
+
+ list_add(xstrdup($3), node_create(), &item->target_string);
+};
+
+scanner_fd: FD '=' NUMBER ';'
+{
+ struct ScannerConf *item = tmp;
+
+ item->fd = $3;
+};
+
+scanner_target_port: TARGET_PORT '=' NUMBER ';'
+{
+ struct ScannerConf *item = tmp;
+
+ item->target_port = $3;
+};
+
+scanner_timeout: TIMEOUT '=' timespec ';'
+{
+ struct ScannerConf *item = tmp;
+
+ item->timeout = $3;
+};
+
+scanner_max_read: MAX_READ '=' sizespec ';'
+{
+ struct ScannerConf *item = tmp;
+
+ item->max_read = $3;
+};
+
+scanner_protocol: PROTOCOL '=' PROTOCOLTYPE ':' NUMBER ';'
+{
+ struct ProtocolConf *item;
+ struct ScannerConf *item2;
+
+ item = xcalloc(sizeof(*item));
+ item->type = $3;
+ item->port = $5;
+
+ item2 = tmp;
+
+ list_add(item, node_create(), &item2->protocols);
+};
+
+
+/*************************** OPM BLOCK ***************************/
+opm_entry: OPM '{' opm_items '}' ';' ;
+
+opm_items: opm_items opm_item |
+ opm_item;
+
+opm_item: opm_dnsbl_from |
+ opm_dnsbl_to |
+ opm_sendmail |
+ opm_blacklist_entry |
+ error;
+
+opm_dnsbl_from: DNSBL_FROM '=' STRING ';'
+{
+ xfree(OpmItem.dnsbl_from);
+ OpmItem.dnsbl_from = xstrdup($3);
+};
+
+opm_dnsbl_to: DNSBL_TO '=' STRING ';'
+{
+ xfree(OpmItem.dnsbl_to);
+ OpmItem.dnsbl_to = xstrdup($3);
+};
+
+opm_sendmail: SENDMAIL '=' STRING ';'
+{
+ xfree(OpmItem.sendmail);
+ OpmItem.sendmail = xstrdup($3);
+};
+
+
+/************************** BLACKLIST BLOCK *************************/
+opm_blacklist_entry:
+{
+ struct BlacklistConf *item;
+
+ item = xcalloc(sizeof(*item));
+ item->name = xstrdup("");
+ item->kline = xstrdup("");
+ item->ipv4 = 1;
+ item->ban_unknown = 0;
+ item->type = A_BITMASK;
+
+ list_add(item, node_create(), &OpmItem.blacklists);
+
+ tmp = item;
+}
+BLACKLIST '{' blacklist_items '}' ';';
+
+blacklist_items: blacklist_items blacklist_item |
+ blacklist_item;
+
+blacklist_item: blacklist_name |
+ blacklist_address_family |
+ blacklist_type |
+ blacklist_kline |
+ blacklist_ban_unknown |
+ blacklist_reply |
+ error;
+
+blacklist_name: NAME '=' STRING ';'
+{
+ struct BlacklistConf *item = tmp;
+
+ xfree(item->name);
+ item->name = xstrdup($3);
+};
+
+blacklist_address_family: ADDRESS_FAMILY
+{
+ struct BlacklistConf *item = tmp;
+
+ item->ipv4 = 0;
+ item->ipv6 = 0;
+} '=' blacklist_address_family_items ';' ;
+
+blacklist_address_family_items: blacklist_address_family_items ',' blacklist_address_family_item | blacklist_address_family_item;
+blacklist_address_family_item: IPV4
+{
+ struct BlacklistConf *item = tmp;
+
+ item->ipv4 = 1;
+} | IPV6
+{
+ struct BlacklistConf *item = tmp;
+
+ item->ipv6 = 1;
+};
+
+blacklist_kline: KLINE '=' STRING ';'
+{
+ struct BlacklistConf *item = tmp;
+
+ xfree(item->kline);
+ item->kline = xstrdup($3);
+};
+
+blacklist_type: TYPE '=' STRING ';'
+{
+ struct BlacklistConf *item = tmp;
+
+ if (strcmp("A record bitmask", $3) == 0)
+ item->type = A_BITMASK;
+ else if (strcmp("A record reply", $3) == 0)
+ item->type = A_REPLY;
+ else
+ yyerror("Unknown blacklist type defined");
+};
+
+blacklist_ban_unknown: BAN_UNKNOWN '=' NUMBER ';'
+{
+ struct BlacklistConf *item = tmp;
+
+ item->ban_unknown = $3;
+};
+
+blacklist_reply: REPLY '{' blacklist_reply_items '}' ';';
+
+blacklist_reply_items: blacklist_reply_items blacklist_reply_item |
+ blacklist_reply_item;
+
+blacklist_reply_item: NUMBER '=' STRING ';'
+{
+ struct BlacklistReplyConf *item;
+ struct BlacklistConf *blacklist = tmp;
+
+ item = xcalloc(sizeof(*item));
+ item->number = $1;
+ item->type = xstrdup($3);
+
+ list_add(item, node_create(), &blacklist->reply);
+};
+
+
+/*************************** EXEMPT BLOCK ***************************/
+exempt_entry: EXEMPT '{' exempt_items '}' ';' ;
+
+exempt_items: exempt_items exempt_item |
+ exempt_item;
+
+exempt_item: exempt_mask |
+ error;
+
+exempt_mask: MASK '=' STRING ';'
+{
+ list_add(xstrdup($3), node_create(), &ExemptItem.masks);
+};
+
+%%
diff --git a/src/config.c b/src/config.c
new file mode 100644
index 0000000..f42522c
--- /dev/null
+++ b/src/config.c
@@ -0,0 +1,107 @@
+/*
+ * Copyright (c) 2002 Erik Fears
+ * Copyright (c) 2014-2018 ircd-hybrid 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 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
+ * USA
+ */
+
+#include "setup.h"
+
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "config.h"
+#include "config-parser.h"
+#include "compat.h"
+#include "memory.h"
+#include "log.h"
+#include "scan.h"
+#include "irc.h"
+#include "opercmd.h"
+#include "stats.h"
+#include "firedns.h"
+#include "misc.h"
+
+
+FILE *conf_file;
+struct OptionsConf OptionsItem;
+struct IRCConf IRCItem;
+struct OpmConf OpmItem;
+struct ExemptConf ExemptItem;
+list_t UserItemList;
+list_t ScannerItemList;
+
+
+/* Setup structs that hold configuration data and then reset default values */
+static void
+config_setup(void)
+{
+ /* Setup irc {} block defaults */
+ IRCItem.mode = xstrdup("+c");
+ IRCItem.nick = xstrdup("hopm");
+ IRCItem.port = 6667;
+ IRCItem.readtimeout = 900;
+ IRCItem.reconnectinterval = 30;
+ IRCItem.oper = xstrdup("undefined");
+ IRCItem.username = xstrdup("hopm");
+ IRCItem.realname = xstrdup("Hybrid Open Proxy Monitor");
+ IRCItem.server = xstrdup("irc.example.org");
+ IRCItem.connregex = xstrdup("\\*\\*\\* Notice -- Client connecting: ([^ ]+) \\(([^@]+)@([^\\)]+)\\) \\[([0-9a-f\\.:]+)\\].*");
+ IRCItem.kline = xstrdup("KLINE %u@%h :Open Proxy found on your host.");
+
+ /* Setup options {} block defaults */
+ OptionsItem.command_queue_size = 64;
+ OptionsItem.command_interval = 10;
+ OptionsItem.command_timeout = 180;
+ OptionsItem.negcache = 0; /* 0 disabled negcache */
+ OptionsItem.negcache_rebuild = 43200;
+ OptionsItem.pidfile = xstrdup("hopm.pid");
+ OptionsItem.dns_fdlimit = 50;
+ OptionsItem.dns_timeout = 5;
+}
+
+/* Load configuration from filename, via flex/bison parser */
+void
+config_load(const char *filename)
+{
+ config_setup(); /* Setup/clear current configuration */
+
+ log_printf("CONFIG -> Loading %s", filename);
+
+ strlcpy(conffilebuf, filename, sizeof(conffilebuf));
+
+ if ((conf_file = fopen(filename, "r")) == NULL)
+ {
+ log_printf("CONFIG -> Error opening %s: %s", filename, strerror(errno));
+ exit(EXIT_FAILURE);
+ }
+
+ yyparse();
+ fclose(conf_file);
+
+ scan_init(); /* Initialize the scanners once we have the configuration */
+ stats_init(); /* Initialize stats (UPTIME) */
+ firedns_init(); /* Initialize adns */
+}
+
+void
+yyerror(const char *str)
+{
+ log_printf("CONFIG -> \"%s\", line %u: %s: %s", conffilebuf, lineno, str, stripws(linebuf));
+ exit(EXIT_FAILURE);
+}
diff --git a/src/config.h b/src/config.h
new file mode 100644
index 0000000..af83a0e
--- /dev/null
+++ b/src/config.h
@@ -0,0 +1,153 @@
+/*
+ * Copyright (c) 2002 Erik Fears
+ * Copyright (c) 2014-2018 ircd-hybrid 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 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
+ * USA
+ */
+
+#ifndef CONFIG_H
+#define CONFIG_H
+
+#include <stdio.h>
+#include <time.h>
+
+#include "list.h"
+
+extern char linebuf[512];
+extern char conffilebuf[512];
+extern unsigned int lineno;
+extern FILE *conf_file;
+
+struct IRCConf
+{
+ char *nick;
+ char *username;
+ char *realname;
+ char *server;
+ int port;
+ time_t readtimeout;
+ time_t reconnectinterval;
+ char *password;
+ char *vhost;
+ char *nickserv;
+ char *oper;
+ char *mode;
+ char *away;
+ char *connregex;
+ char *kline;
+ list_t channels; /* List of ChannelConf */
+ list_t performs; /* List of char * */
+ list_t notices; /* List of char * */
+};
+
+struct ChannelConf
+{
+ node_t node; /**< List node; linked into IRCItem->channels */
+ char *name;
+ char *key;
+ char *invite;
+};
+
+struct OptionsConf
+{
+ unsigned int command_queue_size;
+ time_t command_interval;
+ time_t command_timeout;
+ time_t negcache;
+ time_t negcache_rebuild;
+ unsigned int dns_fdlimit;
+ time_t dns_timeout;
+ char *pidfile;
+ char *scanlog;
+};
+
+struct UserConf
+{
+ node_t node; /**< List node; linked into UserItemList */
+ list_t masks; /* List of char * */
+ list_t scanners; /* List of char * */
+};
+
+struct ScannerConf
+{
+ node_t node; /**< List node; linked into ScannerItemList */
+ char *name;
+ list_t protocols;
+ char *vhost;
+ int fd;
+ char *target_ip;
+ int target_port;
+ int timeout;
+ int max_read;
+ list_t target_string;
+ int target_string_created;
+};
+
+struct ProtocolConf
+{
+ int type;
+ unsigned int port;
+};
+
+struct OpmConf
+{
+ list_t blacklists;
+ char *dnsbl_from;
+ char *dnsbl_to;
+ char *sendmail;
+};
+
+enum BlacklistType
+{
+ A_BITMASK = 1,
+ A_REPLY
+};
+
+struct BlacklistConf
+{
+ char *name;
+ char *kline;
+ enum BlacklistType type;
+ unsigned int ipv4;
+ unsigned int ipv6;
+ int ban_unknown;
+ list_t reply;
+ unsigned int stats_recv;
+};
+
+struct BlacklistReplyConf
+{
+ unsigned char number;
+ char *type;
+};
+
+struct ExemptConf
+{
+ list_t masks;
+};
+
+
+/* Extern to actual config data declared in config.c */
+extern struct IRCConf IRCItem;
+extern struct OptionsConf OptionsItem;
+extern struct OpmConf OpmItem;
+extern struct ExemptConf ExemptItem;
+extern list_t UserItemList;
+extern list_t ScannerItemList;
+
+extern void yyerror(const char *);
+extern void config_load(const char *);
+#endif /* CONFIG_H */
diff --git a/src/dnsbl.c b/src/dnsbl.c
new file mode 100644
index 0000000..4973842
--- /dev/null
+++ b/src/dnsbl.c
@@ -0,0 +1,300 @@
+/*
+ * Copyright (c) 2002-2003 Erik Fears
+ * Copyright (c) 2014-2018 ircd-hybrid 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 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
+ * USA
+ */
+
+#include "setup.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netdb.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <assert.h>
+
+#include "compat.h"
+#include "config.h"
+#include "dnsbl.h"
+#include "list.h"
+#include "log.h"
+#include "main.h"
+#include "match.h"
+#include "memory.h"
+#include "scan.h"
+#include "irc.h"
+#include "stats.h"
+
+
+/*
+ * Work out the DNSBL zones and send the dns query
+ */
+void
+dnsbl_add(struct scan_struct *ss)
+{
+ char lookup[128];
+ node_t *node;
+ struct addrinfo hints, *addr_res;
+
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_family = PF_UNSPEC;
+ hints.ai_flags = AI_NUMERICHOST;
+
+ if (getaddrinfo(ss->ip, NULL, &hints, &addr_res))
+ {
+ log_printf("DNSBL -> Invalid address '%s', ignoring.", ss->ip);
+ return;
+ }
+
+ LIST_FOREACH(node, OpmItem.blacklists.head)
+ {
+ struct BlacklistConf *bl = node->data;
+
+ if (addr_res->ai_family == AF_INET && bl->ipv4)
+ {
+ const struct sockaddr_in *v4 = (const struct sockaddr_in *)addr_res->ai_addr;
+ const uint8_t *b = (const uint8_t *)&v4->sin_addr.s_addr;
+
+ snprintf(lookup, sizeof(lookup), "%u.%u.%u.%u.%s",
+ (unsigned int)(b[3]), (unsigned int)(b[2]),
+ (unsigned int)(b[1]), (unsigned int)(b[0]), bl->name);
+ }
+ else if (addr_res->ai_family == AF_INET6 && bl->ipv6)
+ {
+ const struct sockaddr_in6 *v6 = (const struct sockaddr_in6 *)addr_res->ai_addr;
+ const uint8_t *b = (const uint8_t *)&v6->sin6_addr.s6_addr;
+
+ snprintf(lookup, sizeof(lookup),
+ "%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x."
+ "%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%s",
+ (unsigned int)(b[15] & 0xF), (unsigned int)(b[15] >> 4),
+ (unsigned int)(b[14] & 0xF), (unsigned int)(b[14] >> 4),
+ (unsigned int)(b[13] & 0xF), (unsigned int)(b[13] >> 4),
+ (unsigned int)(b[12] & 0xF), (unsigned int)(b[12] >> 4),
+ (unsigned int)(b[11] & 0xF), (unsigned int)(b[11] >> 4),
+ (unsigned int)(b[10] & 0xF), (unsigned int)(b[10] >> 4),
+ (unsigned int)(b[9] & 0xF), (unsigned int)(b[9] >> 4),
+ (unsigned int)(b[8] & 0xF), (unsigned int)(b[8] >> 4),
+ (unsigned int)(b[7] & 0xF), (unsigned int)(b[7] >> 4),
+ (unsigned int)(b[6] & 0xF), (unsigned int)(b[6] >> 4),
+ (unsigned int)(b[5] & 0xF), (unsigned int)(b[5] >> 4),
+ (unsigned int)(b[4] & 0xF), (unsigned int)(b[4] >> 4),
+ (unsigned int)(b[3] & 0xF), (unsigned int)(b[3] >> 4),
+ (unsigned int)(b[2] & 0xF), (unsigned int)(b[2] >> 4),
+ (unsigned int)(b[1] & 0xF), (unsigned int)(b[1] >> 4),
+ (unsigned int)(b[0] & 0xF), (unsigned int)(b[0] >> 4), bl->name);
+ }
+ else
+ continue;
+
+ struct dnsbl_scan *ds = xcalloc(sizeof *ds);
+ ds->ss = ss;
+ ds->bl = bl;
+
+ if (OPT_DEBUG)
+ log_printf("DNSBL -> Passed '%s' to resolver", lookup);
+
+ int res = firedns_getip(FDNS_QRY_A, lookup, ds);
+ if (res == -1 && firedns_errno != FDNS_ERR_FDLIMIT)
+ {
+ log_printf("DNSBL -> Error sending dns lookup for '%s': %s", lookup, firedns_strerror(firedns_errno));
+ xfree(ds);
+ }
+ else
+ ++ss->scans; /* Increase scan count - one for each blacklist */
+ }
+
+ freeaddrinfo(addr_res);
+}
+
+static void
+dnsbl_positive(struct scan_struct *ss, struct BlacklistConf *bl, unsigned char type)
+{
+ char text_type[128] = "";
+ node_t *node;
+
+ if (bl->type == A_BITMASK)
+ {
+ LIST_FOREACH(node, bl->reply.head)
+ {
+ const struct BlacklistReplyConf *item = node->data;
+
+ if (item->number & type)
+ {
+ strlcat(text_type, item->type, sizeof(text_type));
+ strlcat(text_type, ", ", sizeof(text_type));
+ }
+ }
+
+ if (text_type[0])
+ *(strrchr(text_type, ',')) = '\0';
+ }
+ else
+ {
+ LIST_FOREACH(node, bl->reply.head)
+ {
+ const struct BlacklistReplyConf *item = node->data;
+
+ if (item->number == type)
+ {
+ strlcpy(text_type, item->type, sizeof(text_type));
+ break;
+ }
+ }
+ }
+
+ if (text_type[0] == '\0' && bl->ban_unknown == 0)
+ {
+ if (OPT_DEBUG)
+ log_printf("DNSBL -> Unknown result from BL zone %s (%d)", bl->name, type);
+
+ return;
+ }
+
+ if (ss->manual_target)
+ irc_send("PRIVMSG %s :CHECK -> DNSBL -> %s appears in BL zone %s (%s)",
+ ss->manual_target, ss->ip, bl->name, text_type);
+ else if (ss->positive == 0)
+ {
+ /* Only report it if no other scans have found positives yet. */
+ scan_positive(ss, (EmptyString(bl->kline) ? IRCItem.kline : bl->kline), text_type);
+
+ irc_send_channels("DNSBL -> %s!%s@%s [%s] appears in BL zone %s (%s)",
+ ss->irc_nick, ss->irc_username, ss->irc_hostname, ss->ip, bl->name,
+ text_type);
+ log_printf("DNSBL -> %s!%s@%s [%s] appears in BL zone %s (%s)",
+ ss->irc_nick, ss->irc_username, ss->irc_hostname, ss->ip, bl->name,
+ text_type);
+ }
+
+ /* Record stat */
+ stats_dnsblrecv(bl);
+}
+
+void
+dnsbl_result(struct firedns_result *res)
+{
+ struct dnsbl_scan *const ds = res->info;
+
+ if (OPT_DEBUG)
+ {
+ if (ds->ss->manual_target)
+ log_printf("DNSBL -> Lookup result for %s (%s) %d.%d.%d.%d (error: %d)",
+ ds->ss->ip,
+ res->lookup,
+ (unsigned char)res->text[0],
+ (unsigned char)res->text[1],
+ (unsigned char)res->text[2],
+ (unsigned char)res->text[3], firedns_errno);
+ else
+ log_printf("DNSBL -> Lookup result for %s!%s@%s (%s) %d.%d.%d.%d (error: %d)",
+ ds->ss->irc_nick,
+ ds->ss->irc_username,
+ ds->ss->irc_hostname,
+ res->lookup,
+ (unsigned char)res->text[0],
+ (unsigned char)res->text[1],
+ (unsigned char)res->text[2],
+ (unsigned char)res->text[3], firedns_errno);
+ }
+
+ /* Everything is OK */
+ if (res->text[0] == '\0' && firedns_errno == FDNS_ERR_NXDOMAIN)
+ {
+ if (ds->ss->manual_target)
+ irc_send("PRIVMSG %s :CHECK -> DNSBL -> %s does not appear in BL zone %s",
+ ds->ss->manual_target, ds->ss->ip, ds->bl->name);
+
+ --ds->ss->scans; /* We are done with ss here */
+ scan_checkfinished(ds->ss); /* This could free ss, don't use ss after this point */
+ xfree(ds); /* No longer need our information */
+ return;
+ }
+
+ /* Either an error, or a positive lookup */
+ if (firedns_errno == FDNS_ERR_NONE)
+ dnsbl_positive(ds->ss, ds->bl, (unsigned char)res->text[3]);
+ else
+ {
+ log_printf("DNSBL -> Lookup error on %s: %s", res->lookup,
+ firedns_strerror(firedns_errno));
+
+ if (firedns_errno != FDNS_ERR_TIMEOUT)
+ irc_send_channels("DNSBL -> Lookup error on %s: %s", res->lookup,
+ firedns_strerror(firedns_errno));
+ }
+
+ /* Check if ss has any remaining scans */
+ --ds->ss->scans; /* We are done with ss here */
+ scan_checkfinished(ds->ss); /* This could free ss, don't use ss after this point */
+ xfree(ds); /* Finished with dnsbl_scan too */
+}
+
+void
+dnsbl_cycle(void)
+{
+ firedns_cycle();
+}
+
+/*
+ * Send an email to report this open proxy.
+ */
+void
+dnsbl_report(const struct scan_struct *ss)
+{
+ char buf[2048], cmdbuf[256];
+ FILE *fp;
+
+ assert(ss->ip);
+
+ if (EmptyString(OpmItem.dnsbl_to) || EmptyString(OpmItem.dnsbl_from) || EmptyString(OpmItem.sendmail))
+ return;
+
+ snprintf(cmdbuf, sizeof(cmdbuf), "%s -t", OpmItem.sendmail);
+ snprintf(buf, sizeof(buf),
+ "From: %s <%s>\n"
+ "To: %s\n"
+ "Subject: HOPM Report\n"
+ "X-HOPM-Version: %s\n\n"
+ "%s: %s:%d\n\n"
+ "%s\n", IRCItem.nick, OpmItem.dnsbl_from, OpmItem.dnsbl_to,
+ VERSION, scan_gettype(ss->remote->protocol), ss->ip,
+ ss->remote->port, ss->proof);
+
+ if (OPT_DEBUG >= 3)
+ log_printf("DNSBL -> Sending following email:\n%s\n", buf);
+
+ if ((fp = popen(cmdbuf, "w")) == NULL)
+ {
+ log_printf("DNSBL -> Failed to create pipe to '%s' for email report!", cmdbuf);
+ irc_send_channels("I was trying to create a pipe to '%s' to send a DNSBL "
+ "report, and it failed! I'll give up for now.",
+ cmdbuf);
+ return;
+ }
+
+ fputs(buf, fp);
+ pclose(fp);
+
+ log_printf("DNSBL -> Sent report to %s [%s]", OpmItem.dnsbl_to, ss->ip);
+
+ /* Record send in stats */
+ stats_dnsblsend();
+}
diff --git a/src/dnsbl.h b/src/dnsbl.h
new file mode 100644
index 0000000..f468214
--- /dev/null
+++ b/src/dnsbl.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2002-2003 Erik Fears
+ * Copyright (c) 2014-2018 ircd-hybrid 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 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
+ * USA
+ */
+
+#ifndef DNSBL_H
+#define DNSBL_H
+
+#include "firedns.h"
+#include "scan.h"
+
+
+struct dnsbl_scan
+{
+ struct scan_struct *ss;
+ struct BlacklistConf *bl;
+};
+
+extern void dnsbl_add(struct scan_struct *);
+extern void dnsbl_result(struct firedns_result *);
+extern void dnsbl_cycle(void);
+extern void dnsbl_report(const struct scan_struct *);
+#endif
diff --git a/src/firedns.c b/src/firedns.c
new file mode 100644
index 0000000..bcee5da
--- /dev/null
+++ b/src/firedns.c
@@ -0,0 +1,881 @@
+/*
+firedns.c - firedns library
+Copyright (C) 2002 Ian Gulliver
+
+This file has been gutted and mucked with for use in BOPM - see the
+real library at http://ares.penguinhosting.net/~ian/ before you judge
+firedns based on this..
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of version 2 of the GNU General Public License as
+published by the Free Software Foundation.
+
+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 <stdlib.h>
+#include <time.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <poll.h>
+#include <sys/time.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <errno.h>
+#include <fcntl.h>
+
+#include "compat.h"
+#include "memory.h"
+#include "firedns.h"
+#include "config.h"
+#include "list.h"
+#include "log.h"
+#include "dnsbl.h"
+
+#define FIREDNS_TRIES 3
+
+int firedns_errno = FDNS_ERR_NONE;
+
+/* Variables local to this file */
+static unsigned int firedns_fdinuse;
+
+/* up to FDNS_MAX nameservers; populated by firedns_init() */
+static struct in_addr servers4[FDNS_MAX];
+static struct in6_addr servers6[FDNS_MAX];
+
+/* actual count of nameservers; set by firedns_init() */
+static unsigned int i4;
+static unsigned int i6;
+
+/*
+ * Linked list of open DNS queries; populated by firedns_add_query(),
+ * decimated by firedns_getresult()
+ */
+static list_t CONNECTIONS;
+
+/*
+ * List of errors, in order of values used in FDNS_ERR_*, returned by
+ * firedns_strerror
+ */
+static const char *const errors[] =
+{
+ [FDNS_ERR_NONE] = "Success",
+ [FDNS_ERR_FORMAT] = "Format error",
+ [FDNS_ERR_SERVFAIL] = "Server failure",
+ [FDNS_ERR_NXDOMAIN] = "Name error",
+ [FDNS_ERR_NOIMPT] = "Not implemented",
+ [FDNS_ERR_REFUSED] = "Refused",
+ [FDNS_ERR_TIMEOUT] = "Timeout",
+ [FDNS_ERR_NETWORK] = "Network error",
+ [FDNS_ERR_FDLIMIT] = "FD Limit reached",
+ [FDNS_ERR_OTHER] = "Unknown error"
+};
+
+/* Structures */
+
+/* open DNS query */
+struct s_connection
+{
+ node_t node; /**< List node; linked into CONNECTIONS */
+
+ /*
+ * unique ID (random number), matches header ID; both set by
+ * firedns_add_query()
+ */
+ unsigned char id[2];
+ uint16_t class;
+ uint16_t type;
+
+ /* file descriptor returned from sockets */
+ int fd;
+ void *info;
+ time_t start;
+ char lookup[256];
+ int v6;
+};
+
+struct s_rr_middle
+{
+ uint16_t type;
+ uint16_t class;
+
+ /* XXX - firedns depends on this being 4 bytes */
+ uint32_t ttl;
+ uint16_t rdlength;
+};
+
+/* DNS query header */
+struct s_header
+{
+ unsigned char id[2];
+ unsigned char flags1;
+#define FLAGS1_MASK_QR 0x80
+/* bitshift right 3 */
+#define FLAGS1_MASK_OPCODE 0x78
+#define FLAGS1_MASK_AA 0x04
+#define FLAGS1_MASK_TC 0x02
+#define FLAGS1_MASK_RD 0x01
+
+ unsigned char flags2;
+#define FLAGS2_MASK_RA 0x80
+#define FLAGS2_MASK_Z 0x70
+#define FLAGS2_MASK_RCODE 0x0f
+
+ uint16_t qdcount;
+ uint16_t ancount;
+ uint16_t nscount;
+ uint16_t arcount;
+
+ /* DNS question, populated by firedns_build_query_payload() */
+ unsigned char payload[512];
+};
+
+/* Function prototypes */
+static struct s_connection *firedns_add_query(void);
+static int firedns_doquery(struct s_connection *);
+static int firedns_build_query_payload(const char *const, uint16_t, uint16_t, unsigned char *);
+static int firedns_send_requests(struct s_header *, struct s_connection *, int);
+
+
+void
+firedns_init(void)
+{
+ /*
+ * populates servers4 (or -6) struct with up to FDNS_MAX nameserver IP
+ * addresses from /etc/firedns.conf (or /etc/resolv.conf)
+ */
+ FILE *f;
+ struct in_addr addr4;
+ struct in6_addr addr6;
+ char buf[1024];
+ char *p = NULL;
+
+ i6 = 0;
+ i4 = 0;
+
+ srand((unsigned int)time(NULL));
+ memset(servers4, 0, sizeof(servers4));
+ memset(servers6, 0, sizeof(servers6));
+
+ /* read etc/firedns.conf if we've got it, otherwise parse /etc/resolv.conf */
+ f = fopen(FDNS_CONFIG_PREF, "r");
+
+ if (f == NULL)
+ {
+ f = fopen(FDNS_CONFIG_FBCK, "r");
+
+ if (f == NULL)
+ {
+ log_printf("Unable to open %s", FDNS_CONFIG_FBCK);
+ return;
+ }
+
+ while (fgets(buf, sizeof(buf), f))
+ {
+ if ((p = strchr(buf, '\n')))
+ *p = '\0';
+
+ if (strncmp(buf, "nameserver", 10) == 0)
+ {
+ unsigned int i = 10;
+
+ while (buf[i] == ' ' || buf[i] == '\t')
+ ++i;
+
+ if (i6 < FDNS_MAX)
+ {
+ if (inet_pton(AF_INET6, &buf[i], &addr6) > 0)
+ {
+ memcpy(&servers6[i6++], &addr6, sizeof(struct in6_addr));
+ continue;
+ }
+ }
+
+ if (i4 < FDNS_MAX)
+ {
+ if (inet_pton(AF_INET, &buf[i], &addr4) > 0)
+ memcpy(&servers4[i4++], &addr4, sizeof(struct in_addr));
+ }
+ }
+ }
+ }
+ else
+ {
+ while (fgets(buf, sizeof(buf), f))
+ {
+ if ((p = strchr(buf, '\n')))
+ *p = '\0';
+
+ if (i6 < FDNS_MAX)
+ {
+ if (inet_pton(AF_INET6, buf, &addr6) > 0)
+ {
+ memcpy(&servers6[i6++], &addr6, sizeof(struct in6_addr));
+ continue;
+ }
+ }
+
+ if (i4 < FDNS_MAX)
+ {
+ if (inet_pton(AF_INET, buf, &addr4) > 0)
+ memcpy(&servers4[i4++], &addr4, sizeof(struct in_addr));
+ }
+ }
+ }
+
+ fclose(f);
+}
+
+/*
+ * These little hacks are here to avoid alignment and type sizing issues completely by doing manual copies
+ */
+static inline void
+firedns_fill_rr(struct s_rr_middle *restrict const rr, const unsigned char *const restrict input)
+{
+ rr->type = input[0] * 256 + input[1];
+ rr->class = input[2] * 256 + input[3];
+ rr->ttl = input[4] * 16777216 + input[5] * 65536 + input[6] * 256 + input[7];
+ rr->rdlength = input[8] * 256 + input[9];
+}
+
+static inline void
+firedns_fill_header(struct s_header *const restrict header, const unsigned char *const restrict input, const int l)
+{
+ header->id[0] = input[0];
+ header->id[1] = input[1];
+ header->flags1 = input[2];
+ header->flags2 = input[3];
+ header->qdcount = input[4] * 256 + input[5];
+ header->ancount = input[6] * 256 + input[7];
+ header->nscount = input[8] * 256 + input[9];
+ header->arcount = input[10] * 256 + input[11];
+ memcpy(header->payload, &input[12], l);
+}
+
+static inline void
+firedns_empty_header(unsigned char *const restrict output, const struct s_header *const restrict header, const int l)
+{
+ output[0] = header->id[0];
+ output[1] = header->id[1];
+ output[2] = header->flags1;
+ output[3] = header->flags2;
+ output[4] = header->qdcount / 256;
+ output[5] = header->qdcount % 256;
+ output[6] = header->ancount / 256;
+ output[7] = header->ancount % 256;
+ output[8] = header->nscount / 256;
+ output[9] = header->nscount % 256;
+ output[10] = header->arcount / 256;
+ output[11] = header->arcount % 256;
+ memcpy(&output[12], header->payload, l);
+}
+
+/* immediate A query */
+struct in_addr *
+firedns_resolveip4(const char *const name)
+{
+ static struct in_addr addr;
+
+ if (inet_pton(AF_INET, name, &addr) > 0)
+ return &addr;
+
+ return firedns_resolveip(FDNS_QRY_A, name);
+}
+
+/* immediate AAAA query */
+struct in6_addr *
+firedns_resolveip6(const char *const name)
+{
+ static struct in6_addr addr;
+
+ if (inet_pton(AF_INET6, name, &addr) > 0)
+ return &addr;
+
+ return firedns_resolveip(FDNS_QRY_AAAA, name);
+}
+
+/* resolve a query of a given type */
+void *
+firedns_resolveip(int type, const char *const name)
+{
+ struct firedns_result *result;
+ struct timeval tv;
+ fd_set s;
+
+ for (unsigned int t = 0; t < FIREDNS_TRIES; ++t)
+ {
+ int fd = firedns_getip(type, name, NULL);
+ if (fd == -1)
+ return NULL;
+
+ tv.tv_sec = 5;
+ tv.tv_usec = 0;
+ FD_ZERO(&s);
+ FD_SET(fd, &s);
+ select(fd + 1, &s, NULL, NULL, &tv);
+
+ result = firedns_getresult(fd);
+
+ if (firedns_errno == FDNS_ERR_NONE)
+ /*
+ * Return is from static memory in getresult, so there is no need to
+ * copy it until the next call to firedns.
+ */
+ return result->text;
+ else if (firedns_errno == FDNS_ERR_NXDOMAIN)
+ return NULL;
+ }
+
+ if (firedns_errno == FDNS_ERR_NONE)
+ firedns_errno = FDNS_ERR_TIMEOUT;
+
+ return NULL;
+}
+
+/*
+ * build, add and send specified query; retrieve result with
+ * firedns_getresult()
+ */
+int
+firedns_getip(int type, const char *const name, void *info)
+{
+ struct s_connection *s;
+
+ s = firedns_add_query();
+ s->class = 1;
+ s->type = type;
+ s->info = info;
+ strlcpy(s->lookup, name, sizeof(s->lookup));
+
+ if (firedns_fdinuse >= OptionsItem.dns_fdlimit)
+ {
+ firedns_errno = FDNS_ERR_FDLIMIT;
+
+ /* Don't add to queue if there is no info */
+ if (info == NULL)
+ xfree(s);
+ else
+ list_add(s, &s->node, &CONNECTIONS);
+
+ return -1;
+ }
+
+ int fd = firedns_doquery(s);
+ if (fd == -1)
+ {
+ xfree(s);
+ return -1;
+ }
+
+ list_add(s, &s->node, &CONNECTIONS);
+
+ return fd;
+}
+
+/* build DNS query, add to list */
+static struct s_connection *
+firedns_add_query(void)
+{
+ struct s_connection *s;
+
+ /* create new connection object */
+ s = xcalloc(sizeof(*s));
+
+ /* verified by firedns_getresult() */
+ s->id[0] = rand() % 255;
+ s->id[1] = rand() % 255;
+ s->fd = -1;
+
+ return s;
+}
+
+static int
+firedns_doquery(struct s_connection *s)
+{
+ struct s_header h;
+
+ int len = firedns_build_query_payload(s->lookup, s->type, 1, (unsigned char *)&h.payload);
+ if (len == -1)
+ {
+ firedns_errno = FDNS_ERR_FORMAT;
+ return -1;
+ }
+
+ return firedns_send_requests(&h, s, len);
+}
+
+/*
+ * populate payload with query: name= question, rr= record type
+ */
+static int
+firedns_build_query_payload(const char *const name, uint16_t rr, uint16_t class,
+ unsigned char *payload)
+{
+ int16_t payloadpos = 0;
+ const char *tempchr, *tempchr2;
+ uint16_t l;
+
+ tempchr2 = name;
+
+ /* split name up into labels, create query */
+ while ((tempchr = strchr(tempchr2, '.')))
+ {
+ l = tempchr - tempchr2;
+
+ if (payloadpos + l + 1 > 507)
+ return -1;
+
+ payload[payloadpos++] = l;
+ memcpy(&payload[payloadpos], tempchr2, l);
+ payloadpos += l;
+ tempchr2 = &tempchr[1];
+ }
+
+ l = strlen(tempchr2);
+
+ if (l)
+ {
+ if (payloadpos + l + 2 > 507)
+ return -1;
+
+ payload[payloadpos++] = l;
+ memcpy(&payload[payloadpos], tempchr2, l);
+ payloadpos += l;
+ payload[payloadpos++] = '\0';
+ }
+
+ if (payloadpos > 508)
+ return -1;
+
+ l = htons(rr);
+ memcpy(&payload[payloadpos], &l, 2);
+
+ l = htons(class);
+ memcpy(&payload[payloadpos + 2], &l, 2);
+
+ return payloadpos + 4;
+}
+
+/* send DNS query */
+static int
+firedns_send_requests(struct s_header *h, struct s_connection *s, int l)
+{
+ int sent_ok = 0;
+ struct sockaddr_in addr4;
+ struct sockaddr_in6 addr6;
+ unsigned char payload[sizeof(struct s_header)];
+
+ /* set header flags */
+ h->id[0] = s->id[0];
+ h->id[1] = s->id[1];
+ h->flags1 = 0 | FLAGS1_MASK_RD;
+ h->flags2 = 0;
+ h->qdcount = 1;
+ h->ancount = 0;
+ h->nscount = 0;
+ h->arcount = 0;
+
+ /* try to create ipv6 or ipv4 socket */
+ s->v6 = 0;
+
+ if (i6 > 0)
+ {
+ s->fd = socket(AF_INET6, SOCK_DGRAM, 0);
+
+ if (s->fd != -1)
+ {
+ if (fcntl(s->fd, F_SETFL, O_NONBLOCK))
+ {
+ close(s->fd);
+ s->fd = -1;
+ }
+ }
+
+ if (s->fd != -1)
+ {
+ memset(&addr6, 0, sizeof(addr6));
+ addr6.sin6_family = AF_INET6;
+
+ if (bind(s->fd, (struct sockaddr *)&addr6, sizeof(addr6)) == 0)
+ s->v6 = 1;
+ else
+ close(s->fd);
+ }
+ }
+
+ if (s->v6 == 0)
+ {
+ s->fd = socket(AF_INET, SOCK_DGRAM, 0);
+
+ if (s->fd != -1)
+ {
+ if (fcntl(s->fd, F_SETFL, O_NONBLOCK))
+ {
+ close(s->fd);
+ s->fd = -1;
+ }
+ }
+
+ if (s->fd != -1)
+ {
+ memset(&addr4, 0, sizeof(addr4));
+ addr4.sin_family = AF_INET;
+ addr4.sin_port = 0;
+ addr4.sin_addr.s_addr = INADDR_ANY;
+
+ if (bind(s->fd, (struct sockaddr *)&addr4, sizeof(addr4)) != 0)
+ {
+ close(s->fd);
+ s->fd = -1;
+ }
+ }
+
+ if (s->fd == -1)
+ {
+ firedns_errno = FDNS_ERR_NETWORK;
+ return -1;
+ }
+ }
+
+ firedns_empty_header(payload, h, l);
+
+ /* if we've got ipv6 support, an ip v6 socket, and ipv6 servers, send to them */
+ if (i6 > 0 && s->v6 == 1)
+ {
+ for (unsigned int i = 0; i < i6; ++i)
+ {
+ memset(&addr6, 0, sizeof(addr6));
+ memcpy(&addr6.sin6_addr, &servers6[i], sizeof(addr6.sin6_addr));
+
+ addr6.sin6_family = AF_INET6;
+ addr6.sin6_port = htons(FDNS_PORT);
+
+ if (sendto(s->fd, payload, l + 12, 0, (struct sockaddr *)&addr6, sizeof(addr6)) > 0)
+ sent_ok = 1;
+ }
+ }
+
+ for (unsigned int i = 0; i < i4; ++i)
+ {
+ /* send via ipv4-over-ipv6 if we've got an ipv6 socket */
+ if (s->v6 == 1)
+ {
+ memset(&addr6, 0, sizeof(addr6));
+ memcpy(addr6.sin6_addr.s6_addr, "\0\0\0\0\0\0\0\0\0\0\xff\xff", 12);
+ memcpy(&addr6.sin6_addr.s6_addr[12], &servers4[i].s_addr, 4);
+ addr6.sin6_family = AF_INET6;
+ addr6.sin6_port = htons(FDNS_PORT);
+
+ if (sendto(s->fd, payload, l + 12, 0, (struct sockaddr *)&addr6, sizeof(addr6)) > 0)
+ sent_ok = 1;
+
+ continue;
+ }
+
+ /* otherwise send via standard ipv4 boringness */
+ memset(&addr4, 0, sizeof(addr4));
+ memcpy(&addr4.sin_addr, &servers4[i], sizeof(addr4.sin_addr));
+ addr4.sin_family = AF_INET;
+ addr4.sin_port = htons(FDNS_PORT);
+
+ if (sendto(s->fd, payload, l + 12, 0, (struct sockaddr *)&addr4, sizeof(addr4)) > 0)
+ sent_ok = 1;
+ }
+
+ if (!sent_ok)
+ {
+ close(s->fd);
+ s->fd = -1;
+ firedns_errno = FDNS_ERR_NETWORK;
+ return -1;
+ }
+
+ time(&s->start);
+ firedns_fdinuse++;
+ firedns_errno = FDNS_ERR_NONE;
+
+ return s->fd;
+}
+
+/* retrieve result of DNS query */
+struct firedns_result *
+firedns_getresult(const int fd)
+{
+ static struct firedns_result result;
+ struct s_header h;
+ struct s_connection *c;
+ node_t *node;
+ int l, i, q, curanswer;
+ struct s_rr_middle rr = { .rdlength = 0 };
+ unsigned char buffer[sizeof(struct s_header)];
+
+ firedns_errno = FDNS_ERR_OTHER;
+ result.info = NULL;
+
+ memset(result.text, 0, sizeof(result.text));
+
+ /* Find query in list of dns lookups */
+ LIST_FOREACH(node, CONNECTIONS.head)
+ {
+ c = node->data;
+
+ if (c->fd == fd)
+ break;
+ else
+ c = NULL;
+ }
+
+ /* query not found */
+ if (c == NULL)
+ return &result;
+
+ /* query found -- we remove in cleanup */
+ l = recv(c->fd, buffer, sizeof(struct s_header), 0);
+
+ result.info = c->info;
+ strlcpy(result.lookup, c->lookup, sizeof(result.lookup));
+
+ if (l == -1)
+ {
+ firedns_errno = FDNS_ERR_NETWORK;
+ goto cleanup;
+ }
+
+ if (l < 12)
+ goto cleanup;
+
+ firedns_fill_header(&h, buffer, l - 12);
+
+ if (c->id[0] != h.id[0] || c->id[1] != h.id[1])
+ /*
+ * ID mismatch: we keep the connection, as this could be an answer to
+ * a previous lookup..
+ */
+ return NULL;
+
+ if ((h.flags1 & FLAGS1_MASK_QR) == 0)
+ goto cleanup;
+
+ if ((h.flags1 & FLAGS1_MASK_OPCODE) != 0)
+ goto cleanup;
+
+ if ((h.flags2 & FLAGS2_MASK_RCODE) != 0)
+ {
+ firedns_errno = (h.flags2 & FLAGS2_MASK_RCODE);
+ goto cleanup;
+ }
+
+ if (h.ancount < 1)
+ {
+ firedns_errno = FDNS_ERR_NXDOMAIN;
+ /* no sense going on if we don't have any answers */
+ goto cleanup;
+ }
+
+ /* skip queries */
+ i = 0;
+ q = 0;
+ l -= 12;
+
+ while (q < h.qdcount && i < l)
+ {
+ if (h.payload[i] > 63)
+ {
+ /* pointer */
+ i += 6; /* skip pointer, class and type */
+ q++;
+ }
+ else
+ {
+ /* label */
+ if (h.payload[i] == 0)
+ {
+ q++;
+ i += 5; /* skip nil, class and type */
+ }
+ else
+ i += h.payload[i] + 1; /* skip length and label */
+ }
+ }
+
+ /* &h.payload[i] should now be the start of the first response */
+ curanswer = 0;
+
+ while (curanswer < h.ancount)
+ {
+ q = 0;
+
+ while (q == 0 && i < l)
+ {
+ if (h.payload[i] > 63)
+ {
+ /* pointer */
+ i += 2; /* skip pointer */
+ q = 1;
+ }
+ else
+ {
+ /* label */
+ if (h.payload[i] == 0)
+ {
+ i++;
+ q = 1;
+ }
+ else
+ i += h.payload[i] + 1; /* skip length and label */
+ }
+ }
+
+ if (l - i < 10)
+ goto cleanup;
+
+ firedns_fill_rr(&rr, &h.payload[i]);
+ i += 10;
+
+ if (rr.type != c->type)
+ {
+ curanswer++;
+ i += rr.rdlength;
+ continue;
+ }
+
+ if (rr.class != c->class)
+ {
+ curanswer++;
+ i += rr.rdlength;
+ continue;
+ }
+
+ break;
+ }
+
+ if (curanswer == h.ancount)
+ goto cleanup;
+ if (i + rr.rdlength > l)
+ goto cleanup;
+ if (rr.rdlength > 1023)
+ goto cleanup;
+
+ firedns_errno = FDNS_ERR_NONE;
+ memcpy(result.text, &h.payload[i], rr.rdlength);
+ result.text[rr.rdlength] = '\0';
+
+/* Clean-up */
+cleanup:
+ list_remove(&c->node, &CONNECTIONS);
+
+ close(c->fd);
+ xfree(c);
+ firedns_fdinuse--;
+
+ return &result;
+}
+
+void
+firedns_cycle(void)
+{
+ node_t *node, *node_next;
+ struct s_connection *p;
+ struct firedns_result *res, new_result;
+ static struct pollfd *ufds = NULL;
+ unsigned int size = 0;
+ time_t timenow;
+
+ if (LIST_SIZE(&CONNECTIONS) == 0)
+ return;
+
+ if (ufds == NULL)
+ ufds = xcalloc(sizeof(*ufds) * OptionsItem.dns_fdlimit);
+
+ time(&timenow);
+
+ LIST_FOREACH_SAFE(node, node_next, CONNECTIONS.head)
+ {
+ if (size >= OptionsItem.dns_fdlimit)
+ break;
+
+ p = node->data;
+
+ if (p->fd < 0)
+ continue;
+
+ if (p->fd > 0 && (p->start + OptionsItem.dns_timeout) < timenow)
+ {
+ /* Timed out - remove from list */
+ list_remove(&p->node, &CONNECTIONS);
+
+ memset(new_result.text, 0, sizeof(new_result.text));
+ new_result.info = p->info;
+ strlcpy(new_result.lookup, p->lookup, sizeof(new_result.lookup));
+
+ close(p->fd);
+ xfree(p);
+ firedns_fdinuse--;
+
+ firedns_errno = FDNS_ERR_TIMEOUT;
+
+ if (new_result.info)
+ dnsbl_result(&new_result);
+
+ continue;
+ }
+
+ ufds[size].events = 0;
+ ufds[size].revents = 0;
+ ufds[size].fd = p->fd;
+ ufds[size].events = POLLIN;
+
+ ++size;
+ }
+
+ switch (poll(ufds, size, 0))
+ {
+ case -1:
+ case 0:
+ return;
+ }
+
+ LIST_FOREACH_SAFE(node, node_next, CONNECTIONS.head)
+ {
+ p = node->data;
+
+ if (p->fd > 0)
+ {
+ for (unsigned int i = 0; i < size; ++i)
+ {
+ if ((ufds[i].revents & POLLIN) && ufds[i].fd == p->fd)
+ {
+ res = firedns_getresult(p->fd);
+
+ if (res && res->info)
+ dnsbl_result(res);
+
+ break;
+ }
+ }
+ }
+ else if (firedns_fdinuse < OptionsItem.dns_fdlimit)
+ firedns_doquery(p);
+ }
+}
+
+const char *
+firedns_strerror(int error)
+{
+ if (error == FDNS_ERR_NETWORK)
+ return strerror(errno);
+
+ return errors[error];
+}
diff --git a/src/firedns.h b/src/firedns.h
new file mode 100644
index 0000000..e48e263
--- /dev/null
+++ b/src/firedns.h
@@ -0,0 +1,86 @@
+/*
+firedns.h - firedns library declarations
+Copyright (C) 2002 Ian Gulliver
+
+This file has been edited for use in BOPM - see the real library at
+http://ares.penguinhosting.net/~ian/ before you judge firedns based
+on this..
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of version 2 of the GNU General Public License as
+published by the Free Software Foundation.
+
+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
+*/
+
+#ifndef _FIREDNS_H
+#define _FIREDNS_H
+
+/* max number of nameservers used */
+#define FDNS_MAX 8
+/* preferred firedns config file */
+#define FDNS_CONFIG_PREF HOPM_ETCDIR "/firedns.conf"
+/* fallback config file */
+#define FDNS_CONFIG_FBCK "/etc/resolv.conf"
+/* DNS well known port */
+#define FDNS_PORT 53
+/* name to IPv4 address */
+#define FDNS_QRY_A 1
+/* name to IPv6 address */
+#define FDNS_QRY_AAAA 28
+
+/* Success */
+#define FDNS_ERR_NONE 0
+/* Format error */
+#define FDNS_ERR_FORMAT 1
+/* Server failure */
+#define FDNS_ERR_SERVFAIL 2
+/* Name error */
+#define FDNS_ERR_NXDOMAIN 3
+/* Not implemented */
+#define FDNS_ERR_NOIMPT 4
+/* Refused */
+#define FDNS_ERR_REFUSED 5
+
+/* Local error codes */
+
+/* Timeout */
+#define FDNS_ERR_TIMEOUT 6
+/* Network error */
+#define FDNS_ERR_NETWORK 7
+/* FD Limit reached */
+#define FDNS_ERR_FDLIMIT 8
+/* Other error */
+#define FDNS_ERR_OTHER 9
+
+/* Used with the above error values */
+extern int firedns_errno;
+
+struct firedns_result
+{
+ char text[1024];
+ char lookup[256];
+ void *info;
+};
+
+/* non-blocking functions */
+extern int firedns_getip(int, const char *const, void *);
+extern struct firedns_result *firedns_getresult(const int);
+
+/* low-timeout blocking functions */
+extern void *firedns_resolveip(int, const char *const);
+extern struct in_addr *firedns_resolveip4(const char *const);
+extern struct in6_addr *firedns_resolveip6(const char *const);
+
+extern void firedns_init(void);
+extern void firedns_cycle(void);
+extern const char *firedns_strerror(int);
+
+#endif
diff --git a/src/irc.c b/src/irc.c
new file mode 100644
index 0000000..8027660
--- /dev/null
+++ b/src/irc.c
@@ -0,0 +1,912 @@
+/*
+ * Copyright (c) 2002-2003 Erik Fears
+ * Copyright (c) 2014-2018 ircd-hybrid 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 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
+ * USA
+ */
+
+#include "setup.h"
+
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netdb.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <poll.h>
+#include <time.h>
+#include <errno.h>
+#include <stdarg.h>
+#include <regex.h>
+#include <assert.h>
+
+#include "config.h"
+#include "irc.h"
+#include "log.h"
+#include "opercmd.h"
+#include "scan.h"
+#include "dnsbl.h"
+#include "stats.h"
+#include "options.h"
+#include "match.h"
+#include "compat.h"
+#include "negcache.h"
+#include "memory.h"
+#include "main.h"
+#include "serno.h"
+
+
+/*
+ * Certain variables we don't want to allocate memory for over and over
+ * again so global scope is given.
+ */
+static char IRC_RAW[MSGLENMAX]; /* Buffer to read data into */
+static unsigned int IRC_RAW_LEN; /* Position of IRC_RAW */
+static int IRC_FD = -1; /* File descriptor for IRC client */
+
+static struct sockaddr_storage IRC_SVR; /* Sock Address Struct for IRC server */
+static socklen_t svr_addrlen;
+static time_t IRC_LAST; /* Last full line of data from irc server */
+static time_t IRC_LASTRECONNECT; /* Time of last reconnection */
+
+
+/* get_channel
+ *
+ * Check if a channel is defined in our conf. If so return
+ * a pointer to it.
+ *
+ * Parameters:
+ * channel: channel to search conf for
+ *
+ * Return: Pointer to ChannelConf containing the channel
+ */
+static const struct ChannelConf *
+get_channel(const char *name)
+{
+ node_t *node;
+
+ LIST_FOREACH(node, IRCItem.channels.head)
+ {
+ struct ChannelConf *item = node->data;
+
+ if (strcasecmp(item->name, name) == 0)
+ return item;
+ }
+
+ return NULL;
+}
+
+/* m_perform
+ *
+ * actions to perform on IRC connection
+ *
+ * Parameters:
+ * parv[0] = source
+ * parv[1] = PING
+ * parv[2] = PING TS/Package
+ *
+ * source_p: UserInfo struct of the source user, or NULL if
+ * the source (parv[0]) is a server.
+ */
+static void
+m_perform(char *parv[], unsigned int parc, const char *msg, const char *source_p)
+{
+ node_t *node;
+
+ log_printf("IRC -> Connected to %s/%d", IRCItem.server, IRCItem.port);
+
+ /* Identify to nickserv if needed */
+ if (!EmptyString(IRCItem.nickserv))
+ irc_send("%s", IRCItem.nickserv);
+
+ /* Oper */
+ irc_send("OPER %s", IRCItem.oper);
+
+ /* Set modes */
+ irc_send("MODE %s %s", IRCItem.nick, IRCItem.mode);
+
+ /* Set Away */
+ if (!EmptyString(IRCItem.away))
+ irc_send("AWAY :%s", IRCItem.away);
+
+ /* Perform */
+ LIST_FOREACH(node, IRCItem.performs.head)
+ irc_send("%s", node->data);
+
+ /* Join all listed channels. */
+ LIST_FOREACH(node, IRCItem.channels.head)
+ {
+ const struct ChannelConf *channel = node->data;
+
+ if (EmptyString(channel->name))
+ continue;
+
+ if (!EmptyString(channel->key))
+ irc_send("JOIN %s %s", channel->name, channel->key);
+ else
+ irc_send("JOIN %s", channel->name);
+ }
+}
+
+/* m_ping
+ *
+ * parv[0] = source
+ * parv[1] = PING
+ * parv[2] = PING TS/Package
+ *
+ * source_p: UserInfo struct of the source user, or NULL if
+ * the source (parv[0]) is a server.
+ */
+static void
+m_ping(char *parv[], unsigned int parc, const char *msg, const char *source_p)
+{
+ if (parc < 3)
+ return;
+
+ if (OPT_DEBUG >= 2)
+ log_printf("IRC -> PING? PONG!");
+
+ irc_send("PONG %s", parv[2]);
+}
+
+/* m_invite
+ *
+ * parv[0] = source
+ * parv[1] = INVITE
+ * parv[2] = target
+ * parv[3] = channel
+ *
+ * source_p: UserInfo struct of the source user, or NULL if
+ * the source (parv[0]) is a server.
+ */
+static void
+m_invite(char *parv[], unsigned int parc, const char *msg, const char *source_p)
+{
+ const struct ChannelConf *channel = NULL;
+
+ if (parc < 4)
+ return;
+
+ log_printf("IRC -> Invited to %s by %s", parv[3], parv[0]);
+
+ if ((channel = get_channel(parv[3])) == NULL)
+ return;
+
+ irc_send("JOIN %s %s", channel->name, channel->key);
+}
+
+/* m_ctcp
+ * parv[0] = source
+ * parv[1] = PRIVMSG
+ * parv[2] = target (channel or user)
+ * parv[3] = message
+ *
+ * source_p: UserInfo struct of the source user, or NULL if
+ * the source (parv[0]) is a server.
+ */
+static void
+m_ctcp(char *parv[], unsigned int parc, const char *msg, const char *source_p)
+{
+ if (strncasecmp(parv[3], "\001VERSION\001", 9) == 0)
+ irc_send("NOTICE %s :\001VERSION Hybrid Open Proxy Monitor %s(%s)\001",
+ source_p, VERSION, SERIALNUM);
+}
+
+/* m_privmsg
+ *
+ * parv[0] = source
+ * parv[1] = PRIVMSG
+ * parv[2] = target (channel or user)
+ * parv[3] = message
+ *
+ * source_p: UserInfo struct of the source user, or NULL if
+ * the source (parv[0]) is a server.
+ */
+static void
+m_privmsg(char *parv[], unsigned int parc, const char *msg, const char *source_p)
+{
+ const struct ChannelConf *channel = NULL;
+
+ if (source_p == NULL)
+ return;
+
+ if (parc < 4)
+ return;
+
+ /* CTCP */
+ if (*parv[3] == '\001')
+ {
+ m_ctcp(parv, parc, msg, source_p);
+ return;
+ }
+
+ /* Only interested in privmsg to channels */
+ if (*parv[2] != '#' && *parv[2] != '&')
+ return;
+
+ /* Get a target */
+ if ((channel = get_channel(parv[2])) == NULL)
+ return;
+
+ int hit = strncasecmp(parv[3], "!all ", 5) == 0;
+ if (hit == 0)
+ {
+ size_t nick_len = strlen(IRCItem.nick);
+
+ if (strncasecmp(parv[3], IRCItem.nick, nick_len) == 0)
+ hit = *(parv[3] + nick_len) == ' ' ||
+ *(parv[3] + nick_len) == ',' ||
+ *(parv[3] + nick_len) == ':';
+ }
+
+ if (hit)
+ /* XXX command_parse will alter parv[3]. */
+ command_parse(parv[3], channel->name, source_p);
+}
+
+/* m_notice
+ *
+ * parv[0] = source
+ * parv[1] = NOTICE
+ * parv[2] = target
+ * parv[3] = message
+ *
+ *
+ * source_p: UserInfo struct of the source user, or NULL if
+ * the source (parv[0]) is a server.
+ */
+static void
+m_notice(char *parv[], unsigned int parc, const char *msg, const char *source_p)
+{
+ static regex_t *preg = NULL;
+ regmatch_t pmatch[5];
+ int errnum;
+ const char *user[4];
+ const node_t *node;
+
+ /* Not interested in notices from users */
+ if (source_p)
+ return;
+
+ if (parc < 4)
+ return;
+
+ /* Compile the regular expression if it has not been already */
+ if (preg == NULL)
+ {
+ preg = xcalloc(sizeof(*preg));
+
+ if ((errnum = regcomp(preg, IRCItem.connregex, REG_ICASE | REG_EXTENDED)))
+ {
+ char errmsg[256];
+
+ regerror(errnum, preg, errmsg, sizeof(errmsg));
+ log_printf("IRC REGEX -> Error when compiling regular expression: %s", errmsg);
+
+ xfree(preg);
+ preg = NULL;
+ return;
+ }
+ }
+
+ /* Match the expression against the possible connection notice */
+ if (regexec(preg, parv[3], 5, pmatch, 0))
+ return;
+
+ if (OPT_DEBUG > 0)
+ log_printf("IRC REGEX -> Regular expression caught connection notice. Parsing.");
+
+ if (pmatch[4].rm_so == -1)
+ {
+ log_printf("IRC REGEX -> pmatch[4].rm_so is -1 while parsing??? Aborting.");
+ return;
+ }
+
+ /*
+ * Offsets for data in the connection notice:
+ *
+ * NICKNAME: pmatch[1].rm_so TO pmatch[1].rm_eo
+ * USERNAME: pmatch[2].rm_so TO pmatch[2].rm_eo
+ * HOSTNAME: pmatch[3].rm_so TO pmatch[3].rm_eo
+ * IP : pmatch[4].rm_so TO pmatch[4].rm_eo
+ */
+ for (unsigned int i = 0; i < 4; ++i)
+ {
+ user[i] = (parv[3] + pmatch[i + 1].rm_so);
+ *(parv[3] + pmatch[i + 1].rm_eo) = '\0';
+ }
+
+ if (OPT_DEBUG > 0)
+ log_printf("IRC REGEX -> Parsed %s!%s@%s [%s] from connection notice.",
+ user[0], user[1], user[2], user[3]);
+
+ LIST_FOREACH(node, IRCItem.notices.head)
+ irc_send("NOTICE %s :%s", user[0], node->data);
+
+ /* Pass this information off to scan.c */
+ scan_connect(user, msg);
+
+ /* Record the connect for stats purposes */
+ stats_connect();
+}
+
+/* m_userhost
+ *
+ * parv[0] = source
+ * parv[1] = USERHOST
+ * parv[2] = target (hopm)
+ * parv[3] = :nick=(flags)user@host
+ *
+ *
+ * source_p: UserInfo struct of the source user, or NULL if
+ * the source (parv[0]) is a server.
+ */
+static void
+m_userhost(char *parv[], unsigned int parc, const char *msg, const char *source_p)
+{
+ if (parc < 4)
+ return;
+
+ command_userhost(parv[3]);
+}
+
+/* m_cannot_join
+ *
+ * parv[0] = source
+ * parv[1] = numeric
+ * parv[2] = target (hopm)
+ * parv[3] = channel
+ * parv[4] = error text
+ */
+static void
+m_cannot_join(char *parv[], unsigned int parc, const char *msg, const char *source_p)
+{
+ const struct ChannelConf *channel = NULL;
+
+ if (parc < 5)
+ return;
+
+ /* Is it one of our channels? */
+ if ((channel = get_channel(parv[3])) == NULL)
+ return;
+
+ if (EmptyString(channel->invite))
+ return;
+
+ irc_send("%s", channel->invite);
+}
+
+/* m_kill
+ *
+ * parv[0] = source
+ * parv[1] = numeric
+ * parv[2] = target (hopm)
+ * parv[3] = channel
+ * parv[4] = error text
+ */
+static void
+m_kill(char *parv[], unsigned int parc, const char *msg, const char *source_p)
+{
+ /* Restart hopm to rehash */
+ main_restart();
+}
+
+/* userinfo_create
+ *
+ * Parse a nick!user@host into a UserInfo struct
+ * and return a pointer to the new struct.
+ *
+ * Parameters:
+ * source: nick!user@host to parse
+ *
+ * Return:
+ * pointer to new UserInfo struct, or NULL if parsing failed
+ */
+static const char *
+userinfo_create(const char *source)
+{
+ static char name[MSGLENMAX];
+ unsigned int has_user = 0;
+ unsigned int has_host = 0;
+
+ strlcpy(name, source, sizeof(name));
+
+ for (char *p = name; *p; ++p)
+ {
+ if (*p == '!')
+ {
+ *p = '\0';
+ ++has_user;
+ continue;
+ }
+
+ if (*p == '@' && has_user)
+ {
+ ++has_host;
+ continue;
+ }
+ }
+
+ if (has_user == 1 && has_host == 1)
+ return name;
+ return NULL;
+};
+
+/* irc_init
+ *
+ * Resolve IRC host and perform other initialization.
+ *
+ * Parameters:
+ * None
+ *
+ * Return:
+ * None
+ */
+static void
+irc_init(void)
+{
+ const void *address = NULL;
+
+ assert(IRC_FD == -1);
+
+ memset(&IRC_SVR, 0, sizeof(IRC_SVR));
+
+ /* Resolve IRC host. */
+ if ((address = firedns_resolveip6(IRCItem.server)))
+ {
+ struct sockaddr_in6 *in = (struct sockaddr_in6 *)&IRC_SVR;
+
+ svr_addrlen = sizeof(*in);
+ IRC_SVR.ss_family = AF_INET6;
+ in->sin6_port = htons(IRCItem.port);
+ memcpy(&in->sin6_addr, address, sizeof(in->sin6_addr));
+ }
+ else if ((address = firedns_resolveip4(IRCItem.server)))
+ {
+ struct sockaddr_in *in = (struct sockaddr_in *)&IRC_SVR;
+
+ svr_addrlen = sizeof(*in);
+ IRC_SVR.ss_family = AF_INET;
+ in->sin_port = htons(IRCItem.port);
+ memcpy(&in->sin_addr, address, sizeof(in->sin_addr));
+ }
+ else
+ {
+ log_printf("IRC -> firedns_resolveip(\"%s\"): %s", IRCItem.server,
+ firedns_strerror(firedns_errno));
+ exit(EXIT_FAILURE);
+ }
+
+ /* Request file desc for IRC client socket */
+ IRC_FD = socket(IRC_SVR.ss_family, SOCK_STREAM, 0);
+
+ if (IRC_FD == -1)
+ {
+ log_printf("IRC -> socket(): error creating socket: %s", strerror(errno));
+ exit(EXIT_FAILURE);
+ }
+
+ /* Bind */
+ if (!EmptyString(IRCItem.vhost))
+ {
+ struct addrinfo hints, *res;
+ int n;
+
+ memset(&hints, 0, sizeof(hints));
+
+ hints.ai_family = AF_UNSPEC;
+ hints.ai_socktype = SOCK_STREAM;
+ hints.ai_flags = AI_NUMERICHOST;
+
+ if ((n = getaddrinfo(IRCItem.vhost, NULL, &hints, &res)))
+ {
+ log_printf("IRC -> error binding to %s: %s", IRCItem.vhost, gai_strerror(n));
+ exit(EXIT_FAILURE);
+ }
+ else if (bind(IRC_FD, res->ai_addr, res->ai_addrlen))
+ {
+ log_printf("IRC -> error binding to %s: %s", IRCItem.vhost, strerror(errno));
+ exit(EXIT_FAILURE);
+ }
+
+ freeaddrinfo(res);
+ }
+}
+
+/* irc_reconnect
+ *
+ * Close connection to IRC server.
+ *
+ * Parameters: NONE
+ *
+ * Return: NONE
+ */
+static void
+irc_reconnect(void)
+{
+ time_t present;
+
+ time(&present);
+
+ /* Only try to reconnect every IRCItem.reconnectinterval seconds */
+ if ((present - IRC_LASTRECONNECT) < IRCItem.reconnectinterval)
+ {
+ /* Sleep to avoid excessive CPU */
+ sleep(1);
+ return;
+ }
+
+ time(&IRC_LASTRECONNECT);
+
+ if (IRC_FD > -1)
+ {
+ close(IRC_FD);
+ IRC_FD = -1; /* Set IRC_FD -1 for reconnection on next irc_cycle(). */
+ }
+
+ log_printf("IRC -> Connection to (%s) failed, reconnecting.", IRCItem.server);
+}
+
+/* irc_connect
+ *
+ * Connect to IRC server.
+ * XXX: FD allocation done here
+ *
+ * Parameters: NONE
+ * Return: NONE
+ */
+static void
+irc_connect(void)
+{
+ /* Connect to IRC server as client. */
+ if (connect(IRC_FD, (struct sockaddr *)&IRC_SVR, svr_addrlen) == -1)
+ {
+ log_printf("IRC -> connect(): error connecting to %s: %s",
+ IRCItem.server, strerror(errno));
+
+ if (errno == EISCONN /* Already connected */ || errno == EALREADY /* Previous attempt not complete */)
+ return;
+
+ /* Try to connect again */
+ irc_reconnect();
+ return;
+ }
+
+ irc_send("NICK %s", IRCItem.nick);
+
+ if (!EmptyString(IRCItem.password))
+ irc_send("PASS %s", IRCItem.password);
+
+ irc_send("USER %s %s %s :%s",
+ IRCItem.username,
+ IRCItem.username,
+ IRCItem.username,
+ IRCItem.realname);
+ time(&IRC_LAST);
+}
+
+/* irc_parse
+ *
+ * irc_parse is called by irc_read when a full line of data
+ * is ready to be parsed.
+ *
+ * Parameters: NONE
+ * Return: NONE
+ */
+static void
+irc_parse(void)
+{
+ char *pos;
+
+ /*
+ * parv stores the parsed token, parc is the count of the parsed
+ * tokens
+ *
+ * parv[0] is ALWAYS the source, and is the server name of the
+ * source did not exist
+ */
+ char *parv[17];
+ unsigned int parc = 1;
+ char msg[MSGLENMAX]; /* Temporarily stores IRC msg to pass to handlers */
+
+ struct CommandHash
+ {
+ const char *command;
+ void (*handler)(char *[], unsigned int, const char *, const char *);
+ };
+
+ /*
+ * Table should be ordered with most occuring (or priority)
+ * commands at the top of the list.
+ */
+ static const struct CommandHash COMMAND_TABLE[] =
+ {
+ { .command = "NOTICE", .handler = m_notice },
+ { .command = "PRIVMSG", .handler = m_privmsg },
+ { .command = "PING", .handler = m_ping },
+ { .command = "INVITE", .handler = m_invite },
+ { .command = "001", .handler = m_perform },
+ { .command = "302", .handler = m_userhost },
+ { .command = "471", .handler = m_cannot_join },
+ { .command = "473", .handler = m_cannot_join },
+ { .command = "474", .handler = m_cannot_join },
+ { .command = "475", .handler = m_cannot_join },
+ { .command = "KILL", .handler = m_kill },
+ { .command = NULL }
+ };
+
+ if (IRC_RAW_LEN == 0)
+ return;
+
+ if (OPT_DEBUG >= 2)
+ log_printf("IRC READ -> %s", IRC_RAW);
+
+ time(&IRC_LAST);
+
+ /* Store a copy of IRC_RAW for the handlers (for functions that need PROOF) */
+ strlcpy(msg, IRC_RAW, sizeof(msg));
+
+ /* parv[0] is always the source */
+ if (IRC_RAW[0] == ':')
+ parv[0] = IRC_RAW + 1;
+ else
+ {
+ parv[0] = IRCItem.server;
+ parv[parc++] = IRC_RAW;
+ }
+
+ pos = IRC_RAW;
+
+ while ((pos = strchr(pos, ' ')) && parc <= 17)
+ {
+ /* Avoid excessive spaces and end of IRC_RAW */
+ if (*(pos + 1) == ' ' || *(pos + 1) == '\0')
+ {
+ pos++;
+ continue;
+ }
+
+ /* Anything after a : is considered the final string of the message */
+ if (*(pos + 1) == ':')
+ {
+ parv[parc++] = pos + 2;
+ *pos = '\0';
+ break;
+ }
+
+ /*
+ * Set the next parv at this position and replace the space with a
+ * \0 for the previous parv
+ */
+ parv[parc++] = pos + 1;
+ *pos = '\0';
+ pos++;
+ }
+
+ /*
+ * Determine which command this is from the command table
+ * and let the handler for that command take control
+ */
+ for (const struct CommandHash *cmd = COMMAND_TABLE; cmd->command; ++cmd)
+ {
+ if (strcasecmp(cmd->command, parv[1]) == 0)
+ {
+ cmd->handler(parv, parc, msg, userinfo_create(parv[0]));
+ break;
+ }
+ }
+}
+
+/* irc_read
+ *
+ * irc_read is called by irc_cycle when new data is ready to be
+ * read from the irc server.
+ *
+ * Parameters: NONE
+ * Return: NONE
+ */
+static void
+irc_read(void)
+{
+ ssize_t len;
+ char c;
+
+ while ((len = read(IRC_FD, &c, 1)) > 0)
+ {
+ 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 != '\0')
+ IRC_RAW[IRC_RAW_LEN++] = c;
+ }
+
+ if ((len <= 0) && (errno != EAGAIN))
+ {
+ if (errno != EINTR)
+ log_printf("IRC -> Error reading data from server: %s", strerror(errno));
+
+ irc_reconnect();
+ IRC_RAW_LEN = 0;
+ return;
+ }
+}
+
+/* irc_cycle
+ *
+ * Pass control to the IRC portion of HOPM to handle any awaiting IRC events.
+ *
+ * Parameters:
+ * None
+ *
+ * Return:
+ * None
+ */
+void
+irc_cycle(void)
+{
+ static struct pollfd pfd;
+
+ if (IRC_FD == -1)
+ {
+ /* Initialize negative cache. */
+ if (OptionsItem.negcache)
+ negcache_init();
+
+ /* Resolve remote host. */
+ irc_init();
+
+ /* Connect to remote host. */
+ irc_connect();
+ return; /* In case connect() immediately failed */
+ }
+
+ pfd.fd = IRC_FD;
+ pfd.events = POLLIN;
+
+ /* Block .050 seconds to avoid excessive CPU use on poll(). */
+ switch (poll(&pfd, 1, 50))
+ {
+ case 0:
+ case -1:
+ break;
+ default:
+ /* Check if IRC data is available. */
+ if (pfd.revents & POLLIN)
+ irc_read();
+ else if (pfd.revents & (POLLERR | POLLHUP))
+ irc_reconnect();
+
+ break;
+ }
+}
+
+/* irc_send
+ *
+ * Send data to remote IRC host.
+ *
+ * Parameters:
+ * data: Format of data to send
+ * ...: varargs to format with
+ *
+ * Return: NONE
+ */
+void
+irc_send(const char *data, ...)
+{
+ va_list arglist;
+ char buf[MSGLENMAX];
+ size_t len = 0;
+
+ va_start(arglist, data);
+ len = vsnprintf(buf, sizeof(buf), data, arglist);
+ va_end(arglist);
+
+ if (OPT_DEBUG >= 2)
+ log_printf("IRC SEND -> %s", buf);
+
+ if (len > 510)
+ len = 510;
+
+ buf[len++] = '\r';
+ buf[len++] = '\n';
+
+ if (send(IRC_FD, buf, len, 0) == -1)
+ {
+ /* Return of -1 indicates error sending data; we reconnect. */
+ log_printf("IRC -> Error sending data to server: %s", strerror(errno));
+ irc_reconnect();
+ }
+}
+
+/* irc_send_channels
+ *
+ * Send privmsg to all channels.
+ *
+ * Parameters:
+ * data: Format of data to send
+ * ...: varargs to format with
+ *
+ * Return: NONE
+ */
+void
+irc_send_channels(const char *data, ...)
+{
+ const node_t *node;
+ va_list arglist;
+ char buf[MSGLENMAX];
+
+ va_start(arglist, data);
+ vsnprintf(buf, sizeof(buf), data, arglist);
+ va_end(arglist);
+
+ LIST_FOREACH(node, IRCItem.channels.head)
+ {
+ const struct ChannelConf *chan = node->data;
+
+ irc_send("PRIVMSG %s :%s", chan->name, buf);
+ }
+}
+
+/* irc_timer
+ *
+ * Functions to be performed every ~seconds.
+ *
+ * Parameters: NONE
+ * Return: NONE
+ */
+void
+irc_timer(void)
+{
+ time_t present, delta;
+
+ time(&present);
+
+ delta = present - IRC_LAST;
+
+ /* No data in IRCItem.readtimeout seconds */
+ if (delta >= IRCItem.readtimeout)
+ {
+ log_printf("IRC -> Timeout awaiting data from server.");
+ irc_reconnect();
+
+ /* Make sure we don't do this again for a while */
+ time(&IRC_LAST);
+ }
+ else if (delta >= IRCItem.readtimeout / 2)
+ {
+ /*
+ * Generate some data so high ping times don't cause uneeded
+ * reconnections
+ */
+ irc_send("PING :HOPM");
+ }
+}
diff --git a/src/irc.h b/src/irc.h
new file mode 100644
index 0000000..871907d
--- /dev/null
+++ b/src/irc.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2002-2003 Erik Fears
+ * Copyright (c) 2014-2018 ircd-hybrid 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 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
+ * USA
+ */
+
+#ifndef IRC_H
+#define IRC_H
+
+enum { MSGLENMAX = 513 }; /* 510 bytes message length + \r\n\0 */
+
+
+extern void irc_send(const char *, ...);
+extern void irc_send_channels(const char *, ...);
+extern void irc_cycle(void);
+extern void irc_timer(void);
+#endif
diff --git a/src/libopm/COPYING b/src/libopm/COPYING
new file mode 100644
index 0000000..d159169
--- /dev/null
+++ b/src/libopm/COPYING
@@ -0,0 +1,339 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Lesser General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ 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.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) year name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Lesser General
+Public License instead of this License.
diff --git a/src/libopm/Makefile.am b/src/libopm/Makefile.am
new file mode 100644
index 0000000..dfa49b2
--- /dev/null
+++ b/src/libopm/Makefile.am
@@ -0,0 +1,2 @@
+AUTOMAKE_OPTIONS = foreign
+SUBDIRS = src
diff --git a/src/libopm/Makefile.in b/src/libopm/Makefile.in
new file mode 100644
index 0000000..2cf5060
--- /dev/null
+++ b/src/libopm/Makefile.in
@@ -0,0 +1,632 @@
+# Makefile.in generated by automake 1.15.1 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2017 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.
+
+@SET_MAKE@
+VPATH = @srcdir@
+am__is_gnu_make = { \
+ if test -z '$(MAKELEVEL)'; then \
+ false; \
+ elif test -n '$(MAKE_HOST)'; then \
+ true; \
+ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+ true; \
+ else \
+ false; \
+ fi; \
+}
+am__make_running_with_option = \
+ case $${target_option-} in \
+ ?) ;; \
+ *) echo "am__make_running_with_option: internal error: invalid" \
+ "target option '$${target_option-}' specified" >&2; \
+ exit 1;; \
+ esac; \
+ has_opt=no; \
+ sane_makeflags=$$MAKEFLAGS; \
+ if $(am__is_gnu_make); then \
+ sane_makeflags=$$MFLAGS; \
+ else \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ bs=\\; \
+ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
+ esac; \
+ fi; \
+ skip_next=no; \
+ strip_trailopt () \
+ { \
+ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+ }; \
+ for flg in $$sane_makeflags; do \
+ test $$skip_next = yes && { skip_next=no; continue; }; \
+ case $$flg in \
+ *=*|--*) continue;; \
+ -*I) strip_trailopt 'I'; skip_next=yes;; \
+ -*I?*) strip_trailopt 'I';; \
+ -*O) strip_trailopt 'O'; skip_next=yes;; \
+ -*O?*) strip_trailopt 'O';; \
+ -*l) strip_trailopt 'l'; skip_next=yes;; \
+ -*l?*) strip_trailopt 'l';; \
+ -[dEDm]) skip_next=yes;; \
+ -[JT]) skip_next=yes;; \
+ esac; \
+ case $$flg in \
+ *$$target_option*) has_opt=yes; break;; \
+ esac; \
+ done; \
+ test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = src/libopm
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/ax_append_compile_flags.m4 \
+ $(top_srcdir)/m4/ax_append_flag.m4 \
+ $(top_srcdir)/m4/ax_arg_enable_assert.m4 \
+ $(top_srcdir)/m4/ax_arg_enable_efence.m4 \
+ $(top_srcdir)/m4/ax_arg_enable_warnings.m4 \
+ $(top_srcdir)/m4/ax_arg_openssl.m4 \
+ $(top_srcdir)/m4/ax_check_compile_flag.m4 \
+ $(top_srcdir)/m4/ax_gcc_stack_protect.m4 \
+ $(top_srcdir)/m4/ax_library_net.m4 \
+ $(top_srcdir)/m4/ax_require_defined.m4 \
+ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
+ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
+ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
+mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs
+CONFIG_HEADER = $(top_builddir)/src/setup.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo " GEN " $@;
+am__v_GEN_1 =
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 =
+SOURCES =
+DIST_SOURCES =
+RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \
+ ctags-recursive dvi-recursive html-recursive info-recursive \
+ install-data-recursive install-dvi-recursive \
+ install-exec-recursive install-html-recursive \
+ install-info-recursive install-pdf-recursive \
+ install-ps-recursive install-recursive installcheck-recursive \
+ installdirs-recursive pdf-recursive ps-recursive \
+ tags-recursive uninstall-recursive
+am__can_run_installinfo = \
+ case $$AM_UPDATE_INFO_DIR in \
+ n|no|NO) false;; \
+ *) (install-info --version) >/dev/null 2>&1;; \
+ esac
+RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \
+ distclean-recursive maintainer-clean-recursive
+am__recursive_targets = \
+ $(RECURSIVE_TARGETS) \
+ $(RECURSIVE_CLEAN_TARGETS) \
+ $(am__extra_recursive_targets)
+AM_RECURSIVE_TARGETS = $(am__recursive_targets:-recursive=) TAGS CTAGS \
+ distdir
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates. Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+ BEGIN { nonempty = 0; } \
+ { items[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique. This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+ list='$(am__tagged_files)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | $(am__uniquify_input)`
+ETAGS = etags
+CTAGS = ctags
+DIST_SUBDIRS = $(SUBDIRS)
+am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/mkinstalldirs \
+ COPYING
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+am__relativize = \
+ dir0=`pwd`; \
+ sed_first='s,^\([^/]*\)/.*$$,\1,'; \
+ sed_rest='s,^[^/]*/*,,'; \
+ sed_last='s,^.*/\([^/]*\)$$,\1,'; \
+ sed_butlast='s,/*[^/]*$$,,'; \
+ while test -n "$$dir1"; do \
+ first=`echo "$$dir1" | sed -e "$$sed_first"`; \
+ if test "$$first" != "."; then \
+ if test "$$first" = ".."; then \
+ dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \
+ dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \
+ else \
+ first2=`echo "$$dir2" | sed -e "$$sed_first"`; \
+ if test "$$first2" = "$$first"; then \
+ dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \
+ else \
+ dir2="../$$dir2"; \
+ fi; \
+ dir0="$$dir0"/"$$first"; \
+ fi; \
+ fi; \
+ dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \
+ done; \
+ reldir="$$dir2"
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DLLTOOL = @DLLTOOL@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+GREP = @GREP@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LEX = @LEX@
+LEXLIB = @LEXLIB@
+LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+RANLIB = @RANLIB@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+VERSION = @VERSION@
+YACC = @YACC@
+YFLAGS = @YFLAGS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+AUTOMAKE_OPTIONS = foreign
+SUBDIRS = src
+all: all-recursive
+
+.SUFFIXES:
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/libopm/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --foreign src/libopm/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+# This directory's subdirectories are mostly independent; you can cd
+# into them and run 'make' without going through this Makefile.
+# To change the values of 'make' variables: instead of editing Makefiles,
+# (1) if the variable is set in 'config.status', edit 'config.status'
+# (which will cause the Makefiles to be regenerated when you run 'make');
+# (2) otherwise, pass the desired values on the 'make' command line.
+$(am__recursive_targets):
+ @fail=; \
+ if $(am__make_keepgoing); then \
+ failcom='fail=yes'; \
+ else \
+ failcom='exit 1'; \
+ fi; \
+ dot_seen=no; \
+ target=`echo $@ | sed s/-recursive//`; \
+ case "$@" in \
+ distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \
+ *) list='$(SUBDIRS)' ;; \
+ esac; \
+ for subdir in $$list; do \
+ echo "Making $$target in $$subdir"; \
+ if test "$$subdir" = "."; then \
+ dot_seen=yes; \
+ local_target="$$target-am"; \
+ else \
+ local_target="$$target"; \
+ fi; \
+ ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \
+ || eval $$failcom; \
+ done; \
+ if test "$$dot_seen" = "no"; then \
+ $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \
+ fi; test -z "$$fail"
+
+ID: $(am__tagged_files)
+ $(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-recursive
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ set x; \
+ here=`pwd`; \
+ if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \
+ include_option=--etags-include; \
+ empty_fix=.; \
+ else \
+ include_option=--include; \
+ empty_fix=; \
+ fi; \
+ list='$(SUBDIRS)'; for subdir in $$list; do \
+ if test "$$subdir" = .; then :; else \
+ test ! -f $$subdir/TAGS || \
+ set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \
+ fi; \
+ done; \
+ $(am__define_uniq_tagged_files); \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: ctags-recursive
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ $(am__define_uniq_tagged_files); \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+cscopelist: cscopelist-recursive
+
+cscopelist-am: $(am__tagged_files)
+ list='$(am__tagged_files)'; \
+ case "$(srcdir)" in \
+ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+ *) sdir=$(subdir)/$(srcdir) ;; \
+ esac; \
+ for i in $$list; do \
+ if test -f "$$i"; then \
+ echo "$(subdir)/$$i"; \
+ else \
+ echo "$$sdir/$$i"; \
+ fi; \
+ done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+ @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \
+ if test "$$subdir" = .; then :; else \
+ $(am__make_dryrun) \
+ || test -d "$(distdir)/$$subdir" \
+ || $(MKDIR_P) "$(distdir)/$$subdir" \
+ || exit 1; \
+ dir1=$$subdir; dir2="$(distdir)/$$subdir"; \
+ $(am__relativize); \
+ new_distdir=$$reldir; \
+ dir1=$$subdir; dir2="$(top_distdir)"; \
+ $(am__relativize); \
+ new_top_distdir=$$reldir; \
+ echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \
+ echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \
+ ($(am__cd) $$subdir && \
+ $(MAKE) $(AM_MAKEFLAGS) \
+ top_distdir="$$new_top_distdir" \
+ distdir="$$new_distdir" \
+ am__remove_distdir=: \
+ am__skip_length_check=: \
+ am__skip_mode_fix=: \
+ distdir) \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-recursive
+all-am: Makefile
+installdirs: installdirs-recursive
+installdirs-am:
+install: install-recursive
+install-exec: install-exec-recursive
+install-data: install-data-recursive
+uninstall: uninstall-recursive
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-recursive
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-recursive
+
+clean-am: clean-generic clean-libtool mostlyclean-am
+
+distclean: distclean-recursive
+ -rm -f Makefile
+distclean-am: clean-am distclean-generic distclean-tags
+
+dvi: dvi-recursive
+
+dvi-am:
+
+html: html-recursive
+
+html-am:
+
+info: info-recursive
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-recursive
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-recursive
+
+install-html-am:
+
+install-info: install-info-recursive
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-recursive
+
+install-pdf-am:
+
+install-ps: install-ps-recursive
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-recursive
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-recursive
+
+mostlyclean-am: mostlyclean-generic mostlyclean-libtool
+
+pdf: pdf-recursive
+
+pdf-am:
+
+ps: ps-recursive
+
+ps-am:
+
+uninstall-am:
+
+.MAKE: $(am__recursive_targets) install-am install-strip
+
+.PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am check \
+ check-am clean clean-generic clean-libtool cscopelist-am ctags \
+ ctags-am distclean distclean-generic distclean-libtool \
+ distclean-tags distdir dvi dvi-am html html-am info info-am \
+ install install-am install-data install-data-am install-dvi \
+ install-dvi-am install-exec install-exec-am install-html \
+ install-html-am install-info install-info-am install-man \
+ install-pdf install-pdf-am install-ps install-ps-am \
+ install-strip installcheck installcheck-am installdirs \
+ installdirs-am maintainer-clean maintainer-clean-generic \
+ mostlyclean mostlyclean-generic mostlyclean-libtool pdf pdf-am \
+ ps ps-am tags tags-am uninstall uninstall-am
+
+.PRECIOUS: Makefile
+
+
+# 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:
diff --git a/src/libopm/src/Makefile.am b/src/libopm/src/Makefile.am
new file mode 100644
index 0000000..7726c07
--- /dev/null
+++ b/src/libopm/src/Makefile.am
@@ -0,0 +1,18 @@
+noinst_LTLIBRARIES = libopm.la
+
+libopm_la_SOURCES = config.c \
+ config.h \
+ libopm.c \
+ libopm.h \
+ list.c \
+ list.h \
+ memory.c \
+ memory.h \
+ opm_common.h \
+ opm_error.h \
+ opm.h \
+ opm_types.h \
+ proxy.c \
+ proxy.h
+
+libopm_la_LIBADD = @LTLIBOBJS@
diff --git a/src/libopm/src/Makefile.in b/src/libopm/src/Makefile.in
new file mode 100644
index 0000000..15db3dd
--- /dev/null
+++ b/src/libopm/src/Makefile.in
@@ -0,0 +1,617 @@
+# Makefile.in generated by automake 1.15.1 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2017 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.
+
+@SET_MAKE@
+
+VPATH = @srcdir@
+am__is_gnu_make = { \
+ if test -z '$(MAKELEVEL)'; then \
+ false; \
+ elif test -n '$(MAKE_HOST)'; then \
+ true; \
+ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+ true; \
+ else \
+ false; \
+ fi; \
+}
+am__make_running_with_option = \
+ case $${target_option-} in \
+ ?) ;; \
+ *) echo "am__make_running_with_option: internal error: invalid" \
+ "target option '$${target_option-}' specified" >&2; \
+ exit 1;; \
+ esac; \
+ has_opt=no; \
+ sane_makeflags=$$MAKEFLAGS; \
+ if $(am__is_gnu_make); then \
+ sane_makeflags=$$MFLAGS; \
+ else \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ bs=\\; \
+ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
+ esac; \
+ fi; \
+ skip_next=no; \
+ strip_trailopt () \
+ { \
+ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+ }; \
+ for flg in $$sane_makeflags; do \
+ test $$skip_next = yes && { skip_next=no; continue; }; \
+ case $$flg in \
+ *=*|--*) continue;; \
+ -*I) strip_trailopt 'I'; skip_next=yes;; \
+ -*I?*) strip_trailopt 'I';; \
+ -*O) strip_trailopt 'O'; skip_next=yes;; \
+ -*O?*) strip_trailopt 'O';; \
+ -*l) strip_trailopt 'l'; skip_next=yes;; \
+ -*l?*) strip_trailopt 'l';; \
+ -[dEDm]) skip_next=yes;; \
+ -[JT]) skip_next=yes;; \
+ esac; \
+ case $$flg in \
+ *$$target_option*) has_opt=yes; break;; \
+ esac; \
+ done; \
+ test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = src/libopm/src
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/ax_append_compile_flags.m4 \
+ $(top_srcdir)/m4/ax_append_flag.m4 \
+ $(top_srcdir)/m4/ax_arg_enable_assert.m4 \
+ $(top_srcdir)/m4/ax_arg_enable_efence.m4 \
+ $(top_srcdir)/m4/ax_arg_enable_warnings.m4 \
+ $(top_srcdir)/m4/ax_arg_openssl.m4 \
+ $(top_srcdir)/m4/ax_check_compile_flag.m4 \
+ $(top_srcdir)/m4/ax_gcc_stack_protect.m4 \
+ $(top_srcdir)/m4/ax_library_net.m4 \
+ $(top_srcdir)/m4/ax_require_defined.m4 \
+ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
+ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
+ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
+mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs
+CONFIG_HEADER = $(top_builddir)/src/setup.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+LTLIBRARIES = $(noinst_LTLIBRARIES)
+libopm_la_DEPENDENCIES = @LTLIBOBJS@
+am_libopm_la_OBJECTS = config.lo libopm.lo list.lo memory.lo proxy.lo
+libopm_la_OBJECTS = $(am_libopm_la_OBJECTS)
+AM_V_lt = $(am__v_lt_@AM_V@)
+am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
+am__v_lt_0 = --silent
+am__v_lt_1 =
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo " GEN " $@;
+am__v_GEN_1 =
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 =
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)/src
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__depfiles_maybe = depfiles
+am__mv = mv -f
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_@AM_V@)
+am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
+am__v_CC_0 = @echo " CC " $@;
+am__v_CC_1 =
+CCLD = $(CC)
+LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_@AM_V@)
+am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
+am__v_CCLD_0 = @echo " CCLD " $@;
+am__v_CCLD_1 =
+SOURCES = $(libopm_la_SOURCES)
+DIST_SOURCES = $(libopm_la_SOURCES)
+am__can_run_installinfo = \
+ case $$AM_UPDATE_INFO_DIR in \
+ n|no|NO) false;; \
+ *) (install-info --version) >/dev/null 2>&1;; \
+ esac
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates. Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+ BEGIN { nonempty = 0; } \
+ { items[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique. This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+ list='$(am__tagged_files)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | $(am__uniquify_input)`
+ETAGS = etags
+CTAGS = ctags
+am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/depcomp \
+ $(top_srcdir)/mkinstalldirs
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DLLTOOL = @DLLTOOL@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+GREP = @GREP@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LEX = @LEX@
+LEXLIB = @LEXLIB@
+LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+RANLIB = @RANLIB@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+VERSION = @VERSION@
+YACC = @YACC@
+YFLAGS = @YFLAGS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+noinst_LTLIBRARIES = libopm.la
+libopm_la_SOURCES = config.c \
+ config.h \
+ libopm.c \
+ libopm.h \
+ list.c \
+ list.h \
+ memory.c \
+ memory.h \
+ opm_common.h \
+ opm_error.h \
+ opm.h \
+ opm_types.h \
+ proxy.c \
+ proxy.h
+
+libopm_la_LIBADD = @LTLIBOBJS@
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/libopm/src/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --gnu src/libopm/src/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+clean-noinstLTLIBRARIES:
+ -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES)
+ @list='$(noinst_LTLIBRARIES)'; \
+ locs=`for p in $$list; do echo $$p; done | \
+ sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \
+ sort -u`; \
+ test -z "$$locs" || { \
+ echo rm -f $${locs}; \
+ rm -f $${locs}; \
+ }
+
+libopm.la: $(libopm_la_OBJECTS) $(libopm_la_DEPENDENCIES) $(EXTRA_libopm_la_DEPENDENCIES)
+ $(AM_V_CCLD)$(LINK) $(libopm_la_OBJECTS) $(libopm_la_LIBADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/config.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libopm.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/list.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/memory.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/proxy.Plo@am__quote@
+
+.c.o:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $<
+
+.c.obj:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $<
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+ID: $(am__tagged_files)
+ $(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-am
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ set x; \
+ here=`pwd`; \
+ $(am__define_uniq_tagged_files); \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: ctags-am
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ $(am__define_uniq_tagged_files); \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+cscopelist: cscopelist-am
+
+cscopelist-am: $(am__tagged_files)
+ list='$(am__tagged_files)'; \
+ case "$(srcdir)" in \
+ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+ *) sdir=$(subdir)/$(srcdir) ;; \
+ esac; \
+ for i in $$list; do \
+ if test -f "$$i"; then \
+ echo "$(subdir)/$$i"; \
+ else \
+ echo "$$sdir/$$i"; \
+ fi; \
+ done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(LTLIBRARIES)
+installdirs:
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libtool clean-noinstLTLIBRARIES \
+ mostlyclean-am
+
+distclean: distclean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am:
+
+.MAKE: install-am install-strip
+
+.PHONY: CTAGS GTAGS TAGS all all-am check check-am clean clean-generic \
+ clean-libtool clean-noinstLTLIBRARIES cscopelist-am ctags \
+ ctags-am distclean distclean-compile distclean-generic \
+ distclean-libtool distclean-tags distdir dvi dvi-am html \
+ html-am info info-am install install-am install-data \
+ install-data-am install-dvi install-dvi-am install-exec \
+ install-exec-am install-html install-html-am install-info \
+ install-info-am install-man install-pdf install-pdf-am \
+ install-ps install-ps-am install-strip installcheck \
+ installcheck-am installdirs maintainer-clean \
+ maintainer-clean-generic mostlyclean mostlyclean-compile \
+ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+ tags tags-am uninstall uninstall-am
+
+.PRECIOUS: Makefile
+
+
+# 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:
diff --git a/src/libopm/src/config.c b/src/libopm/src/config.c
new file mode 100644
index 0000000..dfc4c48
--- /dev/null
+++ b/src/libopm/src/config.c
@@ -0,0 +1,249 @@
+/*
+ * 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 <stdlib.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include "memory.h"
+#include "config.h"
+#include "opm_error.h"
+#include "opm_types.h"
+#include "opm_common.h"
+#include "list.h"
+
+
+static const OPM_CONFIG_HASH_T HASH[] =
+{
+ { OPM_CONFIG_FD_LIMIT, OPM_TYPE_INT },
+ { OPM_CONFIG_BIND_IP , OPM_TYPE_ADDRESS },
+ { OPM_CONFIG_DNSBL_HOST, OPM_TYPE_STRING },
+ { OPM_CONFIG_TARGET_STRING, OPM_TYPE_STRINGLIST },
+ { OPM_CONFIG_SCAN_IP, OPM_TYPE_STRING },
+ { OPM_CONFIG_SCAN_PORT, OPM_TYPE_INT },
+ { OPM_CONFIG_MAX_READ, OPM_TYPE_INT },
+ { OPM_CONFIG_TIMEOUT, OPM_TYPE_INT }
+};
+
+/* config_create
+ *
+ * Create an OPM_CONFIG_T struct, set default values and return it
+ *
+ * Parameters:
+ * None;
+ *
+ * Return:
+ * Pointer to allocated OPM_CONFIG_T struct
+ */
+OPM_CONFIG_T *
+libopm_config_create(void)
+{
+ const unsigned int num = sizeof(HASH) / sizeof(OPM_CONFIG_HASH_T);
+ OPM_CONFIG_T *ret;
+
+ ret = libopm_calloc(sizeof(OPM_CONFIG_T));
+ ret->vars = libopm_calloc(sizeof(void *) * num);
+
+
+ /*
+ * Set default config items. This in the future would be much better
+ * if it could set realistic defaults for each individual config item.
+ *
+ * OPM_TYPE_INT = 0
+ * OPM_TYPE_STRING = ""
+ * OPM_TYPE_ADDRESS = 0.0.0.0
+ * OPM_TYPE_STRINGLIST = empty list
+ */
+ for (unsigned int i = 0; i < num; ++i)
+ {
+ switch (libopm_config_gettype(i))
+ {
+ case OPM_TYPE_INT:
+ ret->vars[i] = libopm_calloc(sizeof(int));
+ break;
+
+ case OPM_TYPE_STRING:
+ ret->vars[i] = libopm_strdup("");
+ break;
+
+ case OPM_TYPE_ADDRESS:
+ ret->vars[i] = libopm_calloc(sizeof(struct sockaddr_in));
+ break;
+
+ case OPM_TYPE_STRINGLIST:
+ ret->vars[i] = libopm_calloc(sizeof(OPM_LIST_T));
+ break;
+
+ default:
+ ret->vars[i] = NULL;
+ }
+ }
+
+ return ret;
+}
+
+/* config_free
+ *
+ * Free config structure and clean up
+ *
+ * Parameters:
+ * config: Structure to free/cleanup
+ *
+ * Return:
+ * None
+ */
+void
+libopm_config_free(OPM_CONFIG_T *config)
+{
+ const unsigned int num = sizeof(HASH) / sizeof(OPM_CONFIG_HASH_T);
+ OPM_NODE_T *p, *next;
+ OPM_LIST_T *list;
+
+ for (unsigned int i = 0; i < num; ++i)
+ {
+ if (config->vars[i] == NULL)
+ continue;
+
+ switch (libopm_config_gettype(i))
+ {
+ case OPM_TYPE_STRINGLIST:
+ list = config->vars[i];
+
+ LIST_FOREACH_SAFE(p, next, list->head)
+ {
+ libopm_free(p->data);
+ libopm_free(p);
+ }
+
+ break;
+
+ default:
+ libopm_free(config->vars[i]);
+ break;
+ }
+ }
+
+ libopm_free(config->vars);
+ libopm_free(config);
+}
+
+/* config_set
+ *
+ * Set configuration options on config struct.
+ *
+ * Parameters:
+ * config: Config struct to set parameters on
+ * key: Variable within the struct to set
+ * value: Address of value to set
+ *
+ * Return:
+ * 1: Variable was set
+ * 0: Some error occured
+ */
+
+OPM_ERR_T
+libopm_config_set(OPM_CONFIG_T *config, unsigned int key, const void *value)
+{
+ const unsigned int num = sizeof(HASH) / sizeof(OPM_CONFIG_HASH_T);
+ OPM_NODE_T *node;
+
+ if (key >= num)
+ return OPM_ERR_BADKEY; /* Return appropriate error code eventually */
+
+ switch (libopm_config_gettype(key))
+ {
+ case OPM_TYPE_STRING:
+ if (config->vars[key])
+ libopm_free(config->vars[key]);
+
+ config->vars[key] = libopm_strdup(value);
+ break;
+
+ case OPM_TYPE_INT:
+ *(int *)config->vars[key] = *(const int *)value;
+ break;
+
+ case OPM_TYPE_ADDRESS:
+ if (inet_pton(AF_INET, value, &(((struct sockaddr_in *)config->vars[key])->sin_addr)) <= 0)
+ return OPM_ERR_BADVALUE; /* Return appropriate err code */
+
+ break;
+
+ case OPM_TYPE_STRINGLIST:
+ node = libopm_node_create(libopm_strdup(value));
+ libopm_list_add(config->vars[key], node);
+ break;
+
+ default:
+ return OPM_ERR_BADKEY; /* return appropriate err code */
+ }
+
+ return OPM_SUCCESS;
+}
+
+/* config_gettype
+ *
+ * Get type of key.
+ *
+ * Parameters:
+ * key: Key to get type of.
+ *
+ * Return:
+ * TYPE_? of key
+ */
+int
+libopm_config_gettype(int key)
+{
+ const unsigned int num = sizeof(HASH) / sizeof(OPM_CONFIG_HASH_T);
+
+ for (unsigned int i = 0; i < num; ++i)
+ if (HASH[i].key == key)
+ return HASH[i].type;
+
+ return 0;
+}
+
+/* config
+ *
+ * Retrieve a specific config variable from
+ * an OPM_CONFIG_T struct. This is basically a
+ * wrapper to extracting the variable from the
+ * array.
+ *
+ * Parameters:
+ * config: Config struct to extract from
+ * key: Value to extract
+ *
+ * Return:
+ * -ADDRESS- to extracted value in array. This address
+ * will have to be cast on the return end to be any use.
+ */
+void *
+libopm_config(OPM_CONFIG_T *config, unsigned int key)
+{
+ return config->vars[key];
+}
diff --git a/src/libopm/src/config.h b/src/libopm/src/config.h
new file mode 100644
index 0000000..7bfc80d
--- /dev/null
+++ b/src/libopm/src/config.h
@@ -0,0 +1,19 @@
+#ifndef CONFIG_H
+#define CONFIG_H
+
+#include "libopm.h"
+
+typedef struct _opm_config_hash OPM_CONFIG_HASH_T;
+
+struct _opm_config_hash
+{
+ int key;
+ int type;
+};
+
+extern void libopm_config_free(OPM_CONFIG_T *);
+extern void *libopm_config(OPM_CONFIG_T *, unsigned int);
+extern int libopm_config_gettype(int);
+extern OPM_CONFIG_T *libopm_config_create(void);
+extern OPM_ERR_T libopm_config_set(OPM_CONFIG_T *, unsigned int , const void *);
+#endif /* CONFIG_H */
diff --git a/src/libopm/src/libopm.c b/src/libopm/src/libopm.c
new file mode 100644
index 0000000..89b376f
--- /dev/null
+++ b/src/libopm/src/libopm.c
@@ -0,0 +1,1343 @@
+/*
+ * Copyright (C) 2002-2003 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 <errno.h>
+#include <time.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <string.h>
+#include <stdlib.h>
+#include <poll.h>
+#ifdef HAVE_LIBCRYPTO
+#include <openssl/ssl.h>
+#endif
+
+#include "config.h"
+#include "libopm.h"
+#include "memory.h"
+#include "opm_error.h"
+#include "opm_types.h"
+#include "opm_common.h"
+#include "list.h"
+#include "proxy.h"
+
+
+static OPM_PROTOCOL_CONFIG_T *libopm_protocol_config_create(void);
+static void libopm_protocol_config_free(OPM_PROTOCOL_CONFIG_T *);
+
+static OPM_SCAN_T *libopm_scan_create(OPM_T *, OPM_REMOTE_T *);
+static void libopm_scan_free(OPM_SCAN_T *);
+
+static OPM_CONNECTION_T *libopm_connection_create(void);
+static void libopm_connection_free(OPM_CONNECTION_T *);
+
+static void libopm_check_establish(OPM_T *);
+static void libopm_check_poll(OPM_T *);
+static void libopm_check_closed(OPM_T *);
+static void libopm_check_queue(OPM_T *);
+
+static void libopm_do_connect(OPM_T *, OPM_SCAN_T *, OPM_CONNECTION_T *);
+static void libopm_do_readready(OPM_T *, OPM_SCAN_T *, OPM_CONNECTION_T *);
+static int libopm_do_readready_tls(OPM_T *, OPM_SCAN_T *, OPM_CONNECTION_T *);
+static void libopm_do_writeready(OPM_T *, OPM_SCAN_T *, OPM_CONNECTION_T *);
+static void libopm_do_hup(OPM_T *, OPM_SCAN_T *, OPM_CONNECTION_T *);
+static void libopm_do_read(OPM_T *, OPM_SCAN_T *, OPM_CONNECTION_T *);
+static void libopm_do_openproxy(OPM_T *, OPM_SCAN_T *, OPM_CONNECTION_T *);
+static void libopm_do_callback(OPM_T *, OPM_REMOTE_T *, int, int);
+
+static OPM_REMOTE_T *libopm_setup_remote(OPM_REMOTE_T *, OPM_CONNECTION_T *);
+
+
+/* OPM_PROTOCOLS hash
+ *
+ * OPM_PPROTOCOLS hashes the protocol types (int) to functions
+ * which handle the protocol (sending/receiving protocol specific
+ * data).
+ *
+ */
+static OPM_PROTOCOL_T OPM_PROTOCOLS[] =
+{
+ { OPM_TYPE_HTTP, libopm_proxy_http_write, NULL, 0 },
+ { OPM_TYPE_SOCKS4, libopm_proxy_socks4_write, NULL, 0 },
+ { OPM_TYPE_SOCKS5, libopm_proxy_socks5_write, NULL, 0 },
+ { OPM_TYPE_ROUTER, libopm_proxy_router_write, NULL, 0 },
+ { OPM_TYPE_WINGATE, libopm_proxy_wingate_write, NULL, 0 },
+ { OPM_TYPE_HTTPPOST, libopm_proxy_httppost_write, NULL, 0 },
+ { OPM_TYPE_DREAMBOX, libopm_proxy_dreambox_write, NULL, 0 },
+ { OPM_TYPE_HTTPS, libopm_proxy_https_write, libopm_do_readready_tls, 1 },
+ { OPM_TYPE_HTTPSPOST, libopm_proxy_httpspost_write, libopm_do_readready_tls, 1 },
+ { OPM_TYPE_SSH, NULL, NULL, 0 }
+};
+
+/* opm_create
+ *
+ * Initialize a new scanner and return a pointer to it.
+ *
+ * Parameters:
+ * None
+ *
+ * Return
+ * Pointer to new OPM_T (scanner)
+ */
+OPM_T *
+opm_create(void)
+{
+ OPM_T *ret;
+
+ ret = libopm_calloc(sizeof(*ret));
+ ret->config = libopm_config_create();
+
+ /* Setup callbacks */
+ ret->callbacks = libopm_calloc(sizeof(OPM_CALLBACK_T) * CBLEN);
+
+ return ret;
+}
+
+/* opm_remote_create
+ *
+ * Create OPM_REMOTE_T struct, fill it with neccessary
+ * default values and return it to the client.
+ *
+ * Parameters:
+ * ip: IP of remote host
+ *
+ * Return:
+ * Address of OPM_REMOTE_T created
+ *
+ */
+OPM_REMOTE_T *
+opm_remote_create(const char *ip)
+{
+ OPM_REMOTE_T *ret;
+
+ ret = libopm_calloc(sizeof(*ret));
+ ret->ip = libopm_strdup(ip);
+
+ return ret;
+}
+
+/* opm_remote_free
+ *
+ * Free OPM_REMOTE_T struct and cleanup
+ *
+ * Parameters:
+ * remote: Struct to free
+ *
+ * Return:
+ * None
+ */
+void
+opm_remote_free(OPM_REMOTE_T *remote)
+{
+ OPM_NODE_T *p, *next;
+ OPM_PROTOCOL_CONFIG_T *ppc;
+
+ libopm_free(remote->ip);
+
+ LIST_FOREACH_SAFE(p, next, remote->protocols.head)
+ {
+ ppc = p->data;
+
+ libopm_protocol_config_free(ppc);
+ libopm_list_remove(&remote->protocols, p);
+ libopm_node_free(p);
+ }
+
+ libopm_free(remote);
+}
+
+/* opm_callback
+ * Register scanner level callback
+ *
+ * Parameters
+ * scanner: scanner struct
+ * type: callback type
+ * Return:
+ * Error code
+ */
+
+OPM_ERR_T
+opm_callback(OPM_T *scanner, int type, OPM_CALLBACK_FUNC *function, void *data)
+{
+ if (type < 0 || type >= CBLEN)
+ return OPM_ERR_CBNOTFOUND;
+
+ scanner->callbacks[type].func = function;
+ scanner->callbacks[type].data = data;
+
+ return OPM_SUCCESS;
+}
+
+/* opm_free
+ *
+ * Free OPM_T (scanner) and cleanup
+ *
+ * Parameters:
+ * scanner: Address of OPM_T to cleanup
+ *
+ * Return:
+ * None
+ */
+void
+opm_free(OPM_T *scanner)
+{
+ OPM_NODE_T *p, *next;
+ OPM_PROTOCOL_CONFIG_T *ppc;
+ OPM_SCAN_T *scan;
+
+ libopm_config_free(scanner->config);
+
+ LIST_FOREACH_SAFE(p, next, scanner->protocols.head)
+ {
+ ppc = p->data;
+
+ libopm_protocol_config_free(ppc);
+ libopm_list_remove(&scanner->protocols, p);
+ libopm_node_free(p);
+ }
+
+ LIST_FOREACH_SAFE(p, next, scanner->scans.head)
+ {
+ scan = p->data;
+
+ libopm_scan_free(scan);
+ libopm_list_remove(&scanner->scans, p);
+ libopm_node_free(p);
+ }
+
+ LIST_FOREACH_SAFE(p, next, scanner->queue.head)
+ {
+ scan = p->data;
+
+ libopm_scan_free(scan);
+ libopm_list_remove(&scanner->queue, p);
+ libopm_node_free(p);
+ }
+
+ libopm_free(scanner->callbacks);
+ libopm_free(scanner);
+}
+
+/* opm_config
+ *
+ * Wrapper to config_set. Set configuration variables
+ * on the config struct.
+ *
+ * Parameters:
+ * scanner: OPM_T struct the config struct resides in
+ * key: Variable within the config struct to set
+ * value: Address of value to set variable (key) to
+ *
+ * Return:
+ * OPM_ERR_T containing error code
+ */
+OPM_ERR_T
+opm_config(OPM_T *scanner, int key, const void *value)
+{
+ return libopm_config_set(scanner->config, key, value);
+}
+
+/* opm_addtype
+ *
+ * Add a proxy type and port to the list of protocols
+ * a scanner will use.
+ *
+ * Parameters:
+ * scanner: pointer to scanner struct
+ * type: type of proxy to scan (used in hashing to the functions)
+ * port: port this specific type/protocol will scan on
+ * Return:
+ * OPM_SUCCESS: Successful protocol add
+ * OPM_ERR_BADPROTOCOL: Protocol is unknown
+ */
+OPM_ERR_T
+opm_addtype(OPM_T *scanner, int type, unsigned short int port)
+{
+ OPM_NODE_T *node;
+ OPM_PROTOCOL_CONFIG_T *protocol_config;
+
+ for (unsigned int i = 0; i < sizeof(OPM_PROTOCOLS) / sizeof(OPM_PROTOCOL_T); ++i)
+ {
+ if (type == OPM_PROTOCOLS[i].type)
+ {
+#ifndef HAVE_LIBCRYPTO
+ if (OPM_PROTOCOLS[i].use_tls)
+ return OPM_ERR_BADPROTOCOL;
+#endif
+ protocol_config = libopm_protocol_config_create();
+ protocol_config->type = &OPM_PROTOCOLS[i];
+ protocol_config->port = port;
+
+ node = libopm_node_create(protocol_config);
+ libopm_list_add(&scanner->protocols, node);
+
+ return OPM_SUCCESS;
+ }
+ }
+
+ return OPM_ERR_BADPROTOCOL;
+}
+
+/* opm_remote_addtype
+ *
+ * Add a proxy type and port to the list of protocols
+ * a scanner will use.
+ *
+ * Parameters:
+ * remote: pointer to scanner struct
+ * type: type of proxy to scan (used in hashing to the functions)
+ * port: port this specific type/protocol will scan on
+ * Return:
+ * OPM_SUCCESS: Successful protocol add
+ * OPM_ERR_BADPROTOCOL: Protocol is unknown
+ */
+OPM_ERR_T opm_remote_addtype(OPM_REMOTE_T *remote, int type, unsigned short int port)
+{
+ OPM_NODE_T *node;
+ OPM_PROTOCOL_CONFIG_T *protocol_config;
+
+ for (unsigned int i = 0; i < sizeof(OPM_PROTOCOLS) / sizeof(OPM_PROTOCOL_T); ++i)
+ {
+ if (type == OPM_PROTOCOLS[i].type)
+ {
+#ifndef HAVE_LIBCRYPTO
+ if (OPM_PROTOCOLS[i].use_tls)
+ return OPM_ERR_BADPROTOCOL;
+#endif
+ protocol_config = libopm_protocol_config_create();
+ protocol_config->type = &OPM_PROTOCOLS[i];
+ protocol_config->port = port;
+
+ node = libopm_node_create(protocol_config);
+ libopm_list_add(&remote->protocols, node);
+
+ return OPM_SUCCESS;
+ }
+ }
+
+ return OPM_ERR_BADPROTOCOL;
+}
+
+/* libopm_protocol_config_create
+ *
+ * Allocate and return address of a new OPM_PROTOCOL_CONFIG_T
+ *
+ * Parameters:
+ * None
+ *
+ * Return:
+ * Address of new OPM_PROTOCOL_CONFIG_T
+ */
+static OPM_PROTOCOL_CONFIG_T *
+libopm_protocol_config_create(void)
+{
+ OPM_PROTOCOL_CONFIG_T *ret;
+
+ ret = libopm_calloc(sizeof(*ret));
+
+ return ret;
+}
+
+/* protocol_config_free
+ *
+ * Free OPM_PROTOCOL_CONFIG_T struct
+ *
+ * Parameters:
+ * protocol: struct to free
+ *
+ * Return:
+ * None
+ */
+static void
+libopm_protocol_config_free(OPM_PROTOCOL_CONFIG_T *protocol)
+{
+ libopm_free(protocol);
+}
+
+/* opm_scan
+ *
+ * Scan remote host. The opm_scan function takes an OPM_REMOTE_T
+ * struct, calculates the in_addr of the remote host, and creates
+ * a scan list based on protocols defined in the scanner.
+ *
+ * Parameters:
+ * scanner: Scanner to scan host on
+ * remote: OPM_REMOTE_T defining remote host
+ *
+ * Return:
+ * (to be written)
+ */
+OPM_ERR_T
+opm_scan(OPM_T *scanner, OPM_REMOTE_T *remote)
+{
+ OPM_SCAN_T *scan; /* New scan for OPM_T */
+ OPM_NODE_T *node; /* Node we'll add scan to when we link it to scans */
+ struct in_addr in;
+
+ if (LIST_SIZE(&scanner->protocols) == 0 &&
+ LIST_SIZE(&remote->protocols) == 0)
+ return OPM_ERR_NOPROTOCOLS;
+
+ /*
+ * XXX: libopm ideally shouldn't see an IP address in string representation.
+ * Could have been stuffed into the _OPM_REMOTE struct by the caller that
+ * already does getaddrinfo() anyway.
+ */
+ if (inet_pton(AF_INET, remote->ip, &in) <= 0)
+ return OPM_ERR_BADADDR;
+
+ scan = libopm_scan_create(scanner, remote);
+ memcpy(&scan->addr.sin_addr, &in, sizeof(scan->addr.sin_addr));
+
+ node = libopm_node_create(scan);
+ libopm_list_add(&scanner->queue, node);
+
+ return OPM_SUCCESS;
+}
+
+/* opm_end
+ *
+ * End a scan prematurely.
+ *
+ * Parameters:
+ * scanner: Scanner to end scan on
+ * remote: Pointer to remote struct to search for and end
+ *
+ * Return:
+ * No return. OPM_CALLBACK_END will still be called as normal.
+ */
+void
+opm_end(OPM_T *scanner, OPM_REMOTE_T *remote)
+{
+ OPM_NODE_T *node1, *node2, *next1, *next2;
+ OPM_SCAN_T *scan;
+ OPM_CONNECTION_T *conn;
+
+ /* End active scans */
+ opm_endscan(scanner, remote);
+
+ /*
+ * Secondly remove all traces of it in the queue. Once removed we have to call
+ * OPM_CALLBACK_END
+ */
+ LIST_FOREACH_SAFE(node1, next1, scanner->queue.head)
+ {
+ scan = node1->data;
+
+ if (scan->remote == remote)
+ {
+ /* Free all connections */
+ LIST_FOREACH_SAFE(node2, next2, scan->connections.head)
+ {
+ conn = node2->data;
+
+ libopm_list_remove(&scan->connections, node2);
+ libopm_connection_free(conn);
+ libopm_node_free(node2);
+ continue;
+ }
+
+ /* OPM_CALLBACK_END because check_closed normally handles this */
+ libopm_do_callback(scanner, scan->remote, OPM_CALLBACK_END, 0);
+
+ /* Free up the scan */
+ libopm_list_remove(&scanner->queue, node1);
+ libopm_scan_free(scan);
+ libopm_node_free(node1);
+ }
+ }
+}
+
+/* opm_endscan
+ *
+ * End a scan prematurely. Only end non-queued scans. This is useful
+ * because it only checks the active scan list (saving time), where
+ * opm_end checks both the scan and the possibly large queue.
+ *
+ * Parameters:
+ * scanner: Scanner to end scan on
+ * remote: Pointer to remote struct to search for and end
+ *
+ * Return:
+ * No return. OPM_CALLBACK_END will still be called as normal.
+ */
+void
+opm_endscan(OPM_T *scanner, OPM_REMOTE_T *remote)
+{
+ OPM_NODE_T *node1, *node2;
+ OPM_SCAN_T *scan;
+ OPM_CONNECTION_T *conn;
+
+ /*
+ * First check to see if it's in the queue, if it is set all connections closed
+ * Next cycle of libopm_check_closed will take care of the garbage and handle
+ * OPM_CALLBACK_END
+ */
+ LIST_FOREACH(node1, scanner->scans.head)
+ {
+ scan = node1->data;
+
+ if (scan->remote == remote)
+ {
+ LIST_FOREACH(node2, scan->connections.head)
+ {
+ conn = node2->data;
+ conn->state = OPM_STATE_CLOSED;
+ }
+ }
+ }
+}
+
+/* opm_active
+
+ Return number of scans in a scanner left.
+
+ Parameters:
+ scanner: Scanner to return active scans on
+
+ Return:
+ Number of active scans, both queued and active.
+*/
+size_t
+opm_active(OPM_T *scanner)
+{
+ return LIST_SIZE(&scanner->queue) + LIST_SIZE(&scanner->scans);
+}
+
+/* scan_create
+ *
+ * Create new OPM_SCAN_T struct
+ *
+ * Parameters:
+ * scanner: Scanner the scan is being created for. This
+ * is needed to get information on currently set
+ * protocols/config.
+ *
+ * remote: Remote host this scan will be scanning
+ *
+ * Return
+ * Address of new struct
+ */
+static OPM_SCAN_T *
+libopm_scan_create(OPM_T *scanner, OPM_REMOTE_T *remote)
+{
+ OPM_SCAN_T *ret;
+ OPM_CONNECTION_T *conn;
+ OPM_NODE_T *node, *p;
+#ifdef HAVE_LIBCRYPTO
+ static int tls_init = 0;
+ static SSL_CTX *ctx_client;
+
+ if (!tls_init)
+ {
+ tls_init = 1;
+ SSLeay_add_ssl_algorithms();
+
+ ctx_client = SSL_CTX_new(SSLv23_client_method());
+ if (!ctx_client)
+ exit(EXIT_FAILURE);
+ }
+#endif
+
+ ret = libopm_calloc(sizeof(*ret));
+ ret->remote = remote;
+
+ /* Setup list of connections, one for each protocol */
+ LIST_FOREACH(p, scanner->protocols.head)
+ {
+ conn = libopm_connection_create();
+
+ conn->protocol = ((OPM_PROTOCOL_CONFIG_T *)p->data)->type;
+ conn->port = ((OPM_PROTOCOL_CONFIG_T *)p->data)->port;
+
+#ifdef HAVE_LIBCRYPTO
+ if (conn->protocol->use_tls)
+ /* SSL_new does only fail if OOM in which case HOPM exits anyway */
+ conn->tls_handle = SSL_new(ctx_client);
+#endif
+
+ node = libopm_node_create(conn);
+ libopm_list_add(&ret->connections, node);
+ }
+
+ /*
+ * Do the same for any specific protocols the remote struct might be configured with
+ */
+ LIST_FOREACH(p, remote->protocols.head)
+ {
+ conn = libopm_connection_create();
+
+ conn->protocol = ((OPM_PROTOCOL_CONFIG_T *)p->data)->type;
+ conn->port = ((OPM_PROTOCOL_CONFIG_T *)p->data)->port;
+
+#ifdef HAVE_LIBCRYPTO
+ if (conn->protocol->use_tls)
+ /* SSL_new does only fail if OOM in which case HOPM exits anyway */
+ conn->tls_handle = SSL_new(ctx_client);
+#endif
+
+ node = libopm_node_create(conn);
+ libopm_list_add(&ret->connections, node);
+ }
+
+ return ret;
+}
+
+/* scan_free
+ *
+ * Free and cleanup OPM_SCAN_T struct
+ *
+ * Parametsr:
+ * scan: Scan struct to free
+ *
+ * Return:
+ * None
+ */
+static void
+libopm_scan_free(OPM_SCAN_T *scan)
+{
+ OPM_NODE_T *p, *next;
+ OPM_CONNECTION_T *conn;
+
+ LIST_FOREACH_SAFE(p, next, scan->connections.head)
+ {
+ conn = p->data;
+
+ libopm_connection_free(conn);
+ libopm_list_remove(&scan->connections, p);
+ libopm_node_free(p);
+ }
+
+ libopm_free(scan);
+}
+
+/* connection_create
+ *
+ * Allocate new OPM_CONNECTION_T
+ *
+ * Parameters:
+ * None
+ *
+ * Return:
+ * Address of new OPM_CONNECTION_T
+ */
+static OPM_CONNECTION_T *
+libopm_connection_create(void)
+{
+ OPM_CONNECTION_T *ret;
+
+ ret = libopm_calloc(sizeof(*ret));
+ ret->state = OPM_STATE_UNESTABLISHED;
+
+ return ret;
+}
+
+/* connection_free
+ *
+ * Free OPM_CONNECTION_T struct
+ *
+ * Parameters:
+ * conn: Address of struct to free
+ *
+ * Return:
+ * None
+ */
+static void
+libopm_connection_free(OPM_CONNECTION_T *conn)
+{
+ libopm_free(conn);
+}
+
+/* opm_cycle
+ *
+ * Perform tasks (called by client's loop)
+ *
+ * Parameters:
+ * None
+ * Return:
+ * None
+ */
+void
+opm_cycle(OPM_T *scanner)
+{
+ libopm_check_queue(scanner); /* Move scans from the queue to the live scan list */
+ libopm_check_establish(scanner); /* Make new connections if possible */
+ libopm_check_poll(scanner); /* Poll connections for IO and proxy test */
+ libopm_check_closed(scanner); /* Check for closed or timed out connections */
+}
+
+/* check_queue
+ *
+ * Move scans from the queue to the live scan list as long as there is
+ * room.
+ *
+ * Parameters:
+ * scanner: Scanner to check queue on
+ *
+ * Return:
+ * None
+ */
+static void
+libopm_check_queue(OPM_T *scanner)
+{
+ OPM_NODE_T *node;
+ OPM_SCAN_T *scan;
+ unsigned int protocols, projected, fd_limit;
+
+ if (LIST_SIZE(&scanner->queue) == 0)
+ return;
+
+ fd_limit = *(int *)libopm_config(scanner->config, OPM_CONFIG_FD_LIMIT);
+ projected = scanner->fd_use;
+
+ /*
+ * We want to keep the live scan list as small as possible, so only move
+ * queued scans to the live list if they will not push above fd_limit
+ */
+ while (LIST_SIZE(&scanner->queue) > 0)
+ {
+ /* Grab the top scan */
+ scan = scanner->queue.head->data;
+ protocols = LIST_SIZE(&scan->connections);
+
+ /* Check if it will fit in the live scan list */
+ if ((protocols + projected) > fd_limit)
+ break;
+
+ /*
+ * Scans on the top of the queue were added first, swap the head off the
+ * top of the queue and add it to the tail of the live scan list
+ */
+ node = libopm_list_remove(&scanner->queue, scanner->queue.head);
+ libopm_list_add(&scanner->scans, node);
+ projected += protocols;
+ }
+}
+
+/* check_establish
+ *
+ * Make new connections if there are free file descriptors and connections
+ * to be made.
+ *
+ * Parameters:
+ * scanner: Scanner to check for establish on
+ * Return:
+ * None
+ */
+static void
+libopm_check_establish(OPM_T *scanner)
+{
+ OPM_NODE_T *node1, *node2;
+ OPM_SCAN_T *scan;
+ OPM_CONNECTION_T *conn;
+ unsigned int fd_limit;
+
+ if (LIST_SIZE(&scanner->scans) == 0)
+ return;
+
+ fd_limit = *(int *)libopm_config(scanner->config, OPM_CONFIG_FD_LIMIT);
+
+ if (scanner->fd_use >= fd_limit)
+ return;
+
+ LIST_FOREACH(node1, scanner->scans.head)
+ {
+ scan = node1->data;
+
+ LIST_FOREACH(node2, scan->connections.head)
+ {
+ /* Only scan if we have free file descriptors */
+ if (scanner->fd_use >= fd_limit)
+ return;
+
+ conn = node2->data;
+
+ if (conn->state == OPM_STATE_UNESTABLISHED)
+ libopm_do_connect(scanner, scan, conn);
+ }
+ }
+}
+
+/* check_closed
+ *
+ * Check for connections which have timed out or are
+ * closed. Connections timed out still need to be closed.
+ *
+ * Remove the connection from the list of connections, free
+ * the connection struct and free the list node. Then if this is
+ * the last connection of the scan, consider the scan completed and
+ * free the scan aswell (and callback that the scan ended).
+ *
+ * Parameters:
+ * scanner: Scanner to check on
+ * Return:
+ * None
+ */
+static void
+libopm_check_closed(OPM_T *scanner)
+{
+ time_t present;
+ int timeout;
+ OPM_NODE_T *node1, *node2, *next1, *next2;
+ OPM_SCAN_T *scan;
+ OPM_CONNECTION_T *conn;
+
+ if (LIST_SIZE(&scanner->scans) == 0)
+ return;
+
+ time(&present);
+ timeout = *(int *)libopm_config(scanner->config, OPM_CONFIG_TIMEOUT);
+
+ LIST_FOREACH_SAFE(node1, next1, scanner->scans.head)
+ {
+ scan = node1->data;
+
+ LIST_FOREACH_SAFE(node2, next2, scan->connections.head)
+ {
+ conn = node2->data;
+
+ if (conn->state == OPM_STATE_CLOSED)
+ {
+#ifdef HAVE_LIBCRYPTO
+ if (conn->protocol->use_tls)
+ {
+ SSL_set_shutdown(conn->tls_handle, SSL_RECEIVED_SHUTDOWN);
+ if (!SSL_shutdown(conn->tls_handle))
+ SSL_shutdown(conn->tls_handle);
+ SSL_free(conn->tls_handle);
+ }
+#endif
+ if (conn->fd > -1)
+ close(conn->fd);
+
+ scanner->fd_use--;
+
+ libopm_list_remove(&scan->connections, node2);
+ libopm_connection_free(conn);
+ libopm_node_free(node2);
+ continue;
+ }
+
+ if (((present - conn->creation) >= timeout) && conn->state != OPM_STATE_UNESTABLISHED)
+ {
+#ifdef HAVE_LIBCRYPTO
+ if (conn->protocol->use_tls)
+ {
+ SSL_set_shutdown(conn->tls_handle, SSL_RECEIVED_SHUTDOWN);
+ if (!SSL_shutdown(conn->tls_handle))
+ SSL_shutdown(conn->tls_handle);
+ SSL_free(conn->tls_handle);
+ }
+#endif
+ if (conn->fd > -1)
+ close(conn->fd);
+
+ scanner->fd_use--;
+
+ libopm_do_callback(scanner, libopm_setup_remote(scan->remote, conn), OPM_CALLBACK_TIMEOUT, 0);
+ libopm_list_remove(&scan->connections, node2);
+ libopm_connection_free(conn);
+ libopm_node_free(node2);
+ continue;
+ }
+ }
+
+ /*
+ * No more connections left in this scan, let the client know the scan has
+ * ended, then remove the scan from the scanner, and free it up.
+ */
+ if (LIST_SIZE(&scan->connections) == 0)
+ {
+ libopm_do_callback(scanner, scan->remote, OPM_CALLBACK_END, 0);
+ libopm_list_remove(&scanner->scans, node1);
+ libopm_scan_free(scan);
+ libopm_node_free(node1);
+ }
+ }
+}
+
+/* do_connect
+ *
+ * Call socket() and connect() to start a scan.
+ *
+ * Parametsr:
+ * scan: Scan struct containing the connection
+ * conn: Connection to establish
+ * Return:
+ * None
+ */
+static void
+libopm_do_connect(OPM_T * scanner, OPM_SCAN_T *scan, OPM_CONNECTION_T *conn)
+{
+ struct sockaddr_in *bind_ip;
+ struct sockaddr_in *addr; /* Outgoing host */
+ struct sockaddr_in local_addr; /* For binding */
+
+ addr = &scan->addr; /* Already have the IP in byte format from opm_scan */
+ addr->sin_family = AF_INET;
+ addr->sin_port = htons(conn->port);
+
+ bind_ip = (struct sockaddr_in *)libopm_config(scanner->config, OPM_CONFIG_BIND_IP);
+
+ conn->fd = socket(AF_INET, SOCK_STREAM, 0);
+ scanner->fd_use++; /* Increase file descriptor use */
+
+ if (conn->fd == -1)
+ {
+ libopm_do_callback(scanner, libopm_setup_remote(scan->remote, conn), OPM_CALLBACK_ERROR, OPM_ERR_NOFD);
+ conn->state = OPM_STATE_CLOSED;
+ return;
+ }
+
+ if (bind_ip)
+ {
+ memset(&local_addr, 0, sizeof(local_addr));
+
+ local_addr.sin_addr.s_addr = bind_ip->sin_addr.s_addr;
+ local_addr.sin_family = AF_INET;
+ local_addr.sin_port = htons(0);
+
+ if (bind(conn->fd, (struct sockaddr *)&local_addr, sizeof(local_addr)) == -1)
+ {
+ libopm_do_callback(scanner, libopm_setup_remote(scan->remote, conn), OPM_CALLBACK_ERROR, OPM_ERR_BIND);
+ conn->state = OPM_STATE_CLOSED;
+ return;
+ }
+ }
+
+ /* Set socket non blocking */
+ fcntl(conn->fd, F_SETFL, O_NONBLOCK);
+
+ connect(conn->fd, (struct sockaddr *)addr, sizeof(*addr));
+
+#ifdef HAVE_LIBCRYPTO
+ if (conn->protocol->use_tls)
+ SSL_set_fd(conn->tls_handle, conn->fd);
+#endif
+
+ conn->state = OPM_STATE_ESTABLISHED;
+ time(&conn->creation); /* Stamp creation time, for timeout */
+}
+
+/* check_poll
+ *
+ * Check sockets for ready read/write
+ *
+ * Parameters:
+ * scanner: Scanner to isolate check on
+ * Return:
+ * None
+ */
+static void
+libopm_check_poll(OPM_T *scanner)
+{
+ OPM_NODE_T *node1, *node2;
+ OPM_SCAN_T *scan;
+ OPM_CONNECTION_T *conn;
+ unsigned int size = 0;
+ static unsigned int ufds_size;
+ static struct pollfd *ufds = NULL;
+
+ /* Grow pollfd array (ufds) as needed */
+ if (ufds_size < (*(unsigned int *)libopm_config(scanner->config, OPM_CONFIG_FD_LIMIT)))
+ {
+ libopm_free(ufds);
+
+ ufds = libopm_calloc((sizeof *ufds) * (*(unsigned int *)libopm_config(scanner->config, OPM_CONFIG_FD_LIMIT)));
+ ufds_size = (*(unsigned int *)libopm_config(scanner->config, OPM_CONFIG_FD_LIMIT));
+ }
+
+ if (LIST_SIZE(&scanner->scans) == 0)
+ return;
+
+ LIST_FOREACH(node1, scanner->scans.head)
+ {
+ scan = node1->data;
+
+ LIST_FOREACH(node2, scan->connections.head)
+ {
+ if (size >= ufds_size)
+ break;
+
+ conn = node2->data;
+
+ if (conn->state < OPM_STATE_ESTABLISHED ||
+ conn->state == OPM_STATE_CLOSED)
+ continue;
+
+ ufds[size].events = 0;
+ ufds[size].revents = 0;
+ ufds[size].fd = conn->fd;
+
+ /* Check for HUNG UP. */
+ ufds[size].events |= POLLHUP;
+ /* Check for INVALID FD */
+ ufds[size].events |= POLLNVAL;
+
+ switch (conn->state)
+ {
+ case OPM_STATE_ESTABLISHED:
+ ufds[size].events |= POLLOUT;
+ break;
+ case OPM_STATE_NEGSENT:
+ ufds[size].events |= POLLIN;
+ break;
+ }
+
+ size++;
+ }
+ }
+
+ switch (poll(ufds, size, 0))
+ {
+ case -1:
+ /* error in select/poll */
+ return;
+ case 0:
+ /* Nothing to do */
+ return;
+
+ /* Pass pointer to connection to handler. */
+ }
+
+ LIST_FOREACH(node1, scanner->scans.head)
+ {
+ scan = node1->data;
+
+ LIST_FOREACH(node2, scan->connections.head)
+ {
+ conn = node2->data;
+
+ for (unsigned int i = 0; i < size; ++i)
+ {
+ if ((ufds[i].fd == conn->fd) && (conn->state != OPM_STATE_CLOSED))
+ {
+ if (ufds[i].revents & POLLIN)
+ libopm_do_readready(scanner, scan, conn);
+ if (ufds[i].revents & POLLOUT)
+ libopm_do_writeready(scanner, scan, conn);
+ if (ufds[i].revents & POLLHUP)
+ libopm_do_hup(scanner, scan, conn);
+ }
+ }
+ }
+ }
+}
+
+static int
+libopm_do_readready_tls(OPM_T *scanner, OPM_SCAN_T *scan, OPM_CONNECTION_T *conn)
+{
+#ifdef HAVE_LIBCRYPTO
+ int max_read, length;
+ char readbuf[LIBOPM_TLS_RECORD_SIZE];
+
+ if (!SSL_is_init_finished(conn->tls_handle))
+ return 0;
+
+ if ((length = SSL_read(conn->tls_handle, readbuf, sizeof(readbuf))) <= 0)
+ {
+ switch (SSL_get_error(conn->tls_handle, length))
+ {
+ /* TBD: possibly could recover here from some errors */
+ default:
+ libopm_do_hup(scanner, scan, conn);
+ return 0;
+ }
+ }
+
+ max_read = *(int *)libopm_config(scanner->config, OPM_CONFIG_MAX_READ);
+
+ for (const char *p = readbuf, *end = readbuf + length; p < end; ++p)
+ {
+ conn->bytes_read++;
+
+ if (conn->bytes_read >= max_read)
+ {
+ libopm_do_callback(scanner, libopm_setup_remote(scan->remote, conn), OPM_CALLBACK_ERROR, OPM_ERR_MAX_READ);
+ conn->state = OPM_STATE_CLOSED;
+ return 0;
+ }
+
+ if (*p == '\0' || *p == '\r')
+ continue;
+
+ if (*p == '\n')
+ {
+ conn->readbuf[conn->readlen] = '\0';
+ conn->readlen = 0;
+
+ libopm_do_read(scanner, scan, conn);
+
+ if (conn->state == OPM_STATE_CLOSED)
+ return 0;
+
+ continue;
+ }
+
+ if (conn->readlen < READBUFLEN)
+ conn->readbuf[++(conn->readlen) - 1] = *p; /* -1 to pad for null term */
+ }
+#endif
+ return 0;
+}
+
+/* do_readready
+ *
+ * Remote connection is read ready, read the data into a buffer and check it against
+ * the target_string if neccessary
+ *
+ * Parameters:
+ * scanner: Scanner doing the scan
+ * scan: Specific scan
+ * conn: Specific connection in the scan
+ *
+ * Return:
+ * None
+ */
+static void
+libopm_do_readready(OPM_T *scanner, OPM_SCAN_T *scan, OPM_CONNECTION_T *conn)
+{
+ int max_read;
+ char c;
+
+ /*
+ * If protocol has a specific read function, call that instead of
+ * reading data from here.
+ */
+ if (conn->protocol->read_function)
+ {
+ conn->protocol->read_function(scanner, scan, conn);
+ return;
+ }
+
+ max_read = *(int *)libopm_config(scanner->config, OPM_CONFIG_MAX_READ);
+
+ while (1)
+ {
+ switch (read(conn->fd, &c, 1))
+ {
+ case 0:
+ libopm_do_hup(scanner, scan, conn);
+ return;
+
+ case -1:
+ if (errno != EAGAIN)
+ libopm_do_hup(scanner, scan, conn);
+ return;
+
+ default:
+ conn->bytes_read++;
+
+ if (conn->bytes_read >= max_read)
+ {
+ libopm_do_callback(scanner, libopm_setup_remote(scan->remote, conn), OPM_CALLBACK_ERROR, OPM_ERR_MAX_READ);
+ conn->state = OPM_STATE_CLOSED;
+ return;
+ }
+
+ if (c == '\0' || c == '\r')
+ continue;
+
+ if (c == '\n')
+ {
+ conn->readbuf[conn->readlen] = '\0';
+ conn->readlen = 0;
+
+ libopm_do_read(scanner, scan, conn);
+
+ if (conn->state == OPM_STATE_CLOSED)
+ return;
+
+ continue;
+ }
+
+ if (conn->readlen < READBUFLEN)
+ conn->readbuf[++(conn->readlen) - 1] = c; /* -1 to pad for null term */
+ }
+ }
+}
+
+/* do_read
+ *
+ * A line of data has been read from the socket, check it against
+ * target string.
+ *
+ *
+ *
+ * Parameters:
+ * scanner: Scanner doing the scan
+ * scan: Specific scan
+ * conn: Specific connection in the scan
+ *
+ * Return:
+ * None
+ */
+static void
+libopm_do_read(OPM_T *scanner, OPM_SCAN_T *scan, OPM_CONNECTION_T *conn)
+{
+ OPM_LIST_T *list;
+ OPM_NODE_T *node;
+
+ /* Check readbuf against target strings */
+ list = (OPM_LIST_T *)libopm_config(scanner->config, OPM_CONFIG_TARGET_STRING);
+
+ LIST_FOREACH(node, list->head)
+ {
+ const char *target_string = node->data;
+
+ if (strstr(conn->readbuf, target_string))
+ {
+ libopm_do_openproxy(scanner, scan, conn);
+ break;
+ }
+ }
+}
+
+/* do_openproxy
+ *
+ * An open proxy was found on connection conn. Cleanup the connection and
+ * call the appropriate callback to let the client know the proxy was found.
+ *
+ * Parameters:
+ * scanner: Scanner doing the scan
+ * scan: Specific scan
+ * conn: Specific connection in the scan
+ *
+ * Return:
+ * None
+ */
+static void
+libopm_do_openproxy(OPM_T *scanner, OPM_SCAN_T *scan, OPM_CONNECTION_T *conn)
+{
+ /* Mark the connection for close */
+ conn->state = OPM_STATE_CLOSED;
+
+ /* Call client's open proxy callback */
+ libopm_do_callback(scanner, libopm_setup_remote(scan->remote, conn), OPM_CALLBACK_OPENPROXY, 0);
+}
+
+/* do_writeready
+ *
+ * Remote connection is write ready, call the specific protocol
+ * function for writing to this socket.
+ *
+ * Parameters:
+ * scanner: Scanner doing the scan
+ * scan: Specific scan
+ * conn: Specific connection in the scan
+ *
+ * Return:
+ * None
+ */
+static void
+libopm_do_writeready(OPM_T *scanner, OPM_SCAN_T *scan, OPM_CONNECTION_T *conn)
+{
+ OPM_PROTOCOL_T *protocol;
+
+#ifdef HAVE_LIBCRYPTO
+ if (conn->protocol->use_tls)
+ {
+ if (!SSL_is_init_finished(conn->tls_handle))
+ {
+ SSL_connect(conn->tls_handle);
+ return;
+ }
+ }
+#endif
+
+ protocol = conn->protocol;
+
+ /* Call write function for specific protocol */
+ if (protocol->write_function)
+ protocol->write_function(scanner, scan, conn);
+
+ /* Flag as NEGSENT so we don't have to send data again*/
+ conn->state = OPM_STATE_NEGSENT;
+}
+
+/* do_hup
+ *
+ * Connection ended prematurely
+ *
+ * Parameters:
+ * scanner: Scanner doing the scan
+ * scan: Specific scan
+ * conn: Specific connection in the scan
+ * error: OPM_ERR_T containing the error type
+ * Return:
+ * None
+ */
+static void
+libopm_do_hup(OPM_T *scanner, OPM_SCAN_T *scan, OPM_CONNECTION_T *conn)
+{
+ /* Mark the connection for close */
+ conn->state = OPM_STATE_CLOSED;
+
+ libopm_do_callback(scanner, libopm_setup_remote(scan->remote, conn), OPM_CALLBACK_NEGFAIL, 0);
+}
+
+/* do_callback
+ *
+ * Call callback
+ *
+ * Parameters:
+ * scanner: scanner remote is on
+ * remote: remote callback is for
+ * type: callback type
+ * var: optional var passed back (error codes, etc )
+ * Return:
+ * None
+ */
+static void
+libopm_do_callback(OPM_T *scanner, OPM_REMOTE_T *remote, int type, int var)
+{
+ /* Callback is out of range */
+ if (type < 0 || type >= CBLEN)
+ return;
+
+ if (scanner->callbacks[type].func)
+ (scanner->callbacks[type].func)(scanner, remote, var, scanner->callbacks[type].data);
+}
+
+/* setup_remote
+ *
+ * Setup an OPM_REMOTE_T with information from an OPM_CONNECTION_T
+ * for callback
+ *
+ * Parameters:
+ * remote, conn
+ *
+ * Return:
+ * remote
+ */
+static OPM_REMOTE_T *
+libopm_setup_remote(OPM_REMOTE_T *remote, OPM_CONNECTION_T *conn)
+{
+ remote->port = conn->port;
+ remote->bytes_read = conn->bytes_read;
+ remote->protocol = conn->protocol->type;
+
+ return remote;
+}
diff --git a/src/libopm/src/libopm.h b/src/libopm/src/libopm.h
new file mode 100644
index 0000000..ca03512
--- /dev/null
+++ b/src/libopm/src/libopm.h
@@ -0,0 +1,63 @@
+#ifndef LIBOPM_H
+#define LIBOPM_H
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include "config.h"
+#include "opm_common.h"
+#include "opm.h"
+
+#define CBLEN 5 /* Number of callback functions */
+#define READBUFLEN 128 /* Size of conn->readbuf */
+#define SENDBUFLEN 512 /* Size of sendbuffer in proxy.c */
+#define LIBOPM_TLS_RECORD_SIZE 16384
+
+typedef struct _OPM_SCAN OPM_SCAN_T;
+typedef struct _OPM_CONNECTION OPM_CONNECTION_T;
+typedef struct _OPM_PROTOCOL_CONFIG OPM_PROTOCOL_CONFIG_T;
+typedef struct _OPM_PROTOCOL OPM_PROTOCOL_T;
+
+/*
+ * Types of hard coded proxy READ/WRITE functions which are
+ * setup in a table in libopm.c
+ */
+typedef int OPM_PROXYWRITE_T (OPM_T *, OPM_SCAN_T *, OPM_CONNECTION_T *);
+typedef int OPM_PROXYREAD_T (OPM_T *, OPM_SCAN_T *, OPM_CONNECTION_T *);
+
+struct _OPM_SCAN
+{
+ struct sockaddr_in addr; /* Address in byte order of remote client */
+ OPM_REMOTE_T *remote; /* Pointed to the OPM_REMOTE_T for this scan, passed by client */
+ OPM_LIST_T connections; /* List of individual connections of this scan (1 for each protocol) */
+};
+
+struct _OPM_CONNECTION
+{
+ OPM_PROTOCOL_T *protocol; /* Pointer to specific protocol this connection handles */
+ unsigned short int port; /* Some protocols have multiple ports, eg. HTTP */
+ int fd; /* Allocated file descriptor, 0 if not yet allocated */
+ unsigned short int bytes_read; /* Bytes read so far in this connection */
+ char readbuf[READBUFLEN + 1]; /* 128 byte read buffer, anything over 128 is probably not of use */
+ unsigned short int readlen; /* Length of readbuf */
+ unsigned short int state; /* State of connection */
+ time_t creation; /* When this connection was established */
+ void *tls_handle; /* SSL structure created by SSL_new() */
+};
+
+struct _OPM_PROTOCOL_CONFIG
+{
+ OPM_PROTOCOL_T *type; /* Protocol type */
+ unsigned short int port; /* Port to connect on */
+};
+
+struct _OPM_PROTOCOL
+{
+ int type; /* Protocol type */
+ OPM_PROXYWRITE_T *write_function; /* Write function handler for this protocol */
+ OPM_PROXYREAD_T *read_function; /* Read function handler for this protocol */
+ int use_tls; /* TLS/SSL-enabled protocol such as HTTPS */
+};
+#endif /* LIBOPM_H */
diff --git a/src/libopm/src/list.c b/src/libopm/src/list.c
new file mode 100644
index 0000000..b730b73
--- /dev/null
+++ b/src/libopm/src/list.c
@@ -0,0 +1,97 @@
+/*
+ * Copyright (c) 2002-2003 Erik Fears
+ * Copyright (c) 2014-2018 ircd-hybrid 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 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
+ * USA
+ */
+
+/*! \file list.c
+ * \brief Maintains doubly-linked lists.
+ * \version $Id$
+ */
+
+#include "setup.h"
+
+#include <stdlib.h>
+#include <assert.h>
+
+#include "opm_common.h"
+#include "list.h"
+#include "memory.h"
+
+
+OPM_NODE_T *
+libopm_node_create(void *data)
+{
+ OPM_NODE_T *node = libopm_calloc(sizeof *node);
+
+ node->data = data;
+
+ return node;
+}
+
+OPM_NODE_T *
+libopm_list_add(OPM_LIST_T *list, OPM_NODE_T *node)
+{
+ node->prev = NULL;
+ node->next = list->head;
+
+ /* Assumption: If list->tail != NULL, list->head != NULL */
+ if (list->head)
+ list->head->prev = node;
+ else if (list->tail == NULL)
+ list->tail = node;
+
+ list->head = node;
+ list->elements++;
+
+ return node;
+}
+
+OPM_NODE_T *
+libopm_list_remove(OPM_LIST_T *list, OPM_NODE_T *node)
+{
+ /* Assumption: If node->next == NULL, then list->tail == node
+ * and: If node->prev == NULL, then list->head == node
+ */
+ if (node->next)
+ node->next->prev = node->prev;
+ else
+ {
+ assert(list->tail == node);
+ list->tail = node->prev;
+ }
+
+ if (node->prev)
+ node->prev->next = node->next;
+ else
+ {
+ assert(list->head == node);
+ list->head = node->next;
+ }
+
+ /* Set this to NULL does matter */
+ node->next = node->prev = NULL;
+ list->elements--;
+
+ return node;
+}
+
+void
+libopm_node_free(OPM_NODE_T *node)
+{
+ libopm_free(node);
+}
diff --git a/src/libopm/src/list.h b/src/libopm/src/list.h
new file mode 100644
index 0000000..c18f099
--- /dev/null
+++ b/src/libopm/src/list.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2002-2003 Erik Fears
+ * Copyright (c) 2014-2018 ircd-hybrid 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 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
+ * USA
+ */
+
+/*! \file list.h
+ * \brief A header for the list manipulation routines.
+ * \version $Id$
+ */
+
+#ifndef LIST_H
+#define LIST_H
+
+#define LIST_FOREACH(pos, head) for (pos = (head); pos != NULL; pos = pos->next)
+#define LIST_FOREACH_SAFE(pos, n, head) for (pos = (head), n = pos ? pos->next : NULL; pos != NULL; pos = n, n = pos ? pos->next : NULL)
+#define LIST_FOREACH_PREV(pos, head) for (pos = (head); pos != NULL; pos = pos->prev)
+#define LIST_SIZE(list) (list)->elements
+
+extern OPM_NODE_T *libopm_node_create(void *);
+
+extern OPM_NODE_T *libopm_list_add(OPM_LIST_T *, OPM_NODE_T *);
+extern OPM_NODE_T *libopm_list_remove(OPM_LIST_T *, OPM_NODE_T *);
+
+extern void libopm_node_free(OPM_NODE_T *);
+#endif /* LIST_H */
diff --git a/src/libopm/src/memory.c b/src/libopm/src/memory.c
new file mode 100644
index 0000000..ec54c6c
--- /dev/null
+++ b/src/libopm/src/memory.c
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2002 Erik Fears
+ * Copyright (c) 2014-2018 ircd-hybrid 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 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
+ * USA
+ */
+
+#include <stdlib.h>
+#include <assert.h>
+#include <string.h>
+
+#include "memory.h"
+
+
+/* libopm_calloc
+ *
+ * A wrapper function for malloc(), for catching memory issues
+ * and error handling.
+ *
+ * Parameters
+ * bytes: amount in bytes to allocate
+ *
+ * Return:
+ * Pointer to allocated memory
+ */
+void *
+libopm_calloc(size_t bytes)
+{
+ void *ret = calloc(1, bytes);
+ assert(ret);
+
+ return ret;
+}
+
+/* libopm_free
+ *
+ * Free memory allocated with xcalloc
+ *
+ * Parameters:
+ * var: pointer to memory to free
+ *
+ * Return:
+ * None
+ */
+void
+libopm_free(void *ptr)
+{
+ free(ptr);
+}
+
+void *
+libopm_strdup(const char *s)
+{
+ void *ret = malloc(strlen(s) + 1);
+
+ assert(ret);
+ strcpy(ret, s);
+
+ return ret;
+}
diff --git a/src/libopm/src/memory.h b/src/libopm/src/memory.h
new file mode 100644
index 0000000..24ef445
--- /dev/null
+++ b/src/libopm/src/memory.h
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2002 Erik Fears
+ * Copyright (c) 2014-2018 ircd-hybrid 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 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
+ * USA
+ */
+
+#ifndef MALLOC_H
+#define MALLOC_H
+
+extern void *libopm_calloc(size_t);
+extern void libopm_free(void *);
+extern void *libopm_strdup(const char *);
+
+#endif /* MALLOC_H */
diff --git a/src/libopm/src/opm.h b/src/libopm/src/opm.h
new file mode 100644
index 0000000..3d98634
--- /dev/null
+++ b/src/libopm/src/opm.h
@@ -0,0 +1,70 @@
+/** \file opm.h
+ * \brief Main header for libopm.
+ * \author Erik Fears
+ * \version $Id$
+ */
+
+#ifndef OPM_H
+#define OPM_H
+
+#include "opm_common.h"
+
+typedef struct _OPM_CONFIG OPM_CONFIG_T;
+typedef struct _OPM OPM_T;
+typedef struct _OPM_REMOTE OPM_REMOTE_T;
+typedef struct _OPM_CALLBACK OPM_CALLBACK_T;
+
+typedef int OPM_ERR_T;
+
+typedef void OPM_CALLBACK_FUNC (OPM_T *, OPM_REMOTE_T *, int, void *);
+
+struct _OPM_CALLBACK
+{
+ OPM_CALLBACK_FUNC *func;
+ void *data;
+};
+
+struct _OPM_CONFIG
+{
+ void **vars;
+};
+
+struct _OPM
+{
+ OPM_CONFIG_T *config; /* Individual scanner configuration */
+ OPM_LIST_T queue; /* List of scans in the queue (not yet established) */
+ OPM_LIST_T scans; /* List of scans (each scan containing a list of connections) */
+ OPM_LIST_T protocols; /* List of protocols this scanner handles */
+ unsigned int fd_use; /* Number of file descriptors in use */
+ OPM_CALLBACK_T *callbacks; /* Scanner wide callbacks */
+};
+
+struct _OPM_REMOTE
+{
+ char *ip; /* Readable IP address */
+ unsigned short int port; /* Port passed back on certain callbacks */
+ unsigned short int protocol; /* Protocol passed back on certain callbacks */
+ unsigned short int bytes_read; /* Bytes read passed back on certain callbacks */
+ OPM_LIST_T protocols; /* Remote specific protocols */
+ void *data; /* Arbitrary data that the client can point to for any purpose*/
+};
+
+extern OPM_T *opm_create(void);
+extern void opm_free(OPM_T *);
+
+extern OPM_REMOTE_T *opm_remote_create(const char *);
+extern void opm_remote_free(OPM_REMOTE_T *);
+
+extern OPM_ERR_T opm_config(OPM_T *, int, const void *);
+extern OPM_ERR_T opm_scan(OPM_T *, OPM_REMOTE_T *);
+extern void opm_end(OPM_T *, OPM_REMOTE_T *);
+extern void opm_endscan(OPM_T *, OPM_REMOTE_T *);
+
+extern OPM_ERR_T opm_addtype(OPM_T *, int, unsigned short int);
+extern OPM_ERR_T opm_remote_addtype(OPM_REMOTE_T *, int, unsigned short int);
+extern OPM_ERR_T opm_callback(OPM_T *, int, OPM_CALLBACK_FUNC *, void *);
+
+extern void opm_cycle(OPM_T *);
+
+extern size_t opm_active(OPM_T *);
+#endif /* OPM_H */
diff --git a/src/libopm/src/opm_common.h b/src/libopm/src/opm_common.h
new file mode 100644
index 0000000..8472331
--- /dev/null
+++ b/src/libopm/src/opm_common.h
@@ -0,0 +1,21 @@
+#ifndef OPM_COMMON_H
+#define OPM_COMMON_H
+
+typedef struct _libopm_node OPM_NODE_T;
+typedef struct _libopm_list OPM_LIST_T;
+
+
+struct _libopm_list
+{
+ struct _libopm_node *head;
+ struct _libopm_node *tail;
+ unsigned int elements;
+};
+
+struct _libopm_node
+{
+ struct _libopm_node *next;
+ struct _libopm_node *prev;
+ void *data;
+};
+#endif /* OPM_COMMON_H */
diff --git a/src/libopm/src/opm_error.h b/src/libopm/src/opm_error.h
new file mode 100644
index 0000000..ec55793
--- /dev/null
+++ b/src/libopm/src/opm_error.h
@@ -0,0 +1,26 @@
+#ifndef LIBOPM_ERROR_H
+#define LIBOPM_ERROR_H
+
+/* Success */
+#define OPM_SUCCESS 1
+
+/* Configuration Errors */
+#define OPM_ERR_BADKEY 2 /* Unknown or bad key value */
+#define OPM_ERR_BADVALUE 3 /* Bad value matching key */
+#define OPM_ERR_BADPROTOCOL 4 /* Unknown protocol in config */
+
+/* Read Errors */
+#define OPM_ERR_MAX_READ 5 /* Socket reached MAX_READ */
+
+/* Callback Registration Errors */
+#define OPM_ERR_CBNOTFOUND 6 /* Callback is out of range */
+
+/* opm_scan errors */
+#define OPM_ERR_BADADDR 7 /* IP in remote struct is bad */
+#define OPM_ERR_NOPROTOCOLS 8 /* No protocols to scan! */
+
+/* bind/connect errors */
+#define OPM_ERR_BIND 9 /* Error binding to BIND_IP */
+#define OPM_ERR_NOFD 10 /* Unable to allocate file descriptor */
+
+#endif /* LIBOPM_ERROR_H */
diff --git a/src/libopm/src/opm_types.h b/src/libopm/src/opm_types.h
new file mode 100644
index 0000000..d00994b
--- /dev/null
+++ b/src/libopm/src/opm_types.h
@@ -0,0 +1,49 @@
+#ifndef OPM_TYPES_H
+#define OPM_TYPES_H
+
+/* Configuration Directives */
+#define OPM_CONFIG_FD_LIMIT 0
+#define OPM_CONFIG_BIND_IP 1
+#define OPM_CONFIG_DNSBL_HOST 2
+#define OPM_CONFIG_TARGET_STRING 3
+#define OPM_CONFIG_SCAN_IP 4
+#define OPM_CONFIG_SCAN_PORT 5
+#define OPM_CONFIG_MAX_READ 6
+#define OPM_CONFIG_TIMEOUT 7
+
+/* Configuration Variable Types */
+#define OPM_TYPE_INT 1
+#define OPM_TYPE_STRING 2
+#define OPM_TYPE_ADDRESS 3
+#define OPM_TYPE_STRINGLIST 4
+
+/* Protocols */
+#define OPM_TYPE_HTTP 1
+#define OPM_TYPE_SOCKS4 2
+#define OPM_TYPE_SOCKS5 3
+#define OPM_TYPE_WINGATE 4
+#define OPM_TYPE_ROUTER 5
+#define OPM_TYPE_HTTPPOST 6
+#define OPM_TYPE_DREAMBOX 7
+#define OPM_TYPE_HTTPS 8
+#define OPM_TYPE_HTTPSPOST 9
+#define OPM_TYPE_SSH 10
+
+/* States */
+#define OPM_STATE_UNESTABLISHED 1
+#define OPM_STATE_ESTABLISHED 2
+#define OPM_STATE_NEGSENT 3
+#define OPM_STATE_CLOSED 4
+
+
+/*
+ * Callbacks -- If more callback types are added, CBLEN will
+ * need to be changed in libopm.h accordingly
+ */
+#define OPM_CALLBACK_OPENPROXY 0 /* An open proxy has been found REMOTE/SCANNER */
+#define OPM_CALLBACK_NEGFAIL 1 /* Negotiation to a proxy has failed REMOTE/SCANNER */
+#define OPM_CALLBACK_END 2 /* A scan has ended REMOTE/SCANNER */
+#define OPM_CALLBACK_ERROR 3 /* An unrecoverable error has occured */
+#define OPM_CALLBACK_TIMEOUT 4 /* Specific scan (protocol) on host has timed out */
+
+#endif /* OPM_TYPES_H */
diff --git a/src/libopm/src/proxy.c b/src/libopm/src/proxy.c
new file mode 100644
index 0000000..84baadf
--- /dev/null
+++ b/src/libopm/src/proxy.c
@@ -0,0 +1,316 @@
+/* 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 <stdlib.h>
+#include <string.h>
+#ifdef HAVE_LIBCRYPTO
+#include <openssl/ssl.h>
+#endif
+
+#include "config.h"
+#include "proxy.h"
+#include "opm_common.h"
+#include "opm_types.h"
+#include "opm_error.h"
+#include "libopm.h"
+
+
+static char SENDBUF[SENDBUFLEN + 1];
+
+int
+libopm_proxy_http_write(OPM_T *scanner, OPM_SCAN_T *scan, OPM_CONNECTION_T *conn)
+{
+ size_t len = snprintf(SENDBUF, SENDBUFLEN, "CONNECT %s:%d HTTP/1.0\r\n\r\n",
+ (char *)libopm_config(scanner->config, OPM_CONFIG_SCAN_IP),
+ *(int *)libopm_config(scanner->config, OPM_CONFIG_SCAN_PORT));
+
+ if (send(conn->fd, SENDBUF, len, 0) == -1)
+ return 0; /* Return error code ? */
+
+ /* extra linefeed required for MikroTik HttpProxy, must be separate send() */
+ send(conn->fd, "\r\n", 2, 0);
+
+ return OPM_SUCCESS;
+}
+
+/*
+ * 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)
+ */
+int
+libopm_proxy_socks4_write(OPM_T *scanner, OPM_SCAN_T *scan, OPM_CONNECTION_T *conn)
+{
+ size_t len;
+ struct in_addr addr;
+ unsigned long laddr;
+ int scan_port;
+ char *scan_ip;
+
+ scan_ip = (char *)libopm_config(scanner->config, OPM_CONFIG_SCAN_IP);
+ scan_port = *(int *)libopm_config(scanner->config, OPM_CONFIG_SCAN_PORT);
+
+ if (inet_pton(AF_INET, scan_ip, &addr) <= 0)
+ ; /* handle error */
+
+ laddr = htonl(addr.s_addr);
+
+ len = snprintf(SENDBUF, SENDBUFLEN, "%c%c%c%c%c%c%c%c%c", 4, 1,
+ (((unsigned short)scan_port) >> 8) & 0xFF,
+ (((unsigned short)scan_port) & 0xFF),
+ (char)(laddr >> 24) & 0xFF, (char)(laddr >> 16) & 0xFF,
+ (char)(laddr >> 8) & 0xFF, (char)laddr & 0xFF, 0);
+
+ send(conn->fd, SENDBUF, len, 0);
+
+ return OPM_SUCCESS;
+}
+
+/*
+ * 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'
+ *
+ *
+ *
+ * The SOCKS request is formed as follows:
+ *
+ * +----+-----+-------+------+----------+----------+
+ * |VER | CMD | RSV | ATYP | DST.ADDR | DST.PORT |
+ * +----+-----+-------+------+----------+----------+
+ * | 1 | 1 | X'00' | 1 | Variable | 2 |
+ * +----+-----+-------+------+----------+----------+
+ *
+ *
+ * o VER protocol version: X'05'
+ * o CMD
+ * o CONNECT X'01'
+ * o BIND X'02'
+ * o UDP ASSOCIATE X'03'
+ * o RSV RESERVED
+ * o ATYP address type of following address
+ * o IP V4 address: X'01'
+ * o DOMAINNAME: X'03'
+ * o IP V6 address: X'04'
+ * o DST.ADDR desired destination address
+ * o DST.PORT desired destination port in network octet
+ * order
+ *
+ *
+ */
+int
+libopm_proxy_socks5_write(OPM_T *scanner, OPM_SCAN_T *scan, OPM_CONNECTION_T *conn)
+{
+ size_t len;
+ struct in_addr addr;
+ unsigned long laddr;
+ int scan_port;
+ char *scan_ip;
+
+ scan_ip = (char *)libopm_config(scanner->config, OPM_CONFIG_SCAN_IP);
+ scan_port = *(int *)libopm_config(scanner->config, OPM_CONFIG_SCAN_PORT);
+
+ if (inet_pton(AF_INET, scan_ip, &addr) <= 0)
+ ; /* handle error */
+
+ laddr = htonl(addr.s_addr);
+
+ /* Form authentication string */
+ /* Version 5, 1 number of methods, 0 method (no auth). */
+ len = snprintf(SENDBUF, SENDBUFLEN, "%c%c%c", 5, 1, 0);
+ send(conn->fd, SENDBUF, len, 0);
+
+ /* Form request string */
+
+ /*
+ * Will need to write ipv6 support here in future
+ * as socks5 is ipv6 compatible
+ */
+ len = snprintf(SENDBUF, SENDBUFLEN, "%c%c%c%c%c%c%c%c%c%c", 5, 1, 0, 1,
+ (char) (laddr >> 24) & 0xFF, (char) (laddr >> 16) & 0xFF,
+ (char) (laddr >> 8) & 0xFF, (char) laddr & 0xFF,
+ (((unsigned short) scan_port) >> 8) & 0xFF,
+ (((unsigned short) scan_port) & 0xFF));
+
+ send(conn->fd, SENDBUF, len, 0);
+
+ return OPM_SUCCESS;
+}
+
+/*
+ * Open wingates require no authentication, they will send a prompt when
+ * connect.
+ */
+int
+libopm_proxy_wingate_write(OPM_T *scanner, OPM_SCAN_T *scan, OPM_CONNECTION_T *conn)
+{
+ size_t len;
+ int scan_port;
+ char *scan_ip;
+
+ scan_ip = (char *)libopm_config(scanner->config, OPM_CONFIG_SCAN_IP);
+ scan_port = *(int *)libopm_config(scanner->config, OPM_CONFIG_SCAN_PORT);
+
+ len = snprintf(SENDBUF, SENDBUFLEN, "%s:%d\r\n", scan_ip, scan_port);
+ send(conn->fd, SENDBUF, len, 0);
+
+ return OPM_SUCCESS;
+}
+
+/*
+ * 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
+ */
+int
+libopm_proxy_router_write(OPM_T *scanner, OPM_SCAN_T *scan, OPM_CONNECTION_T *conn)
+{
+ size_t len;
+ int scan_port;
+ char *scan_ip;
+
+ scan_ip = (char *)libopm_config(scanner->config, OPM_CONFIG_SCAN_IP);
+ scan_port = *(int *)libopm_config(scanner->config, OPM_CONFIG_SCAN_PORT);
+
+ len = snprintf(SENDBUF, SENDBUFLEN, "cisco\r\n");
+ send(conn->fd, SENDBUF, len, 0);
+
+ len = snprintf(SENDBUF, SENDBUFLEN, "telnet %s %d\r\n", scan_ip, scan_port);
+ send(conn->fd, SENDBUF, len, 0);
+
+ return OPM_SUCCESS;
+}
+
+/*
+ * HTTP POST Scanning
+ *
+ */
+int
+libopm_proxy_httppost_write(OPM_T *scanner, OPM_SCAN_T *scan, OPM_CONNECTION_T *conn)
+{
+ size_t len;
+ int scan_port;
+ char *scan_ip;
+
+ scan_ip = (char *)libopm_config(scanner->config, OPM_CONFIG_SCAN_IP);
+ scan_port = *(int *)libopm_config(scanner->config, OPM_CONFIG_SCAN_PORT);
+
+ len = snprintf(SENDBUF, SENDBUFLEN,
+ "POST http://%s:%d/ HTTP/1.0\r\n"
+ "Content-type: text/plain\r\n"
+ "Content-length: 5\r\n\r\n"
+ "quit\r\n\r\n", scan_ip, scan_port);
+
+ send(conn->fd, SENDBUF, len, 0);
+
+ return OPM_SUCCESS;
+}
+
+/*
+ * Dreambox scanning
+ *
+ * Some dreambox machines have 'dreambox' as the password, and would allow
+ * full root access to telnet or install bouncers.
+ */
+int
+libopm_proxy_dreambox_write(OPM_T *scanner, OPM_SCAN_T *scan, OPM_CONNECTION_T *conn)
+{
+ size_t len;
+ int scan_port;
+ char *scan_ip;
+
+ scan_ip = (char *)libopm_config(scanner->config, OPM_CONFIG_SCAN_IP);
+ scan_port = *(int *)libopm_config(scanner->config, OPM_CONFIG_SCAN_PORT);
+
+ len = snprintf(SENDBUF, SENDBUFLEN, "root\r\n");
+ send(conn->fd, SENDBUF, len, 0);
+
+ len = snprintf(SENDBUF, SENDBUFLEN, "dreambox\r\n");
+ send(conn->fd, SENDBUF, len, 0);
+
+ len = snprintf(SENDBUF, SENDBUFLEN, "telnet %s %d\r\n", scan_ip, scan_port);
+ send(conn->fd, SENDBUF, len, 0);
+
+ len = snprintf(SENDBUF, SENDBUFLEN, "nc %s %d\r\n", scan_ip, scan_port);
+ send(conn->fd, SENDBUF, len, 0);
+
+ return OPM_SUCCESS;
+}
+
+int
+libopm_proxy_https_write(OPM_T *scanner, OPM_SCAN_T *scan, OPM_CONNECTION_T *conn)
+{
+#ifdef HAVE_LIBCRYPTO
+ size_t len = snprintf(SENDBUF, SENDBUFLEN, "CONNECT %s:%d HTTP/1.0\r\n\r\n",
+ (char *)libopm_config(scanner->config, OPM_CONFIG_SCAN_IP),
+ *(int *)libopm_config(scanner->config, OPM_CONFIG_SCAN_PORT));
+
+ SSL_write(conn->tls_handle, SENDBUF, len);
+
+ /* extra linefeed required for MikroTik HttpProxy, must be separate send() */
+ SSL_write(conn->tls_handle, "\r\n", 2);
+#endif
+ return OPM_SUCCESS;
+}
+
+/*
+ * HTTPS POST Scanning
+ *
+ */
+int
+libopm_proxy_httpspost_write(OPM_T *scanner, OPM_SCAN_T *scan, OPM_CONNECTION_T *conn)
+{
+#ifdef HAVE_LIBCRYPTO
+ size_t len;
+ int scan_port;
+ char *scan_ip;
+
+ scan_ip = (char *)libopm_config(scanner->config, OPM_CONFIG_SCAN_IP);
+ scan_port = *(int *)libopm_config(scanner->config, OPM_CONFIG_SCAN_PORT);
+
+ len = snprintf(SENDBUF, SENDBUFLEN,
+ "POST http://%s:%d/ HTTP/1.0\r\n"
+ "Content-type: text/plain\r\n"
+ "Content-length: 5\r\n\r\n"
+ "quit\r\n\r\n", scan_ip, scan_port);
+
+ SSL_write(conn->tls_handle, SENDBUF, len);
+#endif
+ return OPM_SUCCESS;
+}
diff --git a/src/libopm/src/proxy.h b/src/libopm/src/proxy.h
new file mode 100644
index 0000000..c006203
--- /dev/null
+++ b/src/libopm/src/proxy.h
@@ -0,0 +1,15 @@
+#ifndef PROXY_H
+#define PROXY_H
+
+#include "libopm.h"
+
+extern int libopm_proxy_http_write(OPM_T *, OPM_SCAN_T *, OPM_CONNECTION_T *);
+extern int libopm_proxy_socks4_write(OPM_T *, OPM_SCAN_T *, OPM_CONNECTION_T *);
+extern int libopm_proxy_socks5_write(OPM_T *, OPM_SCAN_T *, OPM_CONNECTION_T *);
+extern int libopm_proxy_wingate_write(OPM_T *, OPM_SCAN_T *, OPM_CONNECTION_T *);
+extern int libopm_proxy_router_write(OPM_T *, OPM_SCAN_T *, OPM_CONNECTION_T *);
+extern int libopm_proxy_httppost_write(OPM_T *, OPM_SCAN_T *, OPM_CONNECTION_T *);
+extern int libopm_proxy_dreambox_write(OPM_T *, OPM_SCAN_T *, OPM_CONNECTION_T *);
+extern int libopm_proxy_https_write(OPM_T *, OPM_SCAN_T *, OPM_CONNECTION_T *);
+extern int libopm_proxy_httpspost_write(OPM_T *, OPM_SCAN_T *, OPM_CONNECTION_T *);
+#endif /* PROXY_H */
diff --git a/src/list.c b/src/list.c
new file mode 100644
index 0000000..9fa2b3f
--- /dev/null
+++ b/src/list.c
@@ -0,0 +1,93 @@
+/*
+ * Copyright (c) 2002-2003 Erik Fears
+ * Copyright (c) 2014-2018 ircd-hybrid 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 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
+ * USA
+ */
+
+/*! \file list.c
+ * \brief Maintains doubly-linked lists.
+ * \version $Id$
+ */
+
+#include <stdlib.h>
+#include <assert.h>
+
+#include "memory.h"
+#include "list.h"
+
+
+node_t *
+node_create(void)
+{
+ node_t *node = xcalloc(sizeof *node);
+ return node;
+}
+
+void
+node_free(node_t *node)
+{
+ xfree(node);
+}
+
+node_t *
+list_add(void *data, node_t *node, list_t *list)
+{
+ node->data = data;
+ node->prev = NULL;
+ node->next = list->head;
+
+ /* Assumption: If list->tail != NULL, list->head != NULL */
+ if (list->head)
+ list->head->prev = node;
+ else if (list->tail == NULL)
+ list->tail = node;
+
+ list->head = node;
+ list->elements++;
+
+ return node;
+}
+
+node_t *
+list_remove(node_t *node, list_t *list)
+{
+ /* Assumption: If node->next == NULL, then list->tail == node
+ * and: If node->prev == NULL, then list->head == node
+ */
+ if (node->next)
+ node->next->prev = node->prev;
+ else
+ {
+ assert(list->tail == node);
+ list->tail = node->prev;
+ }
+
+ if (node->prev)
+ node->prev->next = node->next;
+ else
+ {
+ assert(list->head == node);
+ list->head = node->next;
+ }
+
+ /* Set this to NULL does matter */
+ node->next = NULL;
+ node->prev = NULL;
+ list->elements--;
+
+ return node;
+}
diff --git a/src/list.h b/src/list.h
new file mode 100644
index 0000000..e81a133
--- /dev/null
+++ b/src/list.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2002-2003 Erik Fears
+ * Copyright (c) 2014-2018 ircd-hybrid 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 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
+ * USA
+ */
+
+/*! \file list.h
+ * \brief A header for the list manipulation routines.
+ * \version $Id$
+ */
+
+#ifndef LIST_H
+#define LIST_H
+
+#define LIST_FOREACH(pos, head) for (pos = (head); pos != NULL; pos = pos->next)
+#define LIST_FOREACH_SAFE(pos, n, head) for (pos = (head), n = pos ? pos->next : NULL; pos != NULL; pos = n, n = pos ? pos->next : NULL)
+#define LIST_FOREACH_PREV(pos, head) for (pos = (head); pos != NULL; pos = pos->prev)
+#define LIST_SIZE(list) (list)->elements
+
+typedef struct _node node_t;
+typedef struct _list list_t;
+
+struct _list
+{
+ struct _node *head;
+ struct _node *tail;
+ unsigned int elements;
+};
+
+struct _node
+{
+ struct _node *next;
+ struct _node *prev;
+ void *data;
+};
+
+extern node_t *node_create(void);
+extern void node_free(node_t *);
+
+extern node_t *list_add(void *, node_t *, list_t *);
+extern node_t *list_remove(node_t *, list_t *);
+#endif /* LIST_H */
diff --git a/src/log.c b/src/log.c
new file mode 100644
index 0000000..c6d1f18
--- /dev/null
+++ b/src/log.c
@@ -0,0 +1,92 @@
+/*
+ * Copyright (c) 2002 Erik Fears
+ * Copyright (c) 2014-2018 ircd-hybrid 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 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
+ * USA
+ */
+
+#include "setup.h"
+
+#include <stdio.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <time.h>
+
+#include "log.h"
+#include "main.h"
+#include "misc.h"
+
+
+FILE *logfile;
+FILE *scanlogfile;
+
+void
+log_open(const char *filename)
+{
+ logfile = fopen(filename, "a");
+
+ if (logfile == NULL)
+ {
+ perror("Cannot open log file. Aborting.");
+ exit(EXIT_FAILURE);
+ }
+}
+
+void
+log_close(void)
+{
+ fclose(logfile);
+}
+
+void
+scanlog_open(const char *filename)
+{
+ scanlogfile = fopen(filename, "a");
+
+ if (scanlogfile == NULL)
+ log_printf("Failed to open scan log file: %s", strerror(errno));
+}
+
+void
+scanlog_close(void)
+{
+ if (scanlogfile)
+ fclose(scanlogfile);
+}
+
+void
+log_printf(const char *fmt, ...)
+{
+ char buf[LOG_BUFSIZE];
+ va_list args;
+
+ if (OPT_DEBUG == 0 && logfile == NULL)
+ return;
+
+ va_start(args, fmt);
+ vsnprintf(buf, sizeof(buf), fmt, args);
+ va_end(args);
+
+ if (OPT_DEBUG)
+ fprintf(stderr, "[%s] %s\n", date_iso8601(0), buf);
+ else
+ {
+ fprintf(logfile, "[%s] %s\n", date_iso8601(0), buf);
+ fflush(logfile);
+ }
+}
diff --git a/src/log.h b/src/log.h
new file mode 100644
index 0000000..3e4fac3
--- /dev/null
+++ b/src/log.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2002 Erik Fears
+ * Copyright (c) 2014-2018 ircd-hybrid 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 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
+ * USA
+ */
+
+#ifndef LOG_H
+#define LOG_H
+
+enum { LOG_BUFSIZE = 512 };
+
+extern void log_open(const char *);
+extern void log_close(void);
+extern void scanlog_open(const char *);
+extern void scanlog_close(void);
+#ifdef __GNUC__
+extern void log_printf(const char *, ...) __attribute__((format(printf,1,2)));
+#else
+extern void log_printf(const char *, ...);
+#endif
+#endif
diff --git a/src/main.c b/src/main.c
new file mode 100644
index 0000000..ead870f
--- /dev/null
+++ b/src/main.c
@@ -0,0 +1,283 @@
+/*
+ * Copyright (c) 2002-2003 Erik Fears
+ * Copyright (c) 2014-2018 ircd-hybrid 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 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
+ * USA
+ */
+
+#include "setup.h"
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <signal.h>
+#include <unistd.h>
+#include <errno.h>
+#include <sys/resource.h> /* getrlimit */
+#include <fcntl.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "config.h"
+#include "irc.h"
+#include "log.h"
+#include "opercmd.h"
+#include "scan.h"
+#include "options.h"
+#include "memory.h"
+#include "main.h"
+
+
+static int RESTART; /* Flagged to restart on next cycle */
+static int ALARMED; /* Flagged to call timer functions on next cycle */
+static int REOPEN; /* Flagged to reopen log files on next cycle */
+
+static struct sigaction ALARMACTION;
+static struct sigaction INTACTION;
+static struct sigaction HUPACTION;
+static struct sigaction USR1ACTION;
+
+static const char *CONFNAME = DEFAULTNAME;
+static const char *CONFDIR = HOPM_ETCDIR;
+static const char *LOGDIR = HOPM_LOGDIR;
+static char *CONFFILE, *LOGFILE;
+
+unsigned int OPT_DEBUG = 0; /* Debug level */
+
+
+static void
+setup_corelimit(void)
+{
+ struct rlimit rlim;
+
+ if (getrlimit(RLIMIT_CORE, &rlim) == 0)
+ {
+ rlim.rlim_cur = rlim.rlim_max;
+ setrlimit(RLIMIT_CORE, &rlim);
+ }
+}
+
+static void
+do_signal(int signum)
+{
+ switch (signum)
+ {
+ case SIGALRM:
+ ALARMED = 1;
+ alarm(1);
+ break;
+ case SIGINT:
+ log_printf("MAIN -> Caught SIGINT, bye!");
+ exit(0);
+ break;
+ case SIGHUP:
+ RESTART = 1;
+ break;
+ case SIGUSR1:
+ REOPEN = 1;
+ break;
+ }
+}
+
+int
+main(int argc, char *argv[])
+{
+ pid_t pid;
+ size_t lenc, lenl;
+ FILE *pidout;
+ struct rlimit rlim;
+
+ setup_corelimit();
+
+ while (1)
+ {
+ int c = getopt(argc, argv, "dc:");
+ if (c == -1)
+ break;
+
+ switch (c)
+ {
+ case 'c':
+ CONFNAME = xstrdup(optarg);
+ break;
+ case 'd':
+ ++OPT_DEBUG;
+ break;
+ 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;
+
+ CONFFILE = xcalloc(lenc * sizeof *CONFFILE);
+ LOGFILE = xcalloc(lenl * sizeof *LOGFILE);
+
+ snprintf(CONFFILE, lenc, "%s/%s.%s", CONFDIR, CONFNAME, CONFEXT);
+ snprintf(LOGFILE, lenl, "%s/%s.%s", LOGDIR, CONFNAME, LOGEXT);
+
+ if (chdir(HOPM_PREFIX))
+ {
+ perror("chdir");
+ exit(EXIT_FAILURE);
+ }
+
+ /* Fork off. */
+ if (OPT_DEBUG == 0)
+ {
+ if ((pid = fork()) < 0)
+ {
+ perror("fork()");
+ exit(EXIT_FAILURE);
+ }
+ else if (pid != 0)
+ _exit(EXIT_SUCCESS);
+
+ /* Get us in our own process group. */
+ if (setpgid(0, 0) < 0)
+ {
+ perror("setpgid()");
+ exit(EXIT_FAILURE);
+ }
+
+ /* Reset file mode. */
+ umask(077); /* umask 077: u=rwx,g=,o= */
+
+ /* Close file descriptors. */
+ close(STDIN_FILENO);
+ close(STDOUT_FILENO);
+ close(STDERR_FILENO);
+
+ log_open(LOGFILE);
+ }
+ else
+ log_printf("MAIN -> Debug level %d", OPT_DEBUG);
+
+ log_printf("MAIN -> HOPM %s started.", VERSION);
+ log_printf("MAIN -> Reading configuration file...");
+
+ config_load(CONFFILE);
+
+ if (OptionsItem.scanlog)
+ scanlog_open(OptionsItem.scanlog);
+
+ pidout = fopen(OptionsItem.pidfile, "w");
+
+ if (pidout)
+ {
+ fprintf(pidout, "%u\n", (unsigned int)getpid());
+ fclose(pidout);
+ }
+ else
+ {
+ log_printf("MAIN -> Error opening pid file %s: %s", OptionsItem.pidfile,
+ strerror(errno));
+ exit(EXIT_FAILURE);
+ }
+
+ /* Setup alarm & int handlers. */
+ ALARMACTION.sa_handler = &do_signal;
+ ALARMACTION.sa_flags = SA_RESTART;
+ INTACTION.sa_handler = &do_signal;
+ HUPACTION.sa_handler = &do_signal;
+ USR1ACTION.sa_handler = &do_signal;
+
+ sigaction(SIGALRM, &ALARMACTION, NULL);
+ sigaction(SIGINT, &INTACTION, NULL);
+ sigaction(SIGHUP, &HUPACTION, NULL);
+ sigaction(SIGUSR1, &USR1ACTION, NULL);
+
+ /* Ignore SIGPIPE. */
+ signal(SIGPIPE, SIG_IGN);
+
+ alarm(1);
+
+ while (1)
+ {
+ /* Main cycles */
+ irc_cycle();
+ scan_cycle();
+
+ /* Restart HOPM if main_restart() was called (usually happens by m_kill in irc.c) */
+ if (RESTART)
+ {
+ /* If restarted in debug mode, die */
+ if (OPT_DEBUG)
+ return 1;
+
+ log_printf("MAIN -> Restarting process");
+
+ /* Get upper file descriptor limit */
+ if (getrlimit(RLIMIT_NOFILE, &rlim) == -1)
+ {
+ log_printf("MAIN RESTART -> getrlimit() error retrieving RLIMIT_NOFILE (%s)", strerror(errno));
+ return 1;
+ }
+
+ /* Set file descriptors 0-rlim_cur close on exec */
+ for (unsigned int i = 0; i < rlim.rlim_cur; ++i)
+ fcntl(i, F_SETFD, FD_CLOEXEC);
+
+ /* execute new process */
+ if (execv(HOPM_BINPATH, argv) == -1)
+ log_printf("MAIN RESTART -> Execution of \"%s\" failed. ERROR: %s", HOPM_BINPATH, strerror(errno));
+
+ exit(0); /* Should only get here if execv() failed */
+ }
+
+ /* Check for log reopen */
+ if (REOPEN)
+ {
+ log_printf("MAIN -> Caught SIGUSR1, reopening logfiles");
+ log_close();
+ log_open(LOGFILE);
+
+ if (OptionsItem.scanlog)
+ {
+ scanlog_close();
+ scanlog_open(OptionsItem.scanlog);
+ }
+
+ log_printf("MAIN -> reopened logfiles");
+
+ REOPEN = 0;
+ }
+
+ /* Call 1 second timers */
+ if (ALARMED)
+ {
+ irc_timer();
+ scan_timer();
+ command_timer();
+
+ ALARMED = 0;
+ }
+ }
+
+ if (OPT_DEBUG == 0)
+ log_close();
+
+ /* If there's no scanlog open then this will do nothing anyway */
+ scanlog_close();
+ return 0;
+}
+
+void
+main_restart(void)
+{
+ RESTART = 1;
+}
diff --git a/src/main.h b/src/main.h
new file mode 100644
index 0000000..b939962
--- /dev/null
+++ b/src/main.h
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2002-2003 Erik Fears
+ * Copyright (c) 2014-2018 ircd-hybrid 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 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
+ * USA
+ */
+
+#ifndef MAIN_H
+#define MAIN_H
+extern unsigned int OPT_DEBUG;
+
+extern void main_restart(void);
+#endif /* MAIN_H */
diff --git a/src/match.c b/src/match.c
new file mode 100644
index 0000000..4dfc839
--- /dev/null
+++ b/src/match.c
@@ -0,0 +1,156 @@
+/*
+ * ircd-hybrid: an advanced, lightweight Internet Relay Chat Daemon (ircd)
+ *
+ * Copyright (c) 1997-2018 ircd-hybrid 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 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
+ * USA
+ */
+
+/*! \file match.c
+ * \brief Functions to match/compare strings.
+ * \version $Id$
+ */
+
+#include "match.h"
+
+
+#define ToLower(c) (ToLowerTab[(unsigned char)(c)])
+
+static 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
+};
+
+/*! \brief Check a string against a mask.
+ * This test checks using traditional IRC wildcards only: '*' means
+ * match zero or more characters of any type; '?' means match exactly
+ * one character of any type. A backslash escapes the next character
+ * so that a wildcard may be matched exactly.
+ * param mask Wildcard-containing mask.
+ * param name String to check against \a mask.
+ * return Zero if \a mask matches \a name, non-zero if no match.
+ */
+int
+match(const char *mask, const char *name)
+{
+ const char *m = mask, *n = name;
+ const char *m_tmp = mask, *n_tmp = name;
+ unsigned int star = 0;
+
+ while (1)
+ {
+ switch (*m)
+ {
+ case '\0':
+ if (*n == '\0')
+ return 0;
+ backtrack:
+ if (m_tmp == mask)
+ return 1;
+
+ m = m_tmp;
+ n = ++n_tmp;
+
+ if (*n == '\0')
+ return 1;
+ break;
+ case '\\':
+ ++m;
+
+ /* allow escaping to force capitalization */
+ if (*m++ != *n++)
+ goto backtrack;
+ break;
+ case '*':
+ case '?':
+ for (star = 0; ; ++m)
+ {
+ if (*m == '*')
+ star = 1;
+ else if (*m == '?')
+ {
+ if (*n++ == '\0')
+ goto backtrack;
+ }
+ else
+ break;
+ }
+
+ if (star)
+ {
+ if (*m == '\0')
+ return 0;
+ else if (*m == '\\')
+ {
+ m_tmp = ++m;
+
+ if (*m == '\0')
+ return 1;
+ for (n_tmp = n; *n && *n != *m; ++n)
+ ;
+ }
+ else
+ {
+ m_tmp = m;
+ for (n_tmp = n; *n && (ToLower(*n) != ToLower(*m)); ++n)
+ ;
+ }
+ }
+ /* and fall through */
+ default:
+ if (*n == '\0')
+ return *m != '\0';
+ if (ToLower(*m) != ToLower(*n))
+ goto backtrack;
+ ++m;
+ ++n;
+ break;
+ }
+ }
+
+ return 1;
+}
diff --git a/src/match.h b/src/match.h
new file mode 100644
index 0000000..63de382
--- /dev/null
+++ b/src/match.h
@@ -0,0 +1,33 @@
+/*
+ * ircd-hybrid: an advanced, lightweight Internet Relay Chat Daemon (ircd)
+ *
+ * Copyright (c) 1997-2018 ircd-hybrid 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 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
+ * USA
+ */
+
+/*! \file match.h
+ * \brief Functions to match/compare strings.
+ * \version $Id$
+ */
+
+#ifndef MATCH_H
+#define MATCH_H
+
+#define EmptyString(x) (!(x) || (*(x) == '\0'))
+
+extern int match(const char *, const char *);
+#endif
diff --git a/src/memory.c b/src/memory.c
new file mode 100644
index 0000000..7550152
--- /dev/null
+++ b/src/memory.c
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2002 Erik Fears
+ * Copyright (c) 2014-2018 ircd-hybrid 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 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
+ * USA
+ */
+
+#include <stdlib.h>
+#include <assert.h>
+#include <string.h>
+
+#include "memory.h"
+
+
+/* xcalloc
+ *
+ * A wrapper function for malloc(), for catching memory issues
+ * and error handling.
+ *
+ * Parameters
+ * bytes: amount in bytes to allocate
+ *
+ * Return:
+ * Pointer to allocated memory
+ */
+void *
+xcalloc(size_t bytes)
+{
+ void *ret = calloc(1, bytes);
+ assert(ret);
+
+ return ret;
+}
+
+/* xfree
+ *
+ * Free memory allocated with xcalloc
+ *
+ * Parameters:
+ * var: pointer to memory to free
+ *
+ * Return:
+ * None
+ */
+void
+xfree(void *ptr)
+{
+ free(ptr);
+}
+
+void *
+xstrdup(const char *s)
+{
+ void *ret = malloc(strlen(s) + 1);
+
+ assert(ret);
+ strcpy(ret, s);
+
+ return ret;
+}
diff --git a/src/memory.h b/src/memory.h
new file mode 100644
index 0000000..9269f75
--- /dev/null
+++ b/src/memory.h
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2002 Erik Fears
+ * Copyright (c) 2014-2018 ircd-hybrid 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 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
+ * USA
+ */
+
+#ifndef MALLOC_H
+#define MALLOC_H
+
+extern void *xcalloc(size_t);
+extern void xfree(void *);
+extern void *xstrdup(const char *);
+
+#endif /* MALLOC_H */
diff --git a/src/misc.c b/src/misc.c
new file mode 100644
index 0000000..6ec0a4d
--- /dev/null
+++ b/src/misc.c
@@ -0,0 +1,96 @@
+/*
+ * Copyright (c) 2002 Erik Fears
+ * Copyright (c) 2014-2018 ircd-hybrid 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 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
+ * USA
+ */
+
+#include "setup.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <time.h>
+
+#include "misc.h"
+
+
+const char *
+date_iso8601(time_t lclock)
+{
+ static char buf[32];
+ static time_t lclock_last;
+
+ if (lclock == 0)
+ lclock = time(0);
+
+ if (lclock_last != lclock)
+ {
+ lclock_last = lclock;
+ strftime(buf, sizeof(buf), "%FT%T%z", localtime(&lclock));
+ }
+
+ return buf;
+}
+
+/*
+ * Split a time_t into an English-language explanation of how
+ * much time it represents, e.g. "2 hours 45 minutes 8 seconds"
+ */
+const char *
+time_dissect(time_t duration)
+{
+ static char buf[32]; /* 32 = sizeof("9999999999999999 days, 23:59:59") */
+ unsigned int days = 0, hours = 0, minutes = 0, seconds = 0;
+
+ while (duration >= 60 * 60 * 24)
+ {
+ duration -= 60 * 60 * 24;
+ ++days;
+ }
+
+ while (duration >= 60 * 60)
+ {
+ duration -= 60 * 60;
+ ++hours;
+ }
+
+ while (duration >= 60)
+ {
+ duration -= 60;
+ ++minutes;
+ }
+
+ seconds = duration;
+
+ snprintf(buf, sizeof(buf), "%u day%s, %02u:%02u:%02u",
+ days, days == 1 ? "" : "s", hours, minutes, seconds);
+ return buf;
+}
+
+const char *
+stripws(char *txt)
+{
+ while (*txt == '\t' || *txt == ' ')
+ ++txt;
+
+ char *tmp = txt + strlen(txt) - 1;
+ while (tmp >= txt && (*tmp == '\t' || *tmp == ' '))
+ --tmp;
+
+ *(tmp + 1) = '\0';
+
+ return txt;
+}
diff --git a/src/misc.h b/src/misc.h
new file mode 100644
index 0000000..aad8709
--- /dev/null
+++ b/src/misc.h
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2002 Erik Fears
+ * Copyright (c) 2014-2018 ircd-hybrid 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 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
+ * USA
+ */
+
+#ifndef MISC_H
+#define MISC_H
+
+extern const char *date_iso8601(time_t);
+extern const char *time_dissect(time_t);
+extern const char *stripws(char *);
+#endif
diff --git a/src/negcache.c b/src/negcache.c
new file mode 100644
index 0000000..070c503
--- /dev/null
+++ b/src/negcache.c
@@ -0,0 +1,125 @@
+/*
+ * Copyright (c) 2002-2003 Andy Smith
+ * Copyright (c) 2014-2018 ircd-hybrid 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 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
+ * USA
+ */
+
+/*
+ * A Negative caching implementation for IPv4/IPv6 addresses. The idea is that
+ * every time an IP address is seen, it is checked against a patricia trie. If
+ * the IP address was previously seen and within an acceptable period of time,
+ * it is not scanned again. Otherwise, the address is scanned as normal. If
+ * it is proven to be OK (i.e. it doesn't run an open proxy) then it is added
+ * to the trie.
+ */
+
+#include "setup.h"
+
+#include <time.h>
+
+#include "list.h"
+#include "patricia.h"
+#include "negcache.h"
+#include "config.h"
+#include "memory.h"
+#include "log.h"
+
+
+extern unsigned int OPT_DEBUG;
+
+static list_t negcache_list;
+static patricia_tree_t *negcache_trie;
+
+
+/*
+ * Initialise the patricia trie we use for storing our negative cache.
+ */
+void
+negcache_init(void)
+{
+ if (negcache_trie)
+ return; /* Cache already exists */
+
+ negcache_trie = patricia_new(PATRICIA_MAXBITS);
+}
+
+/*
+ * Check whether an IP address is in our negative cache and was added
+ * recently enough. Return a pointer to its node if so, NULL otherwise.
+ */
+struct negcache_item *
+negcache_check(const char *ipstr)
+{
+ if (OptionsItem.negcache == 0)
+ return NULL;
+
+ patricia_node_t *pnode = patricia_try_search_exact(negcache_trie, ipstr);
+ if (pnode)
+ {
+ struct negcache_item *n = pnode->data;
+
+ if (time(NULL) - n->seen <= OptionsItem.negcache)
+ return n;
+ }
+
+ return NULL;
+}
+
+/*
+ * Prepare an ASCII string representing an IPv4/IPv6 address for inserting into
+ * our negative cache.
+ */
+void
+negcache_insert(const char *ipstr)
+{
+ patricia_node_t *pnode = patricia_make_and_lookup(negcache_trie, ipstr);
+ if (pnode == NULL || pnode->data)
+ return; /* Malformed IP address or already added to the trie */
+
+ struct negcache_item *n = xcalloc(sizeof(*n));
+ n->seen = time(NULL);
+
+ pnode->data = n;
+ list_add(pnode, &n->node, &negcache_list);
+}
+
+/*
+ * Wrapper for recursive rebuild function.
+ */
+void
+negcache_rebuild(void)
+{
+ node_t *node, *node_next;
+
+ LIST_FOREACH_SAFE(node, node_next, negcache_list.head)
+ {
+ patricia_node_t *pnode = node->data;
+ struct negcache_item *n = pnode->data;
+
+ if (n->seen + OptionsItem.negcache < time(NULL))
+ {
+ if (OPT_DEBUG >= 2)
+ log_printf("NEGCACHE -> Deleting expired negcache node for %s added at %lu",
+ patricia_prefix_toa(pnode->prefix, 0), n->seen);
+
+ list_remove(&n->node, &negcache_list);
+
+ xfree(n);
+ patricia_remove(negcache_trie, pnode);
+ }
+ }
+}
diff --git a/src/negcache.h b/src/negcache.h
new file mode 100644
index 0000000..eef2ddb
--- /dev/null
+++ b/src/negcache.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2002-2003 Andy Smith
+ * Copyright (c) 2014-2018 ircd-hybrid 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 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
+ * USA
+ */
+
+#ifndef NEGCACHE_H
+#define NEGCACHE_H
+
+struct negcache_item
+{
+ node_t node; /**< List node; linked into negcache_list */
+ time_t seen;
+};
+
+extern void negcache_init(void);
+extern struct negcache_item *negcache_check(const char *);
+extern void negcache_insert(const char *);
+extern void negcache_rebuild(void);
+#endif
diff --git a/src/opercmd.c b/src/opercmd.c
new file mode 100644
index 0000000..0cae2ad
--- /dev/null
+++ b/src/opercmd.c
@@ -0,0 +1,302 @@
+/*
+ * Copyright (c) 2002 Erik Fears
+ * Copyright (c) 2014-2018 ircd-hybrid 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 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
+ * USA
+ */
+
+#include "setup.h"
+
+#include <string.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <time.h>
+
+#include "list.h"
+#include "options.h"
+#include "irc.h"
+#include "log.h"
+#include "main.h"
+#include "config.h"
+#include "opercmd.h"
+#include "scan.h"
+#include "memory.h"
+#include "stats.h"
+
+
+static list_t COMMANDS; /* List of active commands */
+
+
+/* cmd_check
+ *
+ * Start a manual scan on given IP address/hostname.
+ *
+ * Parameters:
+ * param: Parameters of the command
+ * target: channel command was sent to
+ *
+ */
+static void
+cmd_check(char *param, const char *target)
+{
+ scan_manual(param, target);
+}
+
+/* cmd_stat
+ *
+ * Send output of stats to channel.
+ *
+ * Parameters:
+ * param: Parameters of the command
+ * target: channel command was sent to
+ */
+static void
+cmd_stats(char *param, const char *target)
+{
+ stats_output(target);
+}
+
+/* cmd_fdstat
+ *
+ * Send output of stats to channel.
+ *
+ * Parameters:
+ * param: Parameters of the command
+ * target: channel command was sent to
+ */
+static void
+cmd_fdstat(char *param, const char *target)
+{
+ fdstats_output(target);
+}
+
+/* command_create
+ *
+ * Create a Command struct.
+ *
+ * Parameters:
+ * type: Index in COMMAND_TABLE
+ * param: Parameters to the command (NULL if there are not any)
+ * irc_nick: Nickname of user that initiated the command
+ * target: Target channel (target is ALWAYS a channel)
+ *
+ * Return:
+ * Pointer to new Command
+ */
+static struct Command *
+command_create(const struct OperCommandHash *tab, const char *param, const char *irc_nick,
+ const char *target)
+{
+ struct Command *command = xcalloc(sizeof(*command));
+
+ if (param)
+ command->param = xstrdup(param);
+
+ command->tab = tab;
+ command->irc_nick = xstrdup(irc_nick);
+ command->target = target;
+
+ time(&command->added);
+
+ return command;
+}
+
+/* command_free
+ *
+ * Free a command struct
+ *
+ * Parameters:
+ * command: Command struct to free
+ *
+ * Return: NONE
+ */
+static void
+command_free(struct Command *command)
+{
+ if (command->param)
+ xfree(command->param);
+
+ xfree(command->irc_nick);
+ xfree(command);
+}
+
+/* command_parse
+ *
+ * Parse a command to hopm (sent to a channel hopm is on). The command is parsed
+ * from the parameters, and if it is a known command it is stored in a queue. A
+ * userhost is performed on the user to check if they are an IRC operator. When
+ * a reply is returned (command_userhost), the command will be executed.
+ *
+ * Parameters:
+ * command: Command sent (including parameters)
+ * target: Channel command was sent to (we only got this far if there was only one recipient)
+ * source_p: Operator (hopefully) that sent the command.
+ *
+ */
+void
+command_parse(const char *command, const char *target, const char *source_p)
+{
+ char *param; /* Parsed parameters */
+ static const struct OperCommandHash COMMAND_TABLE[] =
+ {
+ { .command = "CHECK", .handler = cmd_check },
+ { .command = "SCAN", .handler = cmd_check },
+ { .command = "STATS", .handler = cmd_stats },
+ { .command = "FDSTAT", .handler = cmd_fdstat },
+ { .command = NULL }
+ };
+
+ if (OPT_DEBUG)
+ log_printf("COMMAND -> Parsing command (%s) from %s [%s]",
+ command, source_p, target);
+
+ /* Only allow OptionsItem.command_queue_size commands in the queue */
+ if (LIST_SIZE(&COMMANDS) >= OptionsItem.command_queue_size)
+ return;
+
+ /*
+ * Parameter is the first character in command after the first space.
+ * 'param' will be NULL if:
+ * 1. There was no space
+ * 2. There was a space but it was the last character in command, in which case
+ * param = '\0'
+ */
+
+ /* Skip past the botname/!all */
+ command = strchr(command, ' ');
+
+ /*
+ * There is no command OR there is at least nothing
+ * past that first space.
+ */
+ if (command == NULL || *++command == '\0')
+ return;
+
+ /* Find the parameters */
+ param = strchr(command, ' ');
+
+ if (param)
+ {
+ *param = '\0';
+ param++;
+ }
+
+ log_printf("COMMAND -> parsed [%s] [%s]", command, param ? param : "");
+
+ /* Lookup the command in the table */
+ for (const struct OperCommandHash *tab = COMMAND_TABLE; tab->command; ++tab)
+ {
+ if (strcasecmp(command, tab->command) == 0)
+ {
+ /* Queue this command */
+ struct Command *cmd = command_create(tab, param, source_p, target);
+
+ list_add(cmd, &cmd->node, &COMMANDS);
+ break;
+ }
+ }
+
+ irc_send("USERHOST %s", source_p);
+}
+
+/* command_timer
+ *
+ * Perform ~1 second actions.
+ *
+ * Parameters: NONE
+ *
+ * Return: NONE
+ *
+ */
+void
+command_timer(void)
+{
+ static unsigned int interval;
+ node_t *node, *node_next;
+ time_t present;
+
+ /* Only perform command removal every OptionsItem.command_interval seconds */
+ if (interval++ < OptionsItem.command_interval)
+ return;
+ else
+ interval = 0;
+
+ time(&present);
+
+ LIST_FOREACH_SAFE(node, node_next, COMMANDS.head)
+ {
+ struct Command *command = node->data;
+
+ if ((present - command->added) > OptionsItem.command_timeout)
+ {
+ list_remove(&command->node, &COMMANDS);
+ command_free(command); /* Cleanup the command */
+ }
+ else /* Since the queue is in order, it's also ordered by time, no nodes after this will be timed out */
+ return;
+ }
+}
+
+/* command_userhost
+ *
+ * A 302 reply was received. The reply is parsed to check if the
+ * user was an operator. If so any commands they had queued are
+ * executed.
+ *
+ * Parameters:
+ * reply: Reply to USERHOST (ex: :grifferz*=+goats@pc-62-30-219-54-pb.blueyonder.co.uk)
+ *
+ * Return: NONE
+ *
+ */
+void
+command_userhost(const char *reply)
+{
+ node_t *node, *node_next;
+ char *tmp;
+ int oper = 0;
+
+ tmp = strchr(reply, '=');
+
+ /* They quit, ignore it */
+ if (tmp == NULL)
+ return;
+
+ /* Operators have a * flag in a USERHOST reply */
+ if (*(tmp - 1) == '*')
+ oper = 1;
+
+ /* Null terminate it so tmp = the oper's nick */
+ if (oper)
+ *(--tmp) = '\0';
+ else
+ *(tmp) = '\0';
+
+ /* Find any queued commands that match this user */
+ LIST_FOREACH_SAFE(node, node_next, COMMANDS.head)
+ {
+ struct Command *command = node->data;
+
+ if (strcmp(command->irc_nick, reply) == 0)
+ {
+ if (oper)
+ command->tab->handler(command->param, command->target);
+
+ list_remove(&command->node, &COMMANDS);
+ command_free(command); /* Cleanup the command */
+ }
+ }
+}
diff --git a/src/opercmd.h b/src/opercmd.h
new file mode 100644
index 0000000..8220801
--- /dev/null
+++ b/src/opercmd.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2002 Erik Fears
+ * Copyright (c) 2014-2018 ircd-hybrid 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 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
+ * USA
+ */
+
+#ifndef OPERCMD_H
+#define OPERCMD_H
+
+struct OperCommandHash
+{
+ const char *command;
+ void (*handler)(char *, const char *);
+};
+
+struct Command
+{
+ node_t node; /**< List node; linked into COMMANDS */
+
+ /* Points to specific entry in COMMAND_TABLE in opercmd.c */
+ const struct OperCommandHash *tab;
+
+ /* Command parameter.
+ * <erik> but i cant think of any commands bopm will ever have that is
+ * multiple parameters
+ *
+ * I still havn't -Erik 12/11/02
+ */
+ char *param;
+
+ /* Who ordered it. */
+ char *irc_nick;
+
+ /* Where the reply is to be sent. */
+ const char *target;
+
+ /*
+ * When it was added, because we might need to remove it if it does
+ * not get executed.
+ */
+ time_t added;
+};
+
+extern void command_init(void);
+extern void command_userhost(const char *);
+extern void command_timer(void);
+extern void command_parse(const char *, const char *, const char *);
+#endif
diff --git a/src/options.h b/src/options.h
new file mode 100644
index 0000000..2a0db3c
--- /dev/null
+++ b/src/options.h
@@ -0,0 +1,13 @@
+#ifndef OPTIONS_H
+#define OPTIONS_H
+
+/* The default name for conf, log, pid files */
+#define DEFAULTNAME "hopm"
+
+/* file extensions */
+/* config */
+#define CONFEXT "conf"
+
+/* log file */
+#define LOGEXT "log"
+#endif /* OPTIONS_H */
diff --git a/src/patchlevel.h b/src/patchlevel.h
new file mode 100644
index 0000000..bc7b009
--- /dev/null
+++ b/src/patchlevel.h
@@ -0,0 +1,8 @@
+/*! \file patchlevel.h
+ * \brief A header defining the patchlevel.
+ * \version $Id$
+ */
+
+#ifndef PATCHLEVEL
+#define PATCHLEVEL "hopm-1.1.5"
+#endif
diff --git a/src/patricia.c b/src/patricia.c
new file mode 100644
index 0000000..c2c972a
--- /dev/null
+++ b/src/patricia.c
@@ -0,0 +1,977 @@
+/*
+ * $Id: patricia.c 7851 2016-11-06 18:19:57Z michael $
+ * Dave Plonka <plonka@doit.wisc.edu>
+ *
+ * This file had been called "radix.c" in the MRT sources.
+ *
+ * I renamed it to "patricia.c" since it's not an implementation of a general
+ * radix trie. Also I pulled in various requirements from "prefix.c" and
+ * "demo.c" so that it could be used as a standalone API.
+ *
+ * Copyright (c) 1999-2013
+ *
+ * The Regents of the University of Michigan ("The Regents") and Merit
+ * Network, Inc.
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <assert.h> /* assert */
+#include <stddef.h> /* NULL */
+#include <stdio.h> /* sprintf, fprintf, stderr */
+#include <stdlib.h> /* free, atol, calloc */
+#include <string.h> /* memcpy, strchr, strlen */
+#include <sys/types.h> /* BSD: for inet_addr */
+#include <sys/socket.h> /* BSD, Linux: for inet_addr */
+#include <netinet/in.h> /* BSD, Linux: for inet_addr */
+#include <arpa/inet.h> /* BSD, Linux, Solaris: for inet_addr */
+
+#include "patricia.h"
+#include "memory.h"
+
+/* { from prefix.c */
+
+/* prefix_tochar
+ * convert prefix information to bytes
+ */
+static unsigned char *
+prefix_tochar(prefix_t *prefix)
+{
+ if (prefix == NULL)
+ return NULL;
+ return (unsigned char *)&prefix->add.sin;
+}
+
+static int
+comp_with_mask(void *addr, void *dest, unsigned int mask)
+{
+ if ( /* mask/8 == 0 || */ memcmp(addr, dest, mask / 8) == 0)
+ {
+ int n = mask / 8;
+ int m = ((-1) << (8 - (mask % 8)));
+
+ if (mask % 8 == 0 || (((unsigned char *)addr)[n] & m) == (((unsigned char *)dest)[n] & m))
+ return 1;
+ }
+
+ return 0;
+}
+
+/*
+ * convert prefix information to ascii string with length
+ */
+const char *
+patricia_prefix_toa(const prefix_t *prefix, int with_len)
+{
+ static char buf[INET6_ADDRSTRLEN + sizeof("/128")];
+
+ assert(prefix);
+ assert(prefix->ref_count >= 0);
+ assert((prefix->family == AF_INET && prefix->bitlen <= 32) ||
+ (prefix->family == AF_INET6 && prefix->bitlen <= 128));
+
+ inet_ntop(prefix->family, &prefix->add.sin6, buf, INET6_ADDRSTRLEN);
+
+ if (with_len)
+ sprintf(buf + strlen(buf), "/%d", prefix->bitlen);
+ return buf;
+}
+
+static prefix_t *
+New_Prefix2(int family, void *dest, int bitlen, prefix_t *prefix)
+{
+ int dynamic_allocated = 0;
+ int addr_size = 0;
+
+ switch (family)
+ {
+ case AF_INET:
+ addr_size = sizeof(struct in_addr);
+ break;
+ case AF_INET6:
+ addr_size = sizeof(struct in6_addr);
+ break;
+ default: return NULL;
+ }
+
+ if (prefix == NULL)
+ {
+ prefix = xcalloc(sizeof(prefix_t));
+ dynamic_allocated = 1;
+ }
+
+ memcpy(&prefix->add.sin6, dest, addr_size);
+ prefix->bitlen = (bitlen >= 0) ? bitlen : addr_size * 8;
+ prefix->family = family;
+ prefix->ref_count = dynamic_allocated == 1;
+
+/* fprintf(stderr, "[C %s, %d]\n", patricia_prefix_toa(prefix), prefix->ref_count); */
+ return prefix;
+}
+
+static prefix_t *
+New_Prefix(int family, void *dest, int bitlen)
+{
+ return New_Prefix2(family, dest, bitlen, NULL);
+}
+
+/* ascii2prefix
+ */
+static prefix_t *
+ascii2prefix(int family, const char *string)
+{
+ int bitlen, maxbitlen = 0;
+ union
+ {
+ struct in_addr sin;
+ struct in6_addr sin6;
+ } sin;
+
+ assert(string);
+
+ /* Easy way to handle both families */
+ if (family == 0)
+ {
+ family = AF_INET;
+
+ if (strchr (string, ':'))
+ family = AF_INET6;
+ }
+
+ if (family == AF_INET)
+ maxbitlen = sizeof(struct in_addr) * 8;
+ else if (family == AF_INET6)
+ maxbitlen = sizeof(struct in6_addr) * 8;
+
+ const char *const cp = strchr(string, '/');
+ if (cp)
+ {
+ char save[MAXLINE];
+
+ bitlen = atoi(cp + 1);
+
+ /* *cp = '\0'; */
+ /* Copy the string to save. Avoid destroying the string */
+ assert(cp - string < MAXLINE);
+ memcpy(save, string, cp - string);
+
+ save[cp - string] = '\0';
+ string = save;
+
+ if (bitlen < 0 || bitlen > maxbitlen)
+ bitlen = maxbitlen;
+ }
+ else
+ bitlen = maxbitlen;
+
+ if (inet_pton(family, string, &sin) <= 0)
+ return NULL;
+ return New_Prefix(family, &sin, bitlen);
+}
+
+static prefix_t *
+Ref_Prefix(prefix_t *prefix)
+{
+ if (prefix == NULL)
+ return NULL;
+
+ if (prefix->ref_count == 0)
+ /* Make a copy in case of a static prefix */
+ return New_Prefix2(prefix->family, &prefix->add, prefix->bitlen, NULL);
+
+ prefix->ref_count++;
+
+/* fprintf(stderr, "[A %s, %d]\n", patricia_prefix_toa(prefix), prefix->ref_count); */
+ return prefix;
+}
+
+static void
+Deref_Prefix(prefix_t *prefix)
+{
+ if (prefix == NULL)
+ return;
+
+ /* For secure programming, raise an assert. No static prefix can call this */
+ assert(prefix->ref_count > 0);
+ if (--prefix->ref_count <= 0)
+ xfree(prefix);
+}
+/* } */
+
+/* #define PATRICIA_DEBUG 1 */
+
+/* these routines support continuous mask only */
+
+patricia_tree_t *
+patricia_new(unsigned int maxbits)
+{
+ patricia_tree_t *patricia = xcalloc(sizeof *patricia);
+ patricia->maxbits = maxbits;
+
+ assert(maxbits <= PATRICIA_MAXBITS); /* XXX */
+ return patricia;
+}
+
+/*
+ * if func is supplied, it will be called as func(node->data)
+ * before deleting the node
+ */
+void
+patricia_clear(patricia_tree_t *patricia, void (*func)(void *))
+{
+ assert(patricia);
+
+ if (patricia->head)
+ {
+ patricia_node_t *Xstack[PATRICIA_MAXBITS + 1];
+ patricia_node_t **Xsp = Xstack;
+ patricia_node_t *Xrn = patricia->head;
+
+ while (Xrn)
+ {
+ patricia_node_t *l = Xrn->l;
+ patricia_node_t *r = Xrn->r;
+
+ if (Xrn->prefix)
+ {
+ Deref_Prefix(Xrn->prefix);
+
+ if (Xrn->data && func)
+ func(Xrn->data);
+ }
+ else
+ {
+ assert(Xrn->data == NULL);
+ }
+
+ xfree(Xrn);
+ patricia->num_active_node--;
+
+ if (l)
+ {
+ if (r)
+ {
+ *Xsp++ = r;
+ }
+
+ Xrn = l;
+ }
+ else if (r)
+ {
+ Xrn = r;
+ }
+ else if (Xsp != Xstack)
+ {
+ Xrn = *(--Xsp);
+ }
+ else
+ {
+ Xrn = NULL;
+ }
+ }
+ }
+
+ assert(patricia->num_active_node == 0);
+ /* xfree (patricia); */
+}
+
+void
+patricia_destroy(patricia_tree_t *patricia, void (*func)(void *))
+{
+ patricia_clear(patricia, func);
+ xfree(patricia);
+}
+
+/*
+ * if func is supplied, it will be called as func(node->prefix, node->data)
+ */
+void
+patricia_process(patricia_tree_t *patricia, void (*func)(prefix_t *, void *))
+{
+ patricia_node_t *node;
+
+ assert(func);
+
+ PATRICIA_WALK(patricia->head, node) {
+ func(node->prefix, node->data);
+ } PATRICIA_WALK_END;
+}
+
+patricia_node_t *
+patricia_search_exact(patricia_tree_t *patricia, prefix_t *prefix)
+{
+ patricia_node_t *node;
+ unsigned char *addr;
+ unsigned int bitlen;
+
+ assert(patricia);
+ assert(prefix);
+ assert(prefix->bitlen <= patricia->maxbits);
+
+ if (patricia->head == NULL)
+ return NULL;
+
+ node = patricia->head;
+ addr = prefix_touchar(prefix);
+ bitlen = prefix->bitlen;
+
+ while (node->bit < bitlen)
+ {
+ if (BIT_TEST(addr[node->bit >> 3], 0x80 >> (node->bit & 0x07)))
+ {
+#ifdef PATRICIA_DEBUG
+ if (node->prefix)
+ fprintf(stderr, "patricia_search_exact: take right %s/%d\n",
+ patricia_prefix_toa(node->prefix), node->prefix->bitlen);
+ else
+ fprintf(stderr, "patricia_search_exact: take right at %u\n", node->bit);
+#endif /* PATRICIA_DEBUG */
+ node = node->r;
+ }
+ else
+ {
+#ifdef PATRICIA_DEBUG
+ if (node->prefix)
+ fprintf(stderr, "patricia_search_exact: take left %s/%d\n",
+ patricia_prefix_toa(node->prefix), node->prefix->bitlen);
+ else
+ fprintf(stderr, "patricia_search_exact: take left at %u\n", node->bit);
+#endif /* PATRICIA_DEBUG */
+ node = node->l;
+ }
+
+ if (node == NULL)
+ return NULL;
+ }
+
+#ifdef PATRICIA_DEBUG
+ if (node->prefix)
+ fprintf(stderr, "patricia_search_exact: stop at %s/%d\n",
+ patricia_prefix_toa(node->prefix), node->prefix->bitlen);
+ else
+ fprintf(stderr, "patricia_search_exact: stop at %u\n", node->bit);
+#endif /* PATRICIA_DEBUG */
+
+ if (node->bit > bitlen || node->prefix == NULL)
+ return NULL;
+
+ assert(node->bit == bitlen);
+ assert(node->bit == node->prefix->bitlen);
+
+ if (comp_with_mask(prefix_tochar(node->prefix), prefix_tochar(prefix), bitlen))
+ {
+#ifdef PATRICIA_DEBUG
+ fprintf(stderr, "patricia_search_exact: found %s/%d\n",
+ patricia_prefix_toa(node->prefix), node->prefix->bitlen);
+#endif /* PATRICIA_DEBUG */
+ return node;
+ }
+
+ return NULL;
+}
+
+/* if inclusive != 0, "best" may be the given prefix itself */
+patricia_node_t *
+patricia_search_best2(patricia_tree_t *patricia, prefix_t *prefix, int inclusive)
+{
+ patricia_node_t *node;
+ patricia_node_t *stack[PATRICIA_MAXBITS + 1];
+ unsigned char *addr;
+ unsigned int bitlen;
+ int cnt = 0;
+
+ assert(patricia);
+ assert(prefix);
+ assert(prefix->bitlen <= patricia->maxbits);
+
+ if (patricia->head == NULL)
+ return NULL;
+
+ node = patricia->head;
+ addr = prefix_touchar(prefix);
+ bitlen = prefix->bitlen;
+
+ while (node->bit < bitlen)
+ {
+ if (node->prefix)
+ {
+#ifdef PATRICIA_DEBUG
+ fprintf(stderr, "patricia_search_best: push %s/%d\n",
+ patricia_prefix_toa(node->prefix), node->prefix->bitlen);
+#endif /* PATRICIA_DEBUG */
+ stack[cnt++] = node;
+ }
+
+ if (BIT_TEST(addr[node->bit >> 3], 0x80 >> (node->bit & 0x07)))
+ {
+#ifdef PATRICIA_DEBUG
+ if (node->prefix)
+ fprintf(stderr, "patricia_search_best: take right %s/%d\n",
+ patricia_prefix_toa(node->prefix), node->prefix->bitlen);
+ else
+ fprintf(stderr, "patricia_search_best: take right at %u\n", node->bit);
+#endif /* PATRICIA_DEBUG */
+ node = node->r;
+ }
+ else
+ {
+#ifdef PATRICIA_DEBUG
+ if (node->prefix)
+ fprintf(stderr, "patricia_search_best: take left %s/%d\n",
+ patricia_prefix_toa(node->prefix), node->prefix->bitlen);
+ else
+ fprintf(stderr, "patricia_search_best: take left at %u\n", node->bit);
+#endif /* PATRICIA_DEBUG */
+ node = node->l;
+ }
+
+ if (node == NULL)
+ break;
+ }
+
+ if (inclusive && node && node->prefix)
+ stack[cnt++] = node;
+
+#ifdef PATRICIA_DEBUG
+ if (node == NULL)
+ fprintf(stderr, "patricia_search_best: stop at null\n");
+ else if (node->prefix)
+ fprintf(stderr, "patricia_search_best: stop at %s/%d\n",
+ patricia_prefix_toa(node->prefix), node->prefix->bitlen);
+ else
+ fprintf(stderr, "patricia_search_best: stop at %u\n", node->bit);
+#endif /* PATRICIA_DEBUG */
+
+ if (cnt <= 0)
+ return NULL;
+
+ while (--cnt >= 0)
+ {
+ node = stack[cnt];
+#ifdef PATRICIA_DEBUG
+ fprintf(stderr, "patricia_search_best: pop %s/%d\n",
+ patricia_prefix_toa(node->prefix), node->prefix->bitlen);
+#endif /* PATRICIA_DEBUG */
+
+ if (comp_with_mask(prefix_tochar(node->prefix),
+ prefix_tochar(prefix), node->prefix->bitlen) && node->prefix->bitlen <= bitlen)
+ {
+#ifdef PATRICIA_DEBUG
+ fprintf(stderr, "patricia_search_best: found %s/%d\n",
+ patricia_prefix_toa(node->prefix), node->prefix->bitlen);
+#endif /* PATRICIA_DEBUG */
+ return node;
+ }
+ }
+
+ return NULL;
+}
+
+patricia_node_t *
+patricia_search_best(patricia_tree_t *patricia, prefix_t *prefix)
+{
+ return patricia_search_best2(patricia, prefix, 1);
+}
+
+patricia_node_t *
+patricia_lookup(patricia_tree_t *patricia, prefix_t *prefix)
+{
+ patricia_node_t *node, *new_node, *parent, *glue;
+ unsigned char *addr, *test_addr;
+ unsigned int bitlen, check_bit, differ_bit;
+ int j, r;
+
+ assert(patricia);
+ assert(prefix);
+ assert(prefix->bitlen <= patricia->maxbits);
+
+ if (patricia->head == NULL)
+ {
+ node = xcalloc(sizeof *node);
+ node->bit = prefix->bitlen;
+ node->prefix = Ref_Prefix (prefix);
+ patricia->head = node;
+#ifdef PATRICIA_DEBUG
+ fprintf(stderr, "patricia_lookup: new_node #0 %s/%d (head)\n",
+ patricia_prefix_toa(prefix), prefix->bitlen);
+#endif /* PATRICIA_DEBUG */
+ patricia->num_active_node++;
+ return node;
+ }
+
+ addr = prefix_touchar(prefix);
+ bitlen = prefix->bitlen;
+ node = patricia->head;
+
+ while (node->bit < bitlen || node->prefix == NULL)
+ {
+ if (node->bit < patricia->maxbits && BIT_TEST(addr[node->bit >> 3], 0x80 >> (node->bit & 0x07)))
+ {
+ if (node->r == NULL)
+ break;
+#ifdef PATRICIA_DEBUG
+ if (node->prefix)
+ fprintf(stderr, "patricia_lookup: take right %s/%d\n",
+ patricia_prefix_toa(node->prefix), node->prefix->bitlen);
+ else
+ fprintf(stderr, "patricia_lookup: take right at %u\n", node->bit);
+#endif /* PATRICIA_DEBUG */
+
+ node = node->r;
+ }
+ else
+ {
+ if (node->l == NULL)
+ break;
+#ifdef PATRICIA_DEBUG
+ if (node->prefix)
+ fprintf(stderr, "patricia_lookup: take left %s/%d\n",
+ patricia_prefix_toa(node->prefix), node->prefix->bitlen);
+ else
+ fprintf(stderr, "patricia_lookup: take left at %u\n", node->bit);
+#endif /* PATRICIA_DEBUG */
+
+ node = node->l;
+ }
+
+ assert(node);
+ }
+
+ assert(node->prefix);
+#ifdef PATRICIA_DEBUG
+ fprintf(stderr, "patricia_lookup: stop at %s/%d\n",
+ patricia_prefix_toa(node->prefix), node->prefix->bitlen);
+#endif /* PATRICIA_DEBUG */
+
+ test_addr = prefix_touchar(node->prefix);
+
+ /* Find the first bit different */
+ check_bit = (node->bit < bitlen) ? node->bit : bitlen;
+ differ_bit = 0;
+
+ for (unsigned int i = 0; i * 8 < check_bit; i++)
+ {
+ if ((r = (addr[i] ^ test_addr[i])) == 0)
+ {
+ differ_bit = (i + 1) * 8;
+ continue;
+ }
+
+ /* I know the better way, but for now */
+ for (j = 0; j < 8; j++)
+ if (BIT_TEST(r, (0x80 >> j)))
+ break;
+
+ /* Must be found */
+ assert(j < 8);
+ differ_bit = i * 8 + j;
+ break;
+ }
+
+ if (differ_bit > check_bit)
+ differ_bit = check_bit;
+#ifdef PATRICIA_DEBUG
+ fprintf(stderr, "patricia_lookup: differ_bit %d\n", differ_bit);
+#endif /* PATRICIA_DEBUG */
+
+ parent = node->parent;
+
+ while (parent && parent->bit >= differ_bit)
+ {
+ node = parent;
+ parent = node->parent;
+
+#ifdef PATRICIA_DEBUG
+ if (node->prefix)
+ fprintf(stderr, "patricia_lookup: up to %s/%d\n",
+ patricia_prefix_toa(node->prefix), node->prefix->bitlen);
+ else
+ fprintf(stderr, "patricia_lookup: up to %u\n", node->bit);
+#endif /* PATRICIA_DEBUG */
+ }
+
+ if (differ_bit == bitlen && node->bit == bitlen)
+ {
+ if (node->prefix)
+ {
+#ifdef PATRICIA_DEBUG
+ fprintf(stderr, "patricia_lookup: found %s/%d\n",
+ patricia_prefix_toa(node->prefix), node->prefix->bitlen);
+#endif /* PATRICIA_DEBUG */
+
+ return node;
+ }
+
+ node->prefix = Ref_Prefix(prefix);
+#ifdef PATRICIA_DEBUG
+ fprintf(stderr, "patricia_lookup: new node #1 %s/%d (glue mod)\n",
+ patricia_prefix_toa(prefix), prefix->bitlen);
+#endif /* PATRICIA_DEBUG */
+
+ assert(node->data == NULL);
+ return node;
+ }
+
+ new_node = xcalloc(sizeof *new_node);
+ new_node->bit = prefix->bitlen;
+ new_node->prefix = Ref_Prefix(prefix);
+ patricia->num_active_node++;
+
+ if (node->bit == differ_bit)
+ {
+ new_node->parent = node;
+
+ if (node->bit < patricia->maxbits && BIT_TEST(addr[node->bit >> 3], 0x80 >> (node->bit & 0x07)))
+ {
+ assert(node->r == NULL);
+ node->r = new_node;
+ }
+ else
+ {
+ assert(node->l == NULL);
+ node->l = new_node;
+ }
+#ifdef PATRICIA_DEBUG
+ fprintf(stderr, "patricia_lookup: new_node #2 %s/%d (child)\n",
+ patricia_prefix_toa(prefix), prefix->bitlen);
+#endif /* PATRICIA_DEBUG */
+ return new_node;
+ }
+
+ if (bitlen == differ_bit)
+ {
+ if (bitlen < patricia->maxbits && BIT_TEST(test_addr[bitlen >> 3], 0x80 >> (bitlen & 0x07)))
+ {
+ new_node->r = node;
+ }
+ else
+ {
+ new_node->l = node;
+ }
+
+ new_node->parent = node->parent;
+
+ if (node->parent == NULL)
+ {
+ assert(patricia->head == node);
+ patricia->head = new_node;
+ }
+ else if (node->parent->r == node)
+ {
+ node->parent->r = new_node;
+ }
+ else
+ {
+ node->parent->l = new_node;
+ }
+
+ node->parent = new_node;
+#ifdef PATRICIA_DEBUG
+ fprintf(stderr, "patricia_lookup: new_node #3 %s/%d (parent)\n",
+ patricia_prefix_toa(prefix), prefix->bitlen);
+#endif /* PATRICIA_DEBUG */
+ }
+ else
+ {
+ glue = xcalloc(sizeof *glue);
+ glue->bit = differ_bit;
+ glue->parent = node->parent;
+ patricia->num_active_node++;
+
+ if (differ_bit < patricia->maxbits && BIT_TEST(addr[differ_bit >> 3], 0x80 >> (differ_bit & 0x07)))
+ {
+ glue->r = new_node;
+ glue->l = node;
+ }
+ else
+ {
+ glue->r = node;
+ glue->l = new_node;
+ }
+
+ new_node->parent = glue;
+
+ if (node->parent == NULL)
+ {
+ assert(patricia->head == node);
+ patricia->head = glue;
+ }
+ else if (node->parent->r == node)
+ {
+ node->parent->r = glue;
+ }
+ else
+ {
+ node->parent->l = glue;
+ }
+
+ node->parent = glue;
+#ifdef PATRICIA_DEBUG
+ fprintf(stderr, "patricia_lookup: new_node #4 %s/%d (glue+node)\n",
+ patricia_prefix_toa(prefix), prefix->bitlen);
+#endif /* PATRICIA_DEBUG */
+ }
+
+ return new_node;
+}
+
+void
+patricia_remove(patricia_tree_t *patricia, patricia_node_t *node)
+{
+ patricia_node_t *parent, *child;
+
+ assert(patricia);
+ assert(node);
+
+ if (node->r && node->l)
+ {
+#ifdef PATRICIA_DEBUG
+ fprintf(stderr, "patricia_remove: #0 %s/%d (r & l)\n",
+ patricia_prefix_toa(node->prefix), node->prefix->bitlen);
+#endif /* PATRICIA_DEBUG */
+
+ /*
+ * This might be a placeholder node -- have to check and make sure
+ * there is a prefix associated with it !
+ */
+ if (node->prefix)
+ Deref_Prefix(node->prefix);
+
+ node->prefix = NULL;
+ /* Also I needed to clear data pointer -- masaki */
+ node->data = NULL;
+ return;
+ }
+
+ if (node->r == NULL && node->l == NULL)
+ {
+#ifdef PATRICIA_DEBUG
+ fprintf(stderr, "patricia_remove: #1 %s/%d (!r & !l)\n",
+ patricia_prefix_toa(node->prefix), node->prefix->bitlen);
+#endif /* PATRICIA_DEBUG */
+
+ parent = node->parent;
+ Deref_Prefix(node->prefix);
+ xfree(node);
+ patricia->num_active_node--;
+
+ if (parent == NULL)
+ {
+ assert(patricia->head == node);
+ patricia->head = NULL;
+ return;
+ }
+
+ if (parent->r == node)
+ {
+ parent->r = NULL;
+ child = parent->l;
+ }
+ else
+ {
+ assert(parent->l == node);
+
+ parent->l = NULL;
+ child = parent->r;
+ }
+
+ if (parent->prefix)
+ return;
+
+ /* We need to remove parent too */
+ if (parent->parent == NULL)
+ {
+ assert(patricia->head == parent);
+ patricia->head = child;
+ }
+ else if (parent->parent->r == parent)
+ {
+ parent->parent->r = child;
+ }
+ else
+ {
+ assert(parent->parent->l == parent);
+ parent->parent->l = child;
+ }
+
+ child->parent = parent->parent;
+ xfree(parent);
+ patricia->num_active_node--;
+ return;
+ }
+
+#ifdef PATRICIA_DEBUG
+ fprintf(stderr, "patricia_remove: #2 %s/%d (r ^ l)\n",
+ patricia_prefix_toa(node->prefix), node->prefix->bitlen);
+#endif /* PATRICIA_DEBUG */
+
+ if (node->r)
+ {
+ child = node->r;
+ }
+ else
+ {
+ assert(node->l);
+ child = node->l;
+ }
+
+ parent = node->parent;
+ child->parent = parent;
+
+ Deref_Prefix(node->prefix);
+ xfree(node);
+ patricia->num_active_node--;
+
+ if (parent == NULL)
+ {
+ assert(patricia->head == node);
+ patricia->head = child;
+ return;
+ }
+
+ if (parent->r == node)
+ {
+ parent->r = child;
+ }
+ else
+ {
+ assert(parent->l == node);
+ parent->l = child;
+ }
+}
+
+/* { from demo.c */
+patricia_node_t *
+patricia_make_and_lookup(patricia_tree_t *tree, const char *string)
+{
+ prefix_t *prefix = ascii2prefix(0, string);
+
+ if (prefix)
+ {
+ patricia_node_t *node = patricia_lookup(tree, prefix);
+ Deref_Prefix(prefix);
+ return node;
+ }
+
+ return NULL;
+}
+
+void
+patricia_lookup_then_remove(patricia_tree_t *tree, const char *string)
+{
+ patricia_node_t *node = patricia_try_search_exact(tree, string);
+ if (node)
+ patricia_remove(tree, node);
+}
+
+patricia_node_t *
+patricia_try_search_exact(patricia_tree_t *tree, const char *string)
+{
+ prefix_t *prefix = ascii2prefix(0, string);
+
+ if (prefix)
+ {
+ patricia_node_t *node = patricia_search_exact(tree, prefix);
+ Deref_Prefix(prefix);
+ return node;
+ }
+
+ return NULL;
+}
+
+patricia_node_t *
+patricia_try_search_best(patricia_tree_t *tree, const char *string)
+{
+ prefix_t *prefix = ascii2prefix(0, string);
+
+ if (prefix)
+ {
+ patricia_node_t *node = patricia_search_best(tree, prefix);
+ Deref_Prefix(prefix);
+ return node;
+ }
+
+ return NULL;
+}
+
+patricia_node_t *
+patricia_try_search_exact_addr(patricia_tree_t *tree, struct sockaddr *addr, int bitlen)
+{
+ int family;
+ void *dest;
+
+ if (addr->sa_family == AF_INET6)
+ {
+ if (bitlen == 0 || bitlen > 128)
+ bitlen = 128;
+ family = AF_INET6;
+ dest = &((struct sockaddr_in6 *)addr)->sin6_addr;
+ }
+ else
+ {
+ if (bitlen == 0 || bitlen > 32)
+ bitlen = 32;
+ family = AF_INET;
+ dest = &((struct sockaddr_in *)addr)->sin_addr;
+ }
+
+ prefix_t *prefix = New_Prefix(family, dest, bitlen);
+ if (prefix)
+ {
+ patricia_node_t *node = patricia_search_exact(tree, prefix);
+ Deref_Prefix(prefix);
+ return node;
+ }
+
+ return NULL;
+}
+
+patricia_node_t *
+patricia_try_search_best_addr(patricia_tree_t *tree, struct sockaddr *addr, int bitlen)
+{
+ int family;
+ void *dest;
+
+ if (addr->sa_family == AF_INET6)
+ {
+ if (bitlen == 0 || bitlen > 128)
+ bitlen = 128;
+ family = AF_INET6;
+ dest = &((struct sockaddr_in6 *)addr)->sin6_addr;
+ }
+ else
+ {
+ if (bitlen == 0 || bitlen > 32)
+ bitlen = 32;
+ family = AF_INET;
+ dest = &((struct sockaddr_in *)addr)->sin_addr;
+ }
+
+ prefix_t *prefix = New_Prefix(family, dest, bitlen);
+ if (prefix)
+ {
+ patricia_node_t *node = patricia_search_best(tree, prefix);
+ Deref_Prefix(prefix);
+ return node;
+ }
+
+ return NULL;
+}
+/* } */
diff --git a/src/patricia.h b/src/patricia.h
new file mode 100644
index 0000000..2e6fb45
--- /dev/null
+++ b/src/patricia.h
@@ -0,0 +1,148 @@
+/*
+ * $Id: patricia.h 7852 2016-11-06 18:20:25Z michael $
+ * Dave Plonka <plonka@doit.wisc.edu>
+ *
+ * This file had been called "radix.h" in the MRT sources.
+ *
+ * I renamed it to "patricia.h" since it's not an implementation of a general
+ * radix trie. Also, pulled in various requirements from "mrt.h" and added
+ * some other things it could be used as a standalone API.
+ *
+ * Copyright (c) 1999-2013
+ *
+ * The Regents of the University of Michigan ("The Regents") and Merit
+ * Network, Inc.
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _PATRICIA_H
+#define _PATRICIA_H
+
+/* { from defs.h */
+#define prefix_touchar(prefix) ((unsigned char *)&(prefix)->add.sin)
+#define MAXLINE 1024
+#define BIT_TEST(f, b) ((f) & (b))
+/* } */
+
+#include <netinet/in.h> /* for struct in_addr */
+#include <sys/socket.h> /* for AF_INET */
+
+/* { from mrt.h */
+typedef struct _prefix_t
+{
+ unsigned short family; /* AF_INET | AF_INET6 */
+ unsigned short bitlen; /* same as mask? */
+ int ref_count; /* reference count */
+
+ union
+ {
+ struct in_addr sin;
+ struct in6_addr sin6;
+ } add;
+} prefix_t;
+/* } */
+
+typedef struct _patricia_node_t
+{
+ unsigned int bit; /* flag if this node used */
+ prefix_t *prefix; /* who we are in patricia tree */
+ struct _patricia_node_t *l, *r; /* left and right children */
+ struct _patricia_node_t *parent; /* may be used */
+ void *data; /* pointer to data */
+ void *user1; /* pointer to usr data (ex. route flap info) */
+} patricia_node_t;
+
+typedef struct _patricia_tree_t
+{
+ patricia_node_t *head;
+ unsigned int maxbits; /* for IP, 32 bit addresses */
+ int num_active_node; /* for debug purpose */
+} patricia_tree_t;
+
+
+extern patricia_node_t *patricia_search_exact(patricia_tree_t *, prefix_t *);
+extern patricia_node_t *patricia_search_best(patricia_tree_t *, prefix_t *);
+extern patricia_node_t *patricia_search_best2(patricia_tree_t *, prefix_t *, int);
+extern patricia_node_t *patricia_lookup(patricia_tree_t *, prefix_t *);
+extern void patricia_remove(patricia_tree_t *, patricia_node_t *);
+extern patricia_tree_t *patricia_new(unsigned int);
+extern void patricia_clear(patricia_tree_t *, void (*)(void *));
+extern void patricia_destroy(patricia_tree_t *, void (*)(void *));
+extern void patricia_process(patricia_tree_t *, void (*)(prefix_t *, void *));
+extern const char *patricia_prefix_toa(const prefix_t *, int);
+extern void patricia_lookup_then_remove(patricia_tree_t *, const char *);
+extern patricia_node_t *patricia_try_search_exact(patricia_tree_t *, const char *);
+extern patricia_node_t *patricia_try_search_best(patricia_tree_t *, const char *);
+extern patricia_node_t *patricia_try_search_exact_addr(patricia_tree_t *, struct sockaddr *, int);
+extern patricia_node_t *patricia_try_search_best_addr(patricia_tree_t *, struct sockaddr *, int);
+
+/* { from demo.c */
+extern patricia_node_t *patricia_make_and_lookup(patricia_tree_t *, const char *);
+/* } */
+
+#define PATRICIA_MAXBITS (sizeof(struct in6_addr) * 8)
+#define PATRICIA_NBIT(x) (0x80 >> ((x) & 0x7f))
+#define PATRICIA_NBYTE(x) ((x) >> 3)
+
+#define PATRICIA_DATA_GET(node, type) (type *)((node)->data)
+#define PATRICIA_DATA_SET(node, value) ((node)->data = (void *)(value))
+
+#define PATRICIA_WALK(Xhead, Xnode) \
+ do { \
+ patricia_node_t *Xstack[PATRICIA_MAXBITS + 1]; \
+ patricia_node_t **Xsp = Xstack; \
+ patricia_node_t *Xrn = (Xhead); \
+ while ((Xnode = Xrn)) { \
+ if (Xnode->prefix)
+
+#define PATRICIA_WALK_ALL(Xhead, Xnode) \
+ do { \
+ patricia_node_t *Xstack[PATRICIA_MAXBITS + 1]; \
+ patricia_node_t **Xsp = Xstack; \
+ patricia_node_t *Xrn = (Xhead); \
+ while ((Xnode = Xrn)) { \
+ if (1)
+
+#define PATRICIA_WALK_BREAK { \
+ if (Xsp != Xstack) { \
+ Xrn = *(--Xsp); \
+ } else { \
+ Xrn = (patricia_node_t *)0; \
+ } \
+ continue; }
+
+#define PATRICIA_WALK_END \
+ if (Xrn->l) { \
+ if (Xrn->r) { \
+ *Xsp++ = Xrn->r; \
+ } \
+ Xrn = Xrn->l; \
+ } else if (Xrn->r) { \
+ Xrn = Xrn->r; \
+ } else if (Xsp != Xstack) { \
+ Xrn = *(--Xsp); \
+ } else { \
+ Xrn = (patricia_node_t *)0; \
+ } \
+ } \
+} while (0)
+
+#endif
diff --git a/src/scan.c b/src/scan.c
new file mode 100644
index 0000000..2008e8c
--- /dev/null
+++ b/src/scan.c
@@ -0,0 +1,969 @@
+/*
+ * Copyright (c) 2002 Erik Fears
+ * Copyright (c) 2014-2018 ircd-hybrid 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 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
+ * USA
+ */
+
+#include "setup.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <sys/socket.h>
+#include <netdb.h>
+#include <netinet/in.h>
+
+#include "compat.h"
+#include "config.h"
+#include "irc.h"
+#include "log.h"
+#include "stats.h"
+#include "dnsbl.h"
+#include "options.h"
+#include "negcache.h"
+#include "main.h"
+#include "memory.h"
+#include "match.h"
+#include "misc.h"
+#include "scan.h"
+
+/* libopm includes */
+#include "libopm/src/opm.h"
+#include "libopm/src/opm_common.h"
+#include "libopm/src/opm_error.h"
+#include "libopm/src/opm_types.h"
+
+
+/* GLOBAL LIST */
+static list_t SCANNERS; /* List of OPM_T */
+
+/* Function declarations */
+static struct scan_struct *scan_create(const char *[], const char *);
+static void scan_free(struct scan_struct *);
+static void scan_irckline(const struct scan_struct *, const char *, const char *);
+static void scan_negative(const struct scan_struct *);
+static void scan_log(OPM_REMOTE_T *);
+
+/** Callbacks for LIBOPM */
+static void scan_open_proxy(OPM_T *, OPM_REMOTE_T *, int, void *);
+static void scan_negotiation_failed(OPM_T *, OPM_REMOTE_T *, int, void *);
+static void scan_timeout(OPM_T *, OPM_REMOTE_T *, int, void *);
+static void scan_end(OPM_T *, OPM_REMOTE_T *, int, void *);
+static void scan_handle_error(OPM_T *, OPM_REMOTE_T *, int, void *);
+
+extern FILE *scanlogfile;
+
+
+/* scan_cycle
+ *
+ * Perform scanner tasks.
+ */
+void
+scan_cycle(void)
+{
+ node_t *node;
+
+ /* Cycle through the blacklist first.. */
+ dnsbl_cycle();
+
+ /* Cycle each scanner object */
+ LIST_FOREACH(node, SCANNERS.head)
+ {
+ struct scanner_struct *scs = node->data;
+ opm_cycle(scs->scanner);
+ }
+}
+
+/* scan_timer
+ *
+ * Perform actions that are to be performed every ~1 second.
+ *
+ * Parameters: NONE
+ * Return: NONE
+ *
+ */
+void
+scan_timer(void)
+{
+ static time_t nc_counter;
+
+ if (OptionsItem.negcache)
+ {
+ if (nc_counter++ >= OptionsItem.negcache_rebuild)
+ {
+ /*
+ * Time to rebuild the negative cache.
+ */
+ if (OPT_DEBUG)
+ log_printf("SCAN -> Rebuilding negative cache");
+
+ negcache_rebuild();
+ nc_counter = 0;
+ }
+ }
+}
+
+/* scan_gettype(int protocol)
+ *
+ * Return human readable name of OPM PROTOCOL given OPM_TYPE_PROTOCOL
+ *
+ * Parameters:
+ * protocol: Protocol to return (from libopm/src/opm_types.h)
+ *
+ * Return:
+ * Pointer to static string containing human readable form of protocol
+ * name
+ *
+ */
+const char *
+scan_gettype(int protocol)
+{
+ static const char *const undef = "undefined";
+ static const struct protocol_assoc protocols[] =
+ {
+ { .type = OPM_TYPE_HTTP, .name = "HTTP" },
+ { .type = OPM_TYPE_HTTPPOST, .name = "HTTPPOST" },
+ { .type = OPM_TYPE_SOCKS4, .name = "SOCKS4" },
+ { .type = OPM_TYPE_SOCKS5, .name = "SOCKS5" },
+ { .type = OPM_TYPE_WINGATE, .name = "WINGATE" },
+ { .type = OPM_TYPE_ROUTER, .name = "ROUTER" },
+ { .type = OPM_TYPE_HTTPS, .name = "HTTPS" },
+ { .type = OPM_TYPE_HTTPSPOST, .name = "HTTPSPOST" },
+ { .type = OPM_TYPE_DREAMBOX, .name = "DREAMBOX" },
+ { .type = OPM_TYPE_SSH, .name = "SSH" },
+ { .type = 0 }
+ };
+
+ for (const struct protocol_assoc *tab = protocols; tab->type; ++tab)
+ if (protocol == tab->type)
+ return tab->name;
+
+ return undef;
+}
+
+/* scan_checkexempt
+ *
+ * Check mask against exempt list.
+ *
+ * Parameters:
+ * mask: Mask to check
+ *
+ * Return:
+ * 1 if mask is in list
+ * 0 if mask is not in list
+ */
+static int
+scan_checkexempt(const char *mask, const char *ipmask)
+{
+ node_t *node;
+
+ LIST_FOREACH(node, ExemptItem.masks.head)
+ {
+ const char *exempt_mask = node->data;
+
+ if (match(exempt_mask, mask) == 0 || match(exempt_mask, ipmask) == 0)
+ return 1;
+ }
+
+ return 0;
+}
+
+/* scan_init
+
+ Initialize scanner and masks list based on configuration.
+
+ Parameters:
+ None
+
+ Return:
+ None
+*/
+void
+scan_init(void)
+{
+ node_t *p, *p2, *p3, *p4;
+
+ /* Setup each individual scanner */
+ LIST_FOREACH(p, ScannerItemList.head)
+ {
+ struct ScannerConf *sc = p->data;
+
+ if (OPT_DEBUG)
+ log_printf("SCAN -> Setting up scanner [%s]", sc->name);
+
+ /* Build the scanner */
+ struct scanner_struct *scs = xcalloc(sizeof(*scs));
+ scs->scanner = opm_create();
+ scs->name = xstrdup(sc->name);
+
+ /* Setup configuration */
+ opm_config(scs->scanner, OPM_CONFIG_FD_LIMIT, &sc->fd);
+ opm_config(scs->scanner, OPM_CONFIG_SCAN_IP, sc->target_ip);
+ opm_config(scs->scanner, OPM_CONFIG_SCAN_PORT, &sc->target_port);
+ opm_config(scs->scanner, OPM_CONFIG_TIMEOUT, &sc->timeout);
+ opm_config(scs->scanner, OPM_CONFIG_MAX_READ, &sc->max_read);
+ opm_config(scs->scanner, OPM_CONFIG_BIND_IP, sc->vhost);
+
+ /* add target strings */
+ LIST_FOREACH(p2, sc->target_string.head)
+ opm_config(scs->scanner, OPM_CONFIG_TARGET_STRING, p2->data);
+
+ /* Setup callbacks */
+ opm_callback(scs->scanner, OPM_CALLBACK_OPENPROXY, &scan_open_proxy, scs);
+ opm_callback(scs->scanner, OPM_CALLBACK_NEGFAIL, &scan_negotiation_failed, scs);
+ opm_callback(scs->scanner, OPM_CALLBACK_TIMEOUT, &scan_timeout, scs);
+ opm_callback(scs->scanner, OPM_CALLBACK_END, &scan_end, scs);
+ opm_callback(scs->scanner, OPM_CALLBACK_ERROR, &scan_handle_error, scs);
+
+ /* Setup the protocols */
+ LIST_FOREACH(p2, sc->protocols.head)
+ {
+ struct ProtocolConf *pc = p2->data;
+
+ if (OPT_DEBUG >= 2)
+ log_printf("SCAN -> Adding protocol %s:%d to scanner [%s]",
+ scan_gettype(pc->type), pc->port, scs->name);
+
+ if (opm_addtype(scs->scanner, pc->type, pc->port) == OPM_ERR_BADPROTOCOL)
+ log_printf("SCAN -> Error bad protocol %s:%d in scanner [%s]",
+ scan_gettype(pc->type), pc->port, scs->name);
+ }
+
+ list_add(scs, node_create(), &SCANNERS);
+ }
+
+ /* Give scanners a list of masks they scan */
+ LIST_FOREACH(p, SCANNERS.head)
+ {
+ struct scanner_struct *scs = p->data;
+
+ LIST_FOREACH(p2, UserItemList.head)
+ {
+ struct UserConf *uc = p2->data;
+
+ LIST_FOREACH(p3, uc->scanners.head)
+ {
+ const char *scannername = p3->data;
+
+ /* Add all these masks to scanner */
+ if (strcasecmp(scannername, scs->name) == 0)
+ {
+ LIST_FOREACH(p4, uc->masks.head)
+ {
+ const char *mask = p4->data;
+
+ if (OPT_DEBUG)
+ log_printf("SCAN -> Linking the mask [%s] to scanner [%s]", mask, scannername);
+
+ list_add(xstrdup(mask), node_create(), &scs->masks);
+ }
+
+ break;
+ }
+ }
+ }
+ }
+
+ /* Initialise negative cache */
+ if (OptionsItem.negcache)
+ {
+ if (OPT_DEBUG >= 2)
+ log_printf("SCAN -> Initializing negative cache");
+
+ negcache_init();
+ }
+}
+
+/* scan_connect
+ *
+ * scan_connect is called when m_notice (irc.c) matches a connection
+ * notice and parses the connecting user out of it.
+ *
+ * Parameters:
+ * user: Parsed items from the connection notice:
+ * user[0] = connecting users nickname
+ * user[1] = connecting users username
+ * user[2] = connecting users hostname
+ * user[3] = connecting users IP
+ * msg = Original connect notice
+ * Return: NONE
+ *
+ */
+void
+scan_connect(const char *user[], const char *msg)
+{
+ node_t *p, *p2;
+ int ret;
+
+ /*
+ * Have to use MSGLENMAX here because it is unknown what the max size of
+ * username/hostname can be. Some ircds use really mad values for
+ * these.
+ */
+ char hostmask[MSGLENMAX];
+ char addrmask[MSGLENMAX];
+
+ /* Check negcache before anything */
+ if (negcache_check(user[3]))
+ {
+ if (OPT_DEBUG)
+ log_printf("SCAN -> %s!%s@%s [%s] is negatively cached. Skipping all tests.",
+ user[0], user[1], user[2], user[3]);
+ return;
+ }
+
+ /* Generate user mask */
+ snprintf(hostmask, sizeof(hostmask), "%s!%s@%s", user[0], user[1], user[2]);
+ snprintf(addrmask, sizeof(addrmask), "%s!%s@%s", user[0], user[1], user[3]);
+
+ /* Check exempt list now that we have a mask */
+ if (scan_checkexempt(hostmask, addrmask))
+ {
+ if (OPT_DEBUG)
+ log_printf("SCAN -> %s [%s] is exempt from scanning", hostmask, user[3]);
+
+ return;
+ }
+
+ /* Create scan_struct */
+ struct scan_struct *ss = scan_create(user, msg);
+
+ /* Store ss in the remote struct, so that in callbacks we have ss */
+ ss->remote->data = ss;
+
+ /* Start checking our DNSBLs */
+ if (LIST_SIZE(&OpmItem.blacklists))
+ dnsbl_add(ss);
+
+ /* Add ss->remote to all matching scanners */
+ LIST_FOREACH(p, SCANNERS.head)
+ {
+ struct scanner_struct *scs = p->data;
+
+ LIST_FOREACH(p2, scs->masks.head)
+ {
+ const char *scsmask = p2->data;
+
+ if (match(scsmask, hostmask) == 0)
+ {
+ if (OPT_DEBUG)
+ log_printf("SCAN -> Passing %s to scanner [%s]", hostmask, scs->name);
+
+ if ((ret = opm_scan(scs->scanner, ss->remote)) != OPM_SUCCESS)
+ {
+ switch (ret)
+ {
+ case OPM_ERR_NOPROTOCOLS:
+ continue;
+ break;
+ case OPM_ERR_BADADDR:
+ if (!strchr(ss->ip, ':')) /* XXX: hack alert. remove when libopm can deal with IPv6 addresses */
+ log_printf("OPM -> Bad address %s [%s]", ss->ip, scs->name);
+ break;
+ default:
+ log_printf("OPM -> Unknown error %s [%s]", ss->ip, scs->name);
+ break;
+ }
+ }
+ else
+ ++ss->scans; /* Increase scan count only if OPM_SUCCESS */
+
+ break; /* Continue to next scanner */
+ }
+ }
+ }
+
+ /* All scanners returned !OPM_SUCCESS and there were no dnsbl checks */
+ if (ss->scans == 0)
+ scan_free(ss);
+}
+
+/* scan_create
+ *
+ * Allocate scan struct, including user information and REMOTE
+ * for LIBOPM.
+ *
+ * Parameters:
+ * user: Parsed items from the connection notice:
+ * user[0] = connecting users nickname
+ * user[1] = connecting users username
+ * user[2] = connecting users hostname
+ * user[3] = connecting users IP
+ * msg = Original connect notice (used as PROOF)
+ *
+ * Return: Pointer to new scan_struct
+ *
+ */
+static struct scan_struct *
+scan_create(const char *user[], const char *msg)
+{
+ struct scan_struct *ss = xcalloc(sizeof(*ss));
+
+ ss->irc_nick = xstrdup(user[0]);
+ ss->irc_username = xstrdup(user[1]);
+ ss->irc_hostname = xstrdup(user[2]);
+ ss->ip = xstrdup(user[3]);
+ ss->proof = xstrdup(msg);
+ ss->remote = opm_remote_create(ss->ip);
+
+ return ss;
+}
+
+/* scan_free
+ *
+ * Free a scan_struct. This should only be done if the scan struct has
+ * no scans left!
+ *
+ * Parameters:
+ * ss: scan_struct to free
+ *
+ * Return: NONE
+ */
+static void
+scan_free(struct scan_struct *ss)
+{
+ xfree(ss->irc_nick);
+ xfree(ss->irc_username);
+ xfree(ss->irc_hostname);
+ xfree(ss->ip);
+ xfree(ss->proof);
+
+ opm_remote_free(ss->remote);
+ xfree(ss);
+}
+
+/* scan_checkfinished
+ *
+ * Check if a scan is complete (ss->scans <= 0)
+ * and free it if need be.
+ */
+void
+scan_checkfinished(struct scan_struct *ss)
+{
+ if (ss->scans <= 0)
+ {
+ if (ss->manual_target)
+ irc_send("PRIVMSG %s :CHECK -> All tests on %s completed.",
+ ss->manual_target, ss->ip);
+ else
+ {
+ if (OPT_DEBUG)
+ /* If there was a manual_target, then irc_nick, etc is NULL. */
+ log_printf("SCAN -> All tests on %s!%s@%s [%s] complete.",
+ ss->irc_nick, ss->irc_username, ss->irc_hostname, ss->ip);
+
+ /* Scan was a negative */
+ if (ss->positive == 0)
+ scan_negative(ss);
+ }
+
+ scan_free(ss);
+ }
+}
+
+/* scan_positive
+ *
+ * Remote host (defined by ss) has been found positive by one or more
+ * tests.
+ *
+ * Parameters:
+ * ss: scan_struct containing information regarding positive host
+ * kline: command to send to IRC server to ban the user (see scan_irckline)
+ * type: string of the type of proxy found to be running on the host
+ *
+ * Return: NONE
+ *
+ */
+void
+scan_positive(struct scan_struct *ss, const char *kline, const char *type)
+{
+ node_t *node;
+
+ /* If already a positive, don't kline/close again */
+ if (ss->positive)
+ return;
+
+ /* Format KLINE and send to IRC server */
+ scan_irckline(ss, kline, type);
+
+ /* Speed up the cleanup procedure */
+ /* Close all scans prematurely */
+ LIST_FOREACH(node, SCANNERS.head)
+ {
+ OPM_T *scanner = ((struct scanner_struct *)node->data)->scanner;
+ opm_end(scanner, ss->remote);
+ }
+
+ /* Set it as a positive to avoid a scan_negative call later on */
+ ss->positive = 1;
+}
+
+/* scan_open_proxy CALLBACK
+ *
+ * Called by libopm when a proxy is verified open.
+ *
+ * Parameters:
+ * scanner: Scanner that found the open proxy.
+ * remote: Remote struct containing information regarding remote end
+ *
+ * Return: NONE
+ */
+static void
+scan_open_proxy(OPM_T *scanner, OPM_REMOTE_T *remote, int notused, void *data)
+{
+ struct scan_struct *ss = remote->data;
+ struct scanner_struct *scs = data;
+
+ /* Record that a scan happened */
+ scan_log(remote);
+
+ if (ss->manual_target)
+ {
+ irc_send("PRIVMSG %s :CHECK -> OPEN PROXY %s:%d (%s) [%s]",
+ ss->manual_target, remote->ip, remote->port,
+ scan_gettype(remote->protocol), scs->name);
+ log_printf("SCAN -> OPEN PROXY %s:%d (%s) [%s]", remote->ip,
+ remote->port, scan_gettype(remote->protocol), scs->name);
+ }
+ else
+ {
+ /* kline and close scan */
+ scan_positive(ss, IRCItem.kline, scan_gettype(remote->protocol));
+
+ /* Report to blacklist */
+ dnsbl_report(ss);
+
+ irc_send_channels("OPEN PROXY -> %s!%s@%s %s:%d (%s) [%s]",
+ ss->irc_nick, ss->irc_username, ss->irc_hostname, remote->ip,
+ remote->port, scan_gettype(remote->protocol), scs->name);
+ log_printf("SCAN -> OPEN PROXY %s!%s@%s %s:%d (%s) [%s]",
+ ss->irc_nick, ss->irc_username, ss->irc_hostname, remote->ip,
+ remote->port, scan_gettype(remote->protocol), scs->name);
+ }
+
+ /* Record the proxy for stats purposes */
+ stats_openproxy(remote->protocol);
+}
+
+/* scan_negotiation_failed CALLBACK
+ *
+ * Called by libopm when negotiation of a specific protocol failed.
+ *
+ * Parameters:
+ * scanner: Scanner where the negotiation failed.
+ * remote: Remote struct containing information regarding remote end
+ *
+ * Return: NONE
+ *
+ */
+static void
+scan_negotiation_failed(OPM_T *scanner, OPM_REMOTE_T *remote, int notused, void *data)
+{
+ const struct scanner_struct *scs = data;
+
+ /* Record that a scan happened */
+ scan_log(remote);
+
+ if (OPT_DEBUG)
+ log_printf("SCAN -> Negotiation failed %s:%d (%s) [%s] (%d bytes read)",
+ remote->ip, remote->port, scan_gettype(remote->protocol), scs->name,
+ remote->bytes_read);
+}
+
+/* scan_timeout CALLBACK
+ *
+ * Called by libopm when the negotiation of a specific protocol timed out.
+ *
+ * Parameters:
+ * scanner: Scanner where the connection timed out.
+ * remote: Remote struct containing information regarding remote end
+ *
+ * Return: NONE
+ *
+ */
+static void
+scan_timeout(OPM_T *scanner, OPM_REMOTE_T *remote, int notused, void *data)
+{
+ const struct scanner_struct *scs = data;
+
+ /* Record that a scan happened */
+ scan_log(remote);
+
+ if (OPT_DEBUG)
+ log_printf("SCAN -> Negotiation timed out %s:%d (%s) [%s] (%d bytes read)",
+ remote->ip, remote->port, scan_gettype(remote->protocol), scs->name,
+ remote->bytes_read);
+}
+
+/* scan_end CALLBACK
+ *
+ * Called by libopm when a specific SCAN has completed (all protocols in
+ * that scan).
+ *
+ * Parameters:
+ * scanner: Scanner the scan ended on.
+ * remote: Remote struct containing information regarding remote end
+ *
+ * Return: NONE
+ */
+static void
+scan_end(OPM_T *scanner, OPM_REMOTE_T *remote, int notused, void *data)
+{
+ struct scan_struct *ss = remote->data;
+ struct scanner_struct *scs = data;
+
+ if (OPT_DEBUG)
+ log_printf("SCAN -> Scan %s [%s] completed", remote->ip, scs->name);
+
+ --ss->scans;
+ scan_checkfinished(ss);
+}
+
+/* scan_handle_error CALLBACK
+ *
+ * Called by libopm when an error occurs with a specific connection. This
+ * does not mean the entire scan has ended.
+ *
+ * Parameters:
+ * scanner: Scanner where the error occured.
+ * remote: Remote struct containing information regarding remote end
+ * err: OPM_ERROR code describing the error.
+ *
+ * Return: NONE
+ */
+static void
+scan_handle_error(OPM_T *scanner, OPM_REMOTE_T *remote, int err, void *data)
+{
+ struct scan_struct *ss = remote->data;
+ struct scanner_struct *scs = data;
+
+ switch (err)
+ {
+ case OPM_ERR_MAX_READ:
+ if (OPT_DEBUG >= 2)
+ log_printf("SCAN -> Max read on %s:%d (%s) [%s] (%d bytes read)",
+ remote->ip, remote->port, scan_gettype(remote->protocol),
+ scs->name, remote->bytes_read);
+
+ if (ss->manual_target)
+ irc_send("PRIVMSG %s :CHECK -> Negotiation failed %s:%d (%s) "
+ "[%s] (%d bytes read)", ss->manual_target,
+ remote->ip, remote->port, scan_gettype(remote->protocol),
+ scs->name, remote->bytes_read);
+ break;
+ case OPM_ERR_BIND:
+ log_printf("SCAN -> Bind error on %s:%d (%s) [%s]", remote->ip,
+ remote->port, scan_gettype(remote->protocol), scs->name);
+
+ if (ss->manual_target)
+ irc_send("PRIVMSG %s :CHECK -> Bind error on %s:%d (%s) [%s]",
+ ss->manual_target, remote->ip, remote->port,
+ scan_gettype(remote->protocol), scs->name);
+ break;
+ case OPM_ERR_NOFD:
+ log_printf("SCAN -> File descriptor allocation error %s:%d (%s) "
+ "[%s]", remote->ip, remote->port,
+ scan_gettype(remote->protocol), scs->name);
+
+ if (ss->manual_target)
+ irc_send("PRIVMSG %s :CHECK -> Scan failed %s:%d (%s) [%s] "
+ "(file descriptor allocation error)",
+ ss->manual_target, remote->ip, remote->port,
+ scan_gettype(remote->protocol), scs->name);
+ break;
+ default: /* Unknown Error! */
+ if (OPT_DEBUG)
+ log_printf("SCAN -> Unknown error %s:%d (%s) [%s]", remote->ip,
+ remote->port, scan_gettype(remote->protocol), scs->name);
+ break;
+ }
+}
+
+/* scan_negative
+ *
+ * Remote host (defined by ss) has passed all tests.
+ *
+ * Parameters:
+ * ss: scan_struct containing information regarding negative host.
+ *
+ * Return: NONE
+ *
+ */
+static void
+scan_negative(const struct scan_struct *ss)
+{
+ /* Insert IP in negcache */
+ if (OptionsItem.negcache)
+ {
+ if (OPT_DEBUG >= 2)
+ log_printf("SCAN -> Adding %s to negative cache", ss->ip);
+
+ negcache_insert(ss->ip);
+ }
+}
+
+/* scan_irckline
+ *
+ * ss has been found as a positive host and is to be klined.
+ * Format a kline message using the kline message provided
+ * as a format, then pass it to irc_send() to be sent to the remote server.
+ *
+ * Parameters:
+ * ss: scan_struct containing information regarding host to be klined
+ * format: kline message to format
+ * type: type of proxy found (%t format character)
+ *
+ * Return: NONE
+ */
+static void
+scan_irckline(const struct scan_struct *ss, const char *format, const char *type)
+{
+ char message[MSGLENMAX] = ""; /* OUTPUT */
+
+ unsigned int pos = 0; /* position in format */
+ unsigned int len = 0; /* position in message */
+ unsigned int size = 0; /* temporary size buffer */
+ struct kline_format_assoc
+ {
+ const char key;
+ const char *data;
+ } table[] =
+ {
+ { 'i', ss->ip },
+ { 'h', ss->irc_hostname },
+ { 'u', ss->irc_username },
+ { 'n', ss->irc_nick },
+ { 't', type },
+ { '\0', NULL }
+ };
+
+ /*
+ * Copy format to message character by character, inserting any matching
+ * data after %.
+ */
+ while (format[pos] != '\0' && len < (MSGLENMAX - 2))
+ {
+ switch (format[pos])
+ {
+ case '%':
+ /* % is the last char in the string, move on */
+ if (format[pos + 1] == '\0')
+ continue;
+
+ /* %% escapes % and becomes % */
+ if (format[pos + 1] == '%')
+ {
+ message[len++] = '%';
+ ++pos; /* Skip past the escaped % */
+ break;
+ }
+
+ /* Safe to check against table now */
+ for (const struct kline_format_assoc *tab = table; tab->key; ++tab)
+ {
+ if (tab->key == format[pos + 1])
+ {
+ size = strlen(tab->data);
+
+ /* Check if the new string can fit! */
+ if ((size + len) > (MSGLENMAX - 1))
+ break;
+ else
+ {
+ strlcat(message, tab->data, sizeof(message));
+ len += size;
+ }
+ }
+ }
+
+ /* Skip key character */
+ ++pos;
+ break;
+
+ default:
+ message[len++] = format[pos];
+ message[len] = '\0';
+ break;
+ }
+
+ /* Continue to next character in format */
+ ++pos;
+ }
+
+ irc_send("%s", message);
+}
+
+/* scan_manual
+ *
+ * Create a manual scan. A manual scan is a scan where the
+ * scan_struct contains a manual_target pointer.
+ */
+void
+scan_manual(char *param, const char *target)
+{
+ char buf[INET6_ADDRSTRLEN];
+ const void *addr = NULL;
+ const char *ip = NULL;
+ char *scannername;
+ node_t *node;
+ int ret, n;
+ struct sockaddr_storage storage;
+ socklen_t storage_len = 0;
+
+ /* If there were no parameters sent, simply alert the user and return */
+ if (param == NULL)
+ {
+ irc_send("PRIVMSG %s :OPM -> Invalid parameters.", target);
+ return;
+ }
+
+ /*
+ * Try to extract a scanner name from param, otherwise we'll be
+ * adding to all scanners
+ */
+ ip = param;
+
+ if ((scannername = strchr(param, ' ')))
+ {
+ *scannername = '\0';
+ scannername++;
+ }
+
+ memset(&storage, 0, sizeof(storage));
+
+ if ((addr = firedns_resolveip6(ip)))
+ {
+ struct sockaddr_in6 *in = (struct sockaddr_in6 *)&storage;
+
+ storage_len = sizeof(*in);
+ storage.ss_family = AF_INET6;
+ memcpy(&in->sin6_addr, addr, sizeof(in->sin6_addr));
+ }
+ else if ((addr = firedns_resolveip4(ip)))
+ {
+ struct sockaddr_in *in = (struct sockaddr_in *)&storage;
+
+ storage_len = sizeof(*in);
+ storage.ss_family = AF_INET;
+ memcpy(&in->sin_addr, addr, sizeof(in->sin_addr));
+ }
+ else
+ {
+ irc_send("PRIVMSG %s :CHECK -> Error resolving host '%s': %s",
+ target, ip, firedns_strerror(firedns_errno));
+ return;
+ }
+
+ if ((n = getnameinfo((const struct sockaddr *)&storage, storage_len, buf, sizeof(buf), NULL, 0, NI_NUMERICHOST)))
+ {
+ irc_send("PRIVMSG %s :CHECK -> invalid address: %s",
+ target, gai_strerror(n));
+ return;
+ }
+
+ ip = buf;
+
+ struct scan_struct *ss = xcalloc(sizeof(*ss));
+ ss->ip = xstrdup(ip);
+ ss->remote = opm_remote_create(ss->ip);
+ ss->remote->data = ss;
+ ss->manual_target = target;
+
+ if (scannername)
+ irc_send("PRIVMSG %s :CHECK -> Checking '%s' for open proxies [%s]",
+ target, ss->ip, scannername);
+ else
+ irc_send("PRIVMSG %s :CHECK -> Checking '%s' for open proxies on all scanners",
+ target, ss->ip);
+
+ if (LIST_SIZE(&OpmItem.blacklists))
+ dnsbl_add(ss);
+
+ /* Add ss->remote to all scanners */
+ LIST_FOREACH(node, SCANNERS.head)
+ {
+ struct scanner_struct *scs = node->data;
+
+ /*
+ * If we have a scannername, only allow that scanner
+ * to be used
+ */
+ if (scannername)
+ if (strcasecmp(scannername, scs->name))
+ continue;
+
+ if (OPT_DEBUG)
+ log_printf("SCAN -> Passing %s to scanner [%s] (MANUAL SCAN)", ss->ip, scs->name);
+
+ if ((ret = opm_scan(scs->scanner, ss->remote)) != OPM_SUCCESS)
+ {
+ switch (ret)
+ {
+ case OPM_ERR_NOPROTOCOLS:
+ break;
+ case OPM_ERR_BADADDR:
+ if (!strchr(ss->ip, ':')) /* XXX: hack alert. remove when libopm can deal with IPv6 addresses */
+ irc_send("PRIVMSG %s :OPM -> Bad address %s [%s]",
+ ss->manual_target, ss->ip, scs->name);
+ break;
+ default:
+ irc_send("PRIVMSG %s :OPM -> Unknown error %s [%s]",
+ ss->manual_target, ss->ip, scs->name);
+ break;
+ }
+ }
+ else
+ ++ss->scans; /* Increase scan count only if OPM_SUCCESS */
+ }
+
+ /*
+ * If all of the scanners gave !OPM_SUCCESS and there were no dnsbl checks,
+ * cleanup here
+ */
+ if (ss->scans == 0)
+ {
+ if (scannername)
+ irc_send("PRIVMSG %s :CHECK -> No such scanner '%s', or '%s' has 0 protocols.",
+ ss->manual_target, scannername, scannername);
+
+ irc_send("PRIVMSG %s :CHECK -> No scans active on '%s', aborting scan.",
+ ss->manual_target, ss->ip);
+ scan_free(ss);
+ }
+}
+
+/* scan_log
+ *
+ * Log the fact that a given ip/port/protocol has just been scanned, if the
+ * user has asked for this to be logged.
+ *
+ * Parameters:
+ * remote: OPM_REMOTE_T for the remote end
+ */
+static void
+scan_log(OPM_REMOTE_T *remote)
+{
+ struct scan_struct *ss = remote->data;
+
+ if (!(OptionsItem.scanlog && scanlogfile))
+ return;
+
+ fprintf(scanlogfile, "[%s] %s:%d (%s) \"%s\"\n", date_iso8601(0), remote->ip,
+ remote->port, scan_gettype(remote->protocol), ss->proof);
+ fflush(scanlogfile);
+}
diff --git a/src/scan.h b/src/scan.h
new file mode 100644
index 0000000..c923d1d
--- /dev/null
+++ b/src/scan.h
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2002 Erik Fears
+ * Copyright (c) 2014-2018 ircd-hybrid 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 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
+ * USA
+ */
+
+#ifndef SCAN_H
+#define SCAN_H
+
+#include "libopm/src/opm.h"
+
+struct scan_struct
+{
+ char *irc_nick;
+ char *irc_username;
+ char *irc_hostname;
+
+ char *ip;
+ char *proof;
+ OPM_REMOTE_T *remote;
+
+ unsigned int scans;
+ unsigned int positive;
+
+ const char *manual_target;
+};
+
+struct scanner_struct
+{
+ char *name;
+ OPM_T *scanner;
+ list_t masks;
+};
+
+struct protocol_assoc
+{
+ int type;
+ const char *name;
+};
+
+extern void scan_init(void);
+extern const char *scan_gettype(int);
+extern void scan_cycle(void);
+extern void scan_connect(const char *[], const char *);
+extern void scan_checkfinished(struct scan_struct *);
+extern void scan_manual(char *, const char *);
+extern void scan_timer(void);
+extern void scan_positive(struct scan_struct *, const char *, const char *);
+#endif /* SCAN_H */
diff --git a/src/serno.h b/src/serno.h
new file mode 100644
index 0000000..bdad155
--- /dev/null
+++ b/src/serno.h
@@ -0,0 +1 @@
+#define SERIALNUM "SVN"
diff --git a/src/setup.h.in b/src/setup.h.in
new file mode 100644
index 0000000..b613273
--- /dev/null
+++ b/src/setup.h.in
@@ -0,0 +1,83 @@
+/* src/setup.h.in. Generated from configure.ac by autoheader. */
+
+/* Define if SSP C support is enabled. */
+#undef ENABLE_SSP_CC
+
+/* Define to 1 if you have the <dlfcn.h> header file. */
+#undef HAVE_DLFCN_H
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#undef HAVE_INTTYPES_H
+
+/* Define to 1 if you have the `crypto' library (-lcrypto). */
+#undef HAVE_LIBCRYPTO
+
+/* Define to 1 if you have the `ssl' library (-lssl). */
+#undef HAVE_LIBSSL
+
+/* Define to 1 if you have the <memory.h> header file. */
+#undef HAVE_MEMORY_H
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#undef HAVE_STDINT_H
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#undef HAVE_STDLIB_H
+
+/* Define to 1 if you have the <strings.h> header file. */
+#undef HAVE_STRINGS_H
+
+/* Define to 1 if you have the <string.h> header file. */
+#undef HAVE_STRING_H
+
+/* Define to 1 if you have the `strlcat' function. */
+#undef HAVE_STRLCAT
+
+/* Define to 1 if you have the `strlcpy' function. */
+#undef HAVE_STRLCPY
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#undef HAVE_SYS_STAT_H
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#undef HAVE_SYS_TYPES_H
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#undef HAVE_UNISTD_H
+
+/* Define to the sub-directory where libtool stores uninstalled libraries. */
+#undef LT_OBJDIR
+
+/* Define to disable assert() statements. */
+#undef NDEBUG
+
+/* Name of package */
+#undef PACKAGE
+
+/* Define to the address where bug reports for this package should be sent. */
+#undef PACKAGE_BUGREPORT
+
+/* Define to the full name of this package. */
+#undef PACKAGE_NAME
+
+/* Define to the full name and version of this package. */
+#undef PACKAGE_STRING
+
+/* Define to the one symbol short name of this package. */
+#undef PACKAGE_TARNAME
+
+/* Define to the home page for this package. */
+#undef PACKAGE_URL
+
+/* Define to the version of this package. */
+#undef PACKAGE_VERSION
+
+/* Define to 1 if you have the ANSI C header files. */
+#undef STDC_HEADERS
+
+/* Version number of package */
+#undef VERSION
+
+/* Define to 1 if `lex' declares `yytext' as a `char *' by default, not a
+ `char[]'. */
+#undef YYTEXT_POINTER
diff --git a/src/stats.c b/src/stats.c
new file mode 100644
index 0000000..800a4cc
--- /dev/null
+++ b/src/stats.c
@@ -0,0 +1,249 @@
+/*
+ * Copyright (c) 2002 Erik Fears
+ * Copyright (c) 2014-2018 ircd-hybrid 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 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
+ * USA
+ */
+
+#include "setup.h"
+
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <sys/types.h>
+#include <sys/resource.h> /* getrlimit */
+#include <errno.h>
+
+#include "irc.h"
+#include "log.h"
+#include "misc.h"
+#include "config.h"
+#include "stats.h"
+#include "libopm/src/opm_types.h"
+
+static time_t STATS_UPTIME;
+static unsigned int STATS_CONNECTIONS;
+static unsigned int STATS_DNSBLSENT;
+
+static struct StatsHash STATS_PROXIES[] =
+{
+ { .type = OPM_TYPE_HTTP, .name = "HTTP" },
+ { .type = OPM_TYPE_HTTPPOST, .name = "HTTPPOST" },
+ { .type = OPM_TYPE_HTTPS, .name = "HTTPS" },
+ { .type = OPM_TYPE_HTTPSPOST, .name = "HTTPSPOST" },
+ { .type = OPM_TYPE_SOCKS4, .name = "SOCKS4" },
+ { .type = OPM_TYPE_SOCKS5, .name = "SOCKS5" },
+ { .type = OPM_TYPE_ROUTER, .name = "ROUTER" },
+ { .type = OPM_TYPE_WINGATE, .name = "WINGATE" },
+ { .type = OPM_TYPE_DREAMBOX, .name = "DREAMBOX" },
+ { .type = OPM_TYPE_SSH, .name = "SSH" },
+ { .type = 0 }
+};
+
+
+/* stats_init
+ *
+ * Perform initialization of HOPM stats
+ *
+ * Parameters: NONE
+ * Return: NONE
+ *
+ */
+void
+stats_init(void)
+{
+ time(&STATS_UPTIME);
+}
+
+/* stats_openproxy
+ *
+ * Record open proxy.
+ *
+ *
+ * Parameters: NONE
+ * Return: NONE
+ *
+ */
+void
+stats_openproxy(unsigned int type)
+{
+ for (struct StatsHash *tab = STATS_PROXIES; tab->name; ++tab)
+ {
+ if (tab->type == type)
+ {
+ ++tab->count;
+ break;
+ }
+ }
+}
+
+/* stats_connect
+ *
+ * Record IRC connect.
+ *
+ *
+ * Parameters: NONE
+ * Return: NONE
+ *
+ */
+void
+stats_connect(void)
+{
+ ++STATS_CONNECTIONS;
+}
+
+/* stats_dnsblrecv
+ *
+ * Record that a user was found in the blacklist.
+ *
+ * Parameters: BlacklistConf structure
+ * Return: NONE
+ *
+ */
+void
+stats_dnsblrecv(struct BlacklistConf *bl)
+{
+ ++bl->stats_recv;
+}
+
+/* stats_dnsblsend
+ *
+ * Record a sent report
+ *
+ * Parameters: NONE
+ * Return: NONE
+ *
+ */
+void
+stats_dnsblsend(void)
+{
+ ++STATS_DNSBLSENT;
+}
+
+/* stats_output
+ *
+ * Output stats to target via privmsg
+ *
+ *
+ * Parameters: NONE
+ * Return: NONE
+ *
+ */
+void
+stats_output(const char *target)
+{
+ time_t present;
+ time_t uptime;
+ node_t *p;
+
+ time(&present);
+ uptime = present - STATS_UPTIME;
+
+ irc_send("PRIVMSG %s :Uptime: %s", target, time_dissect(uptime));
+
+ LIST_FOREACH(p, OpmItem.blacklists.head)
+ {
+ const struct BlacklistConf *bl = p->data;
+
+ if (bl->stats_recv)
+ irc_send("PRIVMSG %s :DNSBL: %u successful lookups from %s",
+ target, bl->stats_recv, bl->name);
+ }
+
+ if (STATS_DNSBLSENT)
+ irc_send("PRIVMSG %s :DNSBL: %u reports sent", target,
+ STATS_DNSBLSENT);
+
+ for (const struct StatsHash *tab = STATS_PROXIES; tab->name; ++tab)
+ if (tab->count)
+ irc_send("PRIVMSG %s :Found %u (%s) open.", target,
+ tab->count, tab->name);
+
+ irc_send("PRIVMSG %s :Number of connects: %u (%.2f/minute)",
+ target, STATS_CONNECTIONS, STATS_CONNECTIONS ?
+ (float)STATS_CONNECTIONS / ((float)uptime / 60.0) : 0.0);
+}
+
+/* fdstats_output
+ *
+ * Output file descriptor stats to target via privmsg
+ *
+ *
+ * Parameters: NONE
+ * Return: NONE
+ *
+ */
+void
+fdstats_output(const char *target)
+{
+ struct rlimit rlim;
+ unsigned int total_fd_use = 0;
+
+ /* Get file descriptor ceiling */
+ if (getrlimit(RLIMIT_NOFILE, &rlim) == -1)
+ {
+ log_printf("FDSTAT -> getrlimit() error retrieving RLIMIT_NOFILE (%s)", strerror(errno));
+ irc_send("PRIVMSG %s :FDSTAT -> getrlimit() error retrieving RLIMIT_NOFILE (%s)",
+ target, strerror(errno));
+ return;
+ }
+
+ /*
+ * Check which file descriptors are active, based on suggestions from:
+ * http://groups.google.com/groups?th=a48b9fe8ca43947c&rnum=1
+ */
+ for (unsigned int i = 0; i < rlim.rlim_cur; ++i)
+ {
+ int newfd = dup(i);
+
+ if (newfd > -1)
+ {
+ ++total_fd_use;
+ close(newfd);
+ }
+ else
+ {
+ switch (errno)
+ {
+ case EMFILE:
+ /*
+ * We ran out of FDs whilst trying to dup an existing one,
+ * so all fds are open and we can stop checking here.
+ */
+ i = total_fd_use = rlim.rlim_cur;
+ break;
+
+ case EBADF:
+ /* Not an FD in use. */
+ break;
+
+ case EINTR:
+ /* Try again. */
+ --i;
+ break;
+
+ default:
+ /* We don't expect any other errors. */
+ log_printf("fd %u errno = %u (%s)", i, errno, strerror(errno));
+ break;
+ }
+ }
+ }
+
+ irc_send("PRIVMSG %s :Total open FD: %u/%d", target, total_fd_use, rlim.rlim_cur);
+}
diff --git a/src/stats.h b/src/stats.h
new file mode 100644
index 0000000..f017a09
--- /dev/null
+++ b/src/stats.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2002 Erik Fears
+ * Copyright (c) 2014-2018 ircd-hybrid 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 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
+ * USA
+ */
+
+#ifndef STATS_H
+#define STATS_H
+
+struct StatsHash
+{
+ const unsigned int type;
+ unsigned int count;
+ const char *name;
+};
+
+extern void stats_init(void);
+extern void stats_openproxy(unsigned int);
+extern void stats_connect(void);
+extern void stats_dnsblrecv(struct BlacklistConf *);
+extern void stats_dnsblsend(void);
+extern void stats_output(const char *);
+extern void fdstats_output(const char *);
+
+#endif /* STATS_H */