diff options
| author | 2019-04-07 00:14:13 -0400 | |
|---|---|---|
| committer | 2019-04-07 00:14:13 -0400 | |
| commit | 5140318f8f758141b4e350871db1fe869eb858dc (patch) | |
| tree | 3cf26f4845b2c4674af81f108fbdbf47a996dcff /src | |
Import Upstream version 1.1.5upstream/1.1.5
Diffstat (limited to 'src')
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 */ |
