diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-17 07:42:04 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-17 07:42:04 +0000 |
commit | 0d47952611198ef6b1163f366dc03922d20b1475 (patch) | |
tree | 3d840a3b8c0daef0754707bfb9f5e873b6b1ac13 /nsock/src | |
parent | Initial commit. (diff) | |
download | nmap-0d47952611198ef6b1163f366dc03922d20b1475.tar.xz nmap-0d47952611198ef6b1163f366dc03922d20b1475.zip |
Adding upstream version 7.94+git20230807.3be01efb1+dfsg.upstream/7.94+git20230807.3be01efb1+dfsgupstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'nsock/src')
39 files changed, 17390 insertions, 0 deletions
diff --git a/nsock/src/Makefile.in b/nsock/src/Makefile.in new file mode 100644 index 0000000..569d999 --- /dev/null +++ b/nsock/src/Makefile.in @@ -0,0 +1,97 @@ +NSOCK_VERSION = 0.02 +prefix = @prefix@ +exec_prefix = @exec_prefix@ +bindir = @bindir@ +sbindir = @sbindir@ +mandir = @mandir@ +srcdir = @srcdir@ +datarootdir = @datarootdir@ + +CC = @CC@ +AR = ar +RANLIB = @RANLIB@ +CCOPT = +DEFS = @DEFS@ -DNSOCK_VERSION=\"$(NSOCK_VERSION)\" +# With GCC, add extra security checks to source code. +DEFS += -D_FORTIFY_SOURCE=2 +INCLS = -I../include +CFLAGS = @CFLAGS@ $(CCOPT) +# CFLAGS = -g -Wall $(DEFS) $(INCLS) +CPPFLAGS = @CPPFLAGS@ $(DEFS) $(INCLS) +STATIC = +SHTOOL = ./shtool +INSTALL = $(SHTOOL) install +MAKEDEPEND = @MAKEDEPEND@ +RPMTDIR=$(HOME)/rpmdir +NBASEDIR=@NBASEDIR@ +NSOCKTESTDIR=@NSOCKTESTDIR@ + +TARGET = libnsock.a + +SRCS = error.c filespace.c gh_heap.c nsock_connect.c nsock_core.c \ + nsock_iod.c nsock_read.c nsock_timers.c nsock_write.c \ + nsock_ssl.c nsock_event.c nsock_pool.c netutils.c nsock_pcap.c \ + nsock_engines.c engine_select.c engine_epoll.c engine_kqueue.c \ + engine_poll.c nsock_proxy.c nsock_log.c proxy_http.c proxy_socks4.c + +OBJS = error.o filespace.o gh_heap.o nsock_connect.o nsock_core.o \ + nsock_iod.o nsock_read.o nsock_timers.o nsock_write.o \ + nsock_ssl.o nsock_event.o nsock_pool.o netutils.o nsock_pcap.o \ + nsock_engines.o engine_select.o engine_epoll.o engine_kqueue.o \ + engine_poll.o nsock_proxy.o nsock_log.o proxy_http.o proxy_socks4.o + +DEPS = error.h filespace.h gh_list.h nsock_internal.h netutils.h nsock_pcap.h \ + nsock_log.h nsock_proxy.h gh_heap.h ../include/nsock.h \ + $(NBASEDIR)/libnbase.a + +.c.o: + $(CC) -c $(CPPFLAGS) $(CFLAGS) $< -o $@ + +all: $(TARGET) + +$(TARGET): $(DEPS) $(OBJS) + rm -f $@ + $(AR) cr $@ $(OBJS) + $(RANLIB) $@ + +$(NBASEDIR)/libnbase.a: $(NBASEDIR)/Makefile + cd $(NBASEDIR) && $(MAKE) + +clean-test: + cd $(NSOCKTESTDIR) && $(MAKE) clean + +clean: clean-test + rm -f $(OBJS) $(TARGET) + +distclean: clean + rm -f Makefile makefile.dep config.log config.status ../include/nsock_config.h $(NSOCKTESTDIR)/Makefile + +depend: + $(MAKEDEPEND) $(INCLS) -s "# DO NOT DELETE" -- $(DEFS) -- $(SRCS) + +check: + cd $(NSOCKTESTDIR) && $(MAKE) && ./run_tests.sh + +${srcdir}/configure: configure.ac + cd ${srcdir} && autoconf + +# autoheader might not change config.h.in, so touch a stamp file. +${srcdir}/config.h.in: stamp-h.in +${srcdir}/stamp-h.in: configure.ac acconfig.h \ + config.h.top config.h.bot + cd ${srcdir} && autoheader + echo timestamp > ${srcdir}/stamp-h.in + +config.h: stamp-h +stamp-h: config.h.in config.status + ./config.status + +Makefile: Makefile.in config.status + ./config.status + +config.status: configure + ./config.status --recheck + +makefile.dep: + $(CC) -MM $(CPPFLAGS) $(SRCS) > $@ +-include makefile.dep diff --git a/nsock/src/acinclude.m4 b/nsock/src/acinclude.m4 new file mode 100644 index 0000000..fc09664 --- /dev/null +++ b/nsock/src/acinclude.m4 @@ -0,0 +1,119 @@ +# =========================================================================== +# http://www.gnu.org/software/autoconf-archive/ax_have_epoll.html +# =========================================================================== +# +# SYNOPSIS +# +# AX_HAVE_EPOLL([ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND]) +# AX_HAVE_EPOLL_PWAIT([ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND]) +# +# DESCRIPTION +# +# This macro determines whether the system supports the epoll I/O event +# interface. A neat usage example would be: +# +# AX_HAVE_EPOLL( +# [AX_CONFIG_FEATURE_ENABLE(epoll)], +# [AX_CONFIG_FEATURE_DISABLE(epoll)]) +# AX_CONFIG_FEATURE( +# [epoll], [This platform supports epoll(7)], +# [HAVE_EPOLL], [This platform supports epoll(7).]) +# +# The epoll interface was added to the Linux kernel in version 2.5.45, and +# the macro verifies that a kernel newer than this is installed. This +# check is somewhat unreliable if <linux/version.h> doesn't match the +# running kernel, but it is necessary regardless, because glibc comes with +# stubs for the epoll_create(), epoll_wait(), etc. that allow programs to +# compile and link even if the kernel is too old; the problem would then +# be detected only at runtime. +# +# Linux kernel version 2.6.19 adds the epoll_pwait() call in addition to +# epoll_wait(). The availability of that function can be tested with the +# second macro. Generally speaking, it is safe to assume that +# AX_HAVE_EPOLL would succeed if AX_HAVE_EPOLL_PWAIT has, but not the +# other way round. +# +# LICENSE +# +# Copyright (c) 2008 Peter Simons <simons@cryp.to> +# +# Copying and distribution of this file, with or without modification, are +# permitted in any medium without royalty provided the copyright notice +# and this notice are preserved. This file is offered as-is, without any +# warranty. + +#serial 10 + +AC_DEFUN([AX_HAVE_EPOLL], [dnl + ax_have_epoll_cppflags="${CPPFLAGS}" + AC_CHECK_HEADER([linux/version.h], [CPPFLAGS="${CPPFLAGS} -DHAVE_LINUX_VERSION_H"]) + AC_MSG_CHECKING([for Linux epoll(7) interface]) + AC_CACHE_VAL([ax_cv_have_epoll], [dnl + AC_LINK_IFELSE([dnl + AC_LANG_PROGRAM([dnl +#include <sys/epoll.h> +#ifdef HAVE_LINUX_VERSION_H +# include <linux/version.h> +# if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,45) +# error linux kernel version is too old to have epoll +# endif +#endif +], [dnl +int fd, rc; +struct epoll_event ev; +fd = epoll_create(128); +rc = epoll_wait(fd, &ev, 1, 0);])], + [ax_cv_have_epoll=yes], + [ax_cv_have_epoll=no])]) + CPPFLAGS="${ax_have_epoll_cppflags}" + AS_IF([test "${ax_cv_have_epoll}" = "yes"], + [AC_MSG_RESULT([yes]) +$1],[AC_MSG_RESULT([no]) +$2]) +])dnl + +AC_DEFUN([AX_HAVE_EPOLL_PWAIT], [dnl + ax_have_epoll_cppflags="${CPPFLAGS}" + AC_CHECK_HEADER([linux/version.h], + [CPPFLAGS="${CPPFLAGS} -DHAVE_LINUX_VERSION_H"]) + AC_MSG_CHECKING([for Linux epoll(7) interface with signals extension]) + AC_CACHE_VAL([ax_cv_have_epoll_pwait], [dnl + AC_LINK_IFELSE([dnl + AC_LANG_PROGRAM([dnl +#ifdef HAVE_LINUX_VERSION_H +# include <linux/version.h> +# if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19) +# error linux kernel version is too old to have epoll_pwait +# endif +#endif +#include <sys/epoll.h> +#include <signal.h> +], [dnl +int fd, rc; +struct epoll_event ev; +fd = epoll_create(128); +rc = epoll_wait(fd, &ev, 1, 0); +rc = epoll_pwait(fd, &ev, 1, 0, (sigset_t const *)(0));])], + [ax_cv_have_epoll_pwait=yes], + [ax_cv_have_epoll_pwait=no])]) + CPPFLAGS="${ax_have_epoll_cppflags}" + AS_IF([test "${ax_cv_have_epoll_pwait}" = "yes"], + [AC_MSG_RESULT([yes]) +$1],[AC_MSG_RESULT([no]) +$2]) +])dnl + +AC_DEFUN([AX_HAVE_POLL], [dnl + AC_MSG_CHECKING([for poll(2)]) + AC_CACHE_VAL([ax_cv_have_poll], [dnl + AC_LINK_IFELSE([dnl + AC_LANG_PROGRAM( + [#include <poll.h>], + [int rc; rc = poll((struct pollfd *)(0), 0, 0);])], + [ax_cv_have_poll=yes], + [ax_cv_have_poll=no])]) + AS_IF([test "${ax_cv_have_poll}" = "yes"], + [AC_MSG_RESULT([yes]) +$1],[AC_MSG_RESULT([no]) +$2]) +])dnl diff --git a/nsock/src/aclocal.m4 b/nsock/src/aclocal.m4 new file mode 100644 index 0000000..e798741 --- /dev/null +++ b/nsock/src/aclocal.m4 @@ -0,0 +1,15 @@ +# generated automatically by aclocal 1.11.6 -*- Autoconf -*- + +# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, +# 2005, 2006, 2007, 2008, 2009, 2010, 2011 Free Software Foundation, +# Inc. +# This file 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. + +m4_include([acinclude.m4]) diff --git a/nsock/src/configure b/nsock/src/configure new file mode 100755 index 0000000..2bf7194 --- /dev/null +++ b/nsock/src/configure @@ -0,0 +1,6298 @@ +#! /bin/sh +# Guess values for system-dependent variables and create Makefiles. +# Generated by GNU Autoconf 2.69. +# +# +# Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc. +# +# +# This configure script is free software; the Free Software Foundation +# gives unlimited permission to copy, distribute and modify it. +## -------------------- ## +## M4sh Initialization. ## +## -------------------- ## + +# Be more Bourne compatible +DUALCASE=1; export DUALCASE # for MKS sh +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : + emulate sh + NULLCMD=: + # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which + # is contrary to our usage. Disable this feature. + alias -g '${1+"$@"}'='"$@"' + setopt NO_GLOB_SUBST +else + case `(set -o) 2>/dev/null` in #( + *posix*) : + set -o posix ;; #( + *) : + ;; +esac +fi + + +as_nl=' +' +export as_nl +# Printing a long string crashes Solaris 7 /usr/bin/printf. +as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' +as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo +as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo +# Prefer a ksh shell builtin over an external printf program on Solaris, +# but without wasting forks for bash or zsh. +if test -z "$BASH_VERSION$ZSH_VERSION" \ + && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then + as_echo='print -r --' + as_echo_n='print -rn --' +elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then + as_echo='printf %s\n' + as_echo_n='printf %s' +else + if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then + as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' + as_echo_n='/usr/ucb/echo -n' + else + as_echo_body='eval expr "X$1" : "X\\(.*\\)"' + as_echo_n_body='eval + arg=$1; + case $arg in #( + *"$as_nl"*) + expr "X$arg" : "X\\(.*\\)$as_nl"; + arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; + esac; + expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" + ' + export as_echo_n_body + as_echo_n='sh -c $as_echo_n_body as_echo' + fi + export as_echo_body + as_echo='sh -c $as_echo_body as_echo' +fi + +# The user is always right. +if test "${PATH_SEPARATOR+set}" != set; then + PATH_SEPARATOR=: + (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { + (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || + PATH_SEPARATOR=';' + } +fi + + +# IFS +# We need space, tab and new line, in precisely that order. Quoting is +# there to prevent editors from complaining about space-tab. +# (If _AS_PATH_WALK were called with IFS unset, it would disable word +# splitting by setting IFS to empty value.) +IFS=" "" $as_nl" + +# Find who we are. Look in the path if we contain no directory separator. +as_myself= +case $0 in #(( + *[\\/]* ) as_myself=$0 ;; + *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break + done +IFS=$as_save_IFS + + ;; +esac +# We did not find ourselves, most probably we were run as `sh COMMAND' +# in which case we are not to be found in the path. +if test "x$as_myself" = x; then + as_myself=$0 +fi +if test ! -f "$as_myself"; then + $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 + exit 1 +fi + +# Unset variables that we do not need and which cause bugs (e.g. in +# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" +# suppresses any "Segmentation fault" message there. '((' could +# trigger a bug in pdksh 5.2.14. +for as_var in BASH_ENV ENV MAIL MAILPATH +do eval test x\${$as_var+set} = xset \ + && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : +done +PS1='$ ' +PS2='> ' +PS4='+ ' + +# NLS nuisances. +LC_ALL=C +export LC_ALL +LANGUAGE=C +export LANGUAGE + +# CDPATH. +(unset CDPATH) >/dev/null 2>&1 && unset CDPATH + +# Use a proper internal environment variable to ensure we don't fall + # into an infinite loop, continuously re-executing ourselves. + if test x"${_as_can_reexec}" != xno && test "x$CONFIG_SHELL" != x; then + _as_can_reexec=no; export _as_can_reexec; + # We cannot yet assume a decent shell, so we have to provide a +# neutralization value for shells without unset; and this also +# works around shells that cannot unset nonexistent variables. +# Preserve -v and -x to the replacement shell. +BASH_ENV=/dev/null +ENV=/dev/null +(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV +case $- in # (((( + *v*x* | *x*v* ) as_opts=-vx ;; + *v* ) as_opts=-v ;; + *x* ) as_opts=-x ;; + * ) as_opts= ;; +esac +exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} +# Admittedly, this is quite paranoid, since all the known shells bail +# out after a failed `exec'. +$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2 +as_fn_exit 255 + fi + # We don't want this to propagate to other subprocesses. + { _as_can_reexec=; unset _as_can_reexec;} +if test "x$CONFIG_SHELL" = x; then + as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then : + emulate sh + NULLCMD=: + # Pre-4.2 versions of Zsh do word splitting on \${1+\"\$@\"}, which + # is contrary to our usage. Disable this feature. + alias -g '\${1+\"\$@\"}'='\"\$@\"' + setopt NO_GLOB_SUBST +else + case \`(set -o) 2>/dev/null\` in #( + *posix*) : + set -o posix ;; #( + *) : + ;; +esac +fi +" + as_required="as_fn_return () { (exit \$1); } +as_fn_success () { as_fn_return 0; } +as_fn_failure () { as_fn_return 1; } +as_fn_ret_success () { return 0; } +as_fn_ret_failure () { return 1; } + +exitcode=0 +as_fn_success || { exitcode=1; echo as_fn_success failed.; } +as_fn_failure && { exitcode=1; echo as_fn_failure succeeded.; } +as_fn_ret_success || { exitcode=1; echo as_fn_ret_success failed.; } +as_fn_ret_failure && { exitcode=1; echo as_fn_ret_failure succeeded.; } +if ( set x; as_fn_ret_success y && test x = \"\$1\" ); then : + +else + exitcode=1; echo positional parameters were not saved. +fi +test x\$exitcode = x0 || exit 1 +test -x / || exit 1" + as_suggested=" as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO + as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO + eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" && + test \"x\`expr \$as_lineno_1'\$as_run' + 1\`\" = \"x\$as_lineno_2'\$as_run'\"' || exit 1 +test \$(( 1 + 1 )) = 2 || exit 1" + if (eval "$as_required") 2>/dev/null; then : + as_have_required=yes +else + as_have_required=no +fi + if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null; then : + +else + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +as_found=false +for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + as_found=: + case $as_dir in #( + /*) + for as_base in sh bash ksh sh5; do + # Try only shells that exist, to save several forks. + as_shell=$as_dir/$as_base + if { test -f "$as_shell" || test -f "$as_shell.exe"; } && + { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$as_shell"; } 2>/dev/null; then : + CONFIG_SHELL=$as_shell as_have_required=yes + if { $as_echo "$as_bourne_compatible""$as_suggested" | as_run=a "$as_shell"; } 2>/dev/null; then : + break 2 +fi +fi + done;; + esac + as_found=false +done +$as_found || { if { test -f "$SHELL" || test -f "$SHELL.exe"; } && + { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$SHELL"; } 2>/dev/null; then : + CONFIG_SHELL=$SHELL as_have_required=yes +fi; } +IFS=$as_save_IFS + + + if test "x$CONFIG_SHELL" != x; then : + export CONFIG_SHELL + # We cannot yet assume a decent shell, so we have to provide a +# neutralization value for shells without unset; and this also +# works around shells that cannot unset nonexistent variables. +# Preserve -v and -x to the replacement shell. +BASH_ENV=/dev/null +ENV=/dev/null +(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV +case $- in # (((( + *v*x* | *x*v* ) as_opts=-vx ;; + *v* ) as_opts=-v ;; + *x* ) as_opts=-x ;; + * ) as_opts= ;; +esac +exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} +# Admittedly, this is quite paranoid, since all the known shells bail +# out after a failed `exec'. +$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2 +exit 255 +fi + + if test x$as_have_required = xno; then : + $as_echo "$0: This script requires a shell more modern than all" + $as_echo "$0: the shells that I found on your system." + if test x${ZSH_VERSION+set} = xset ; then + $as_echo "$0: In particular, zsh $ZSH_VERSION has bugs and should" + $as_echo "$0: be upgraded to zsh 4.3.4 or later." + else + $as_echo "$0: Please tell bug-autoconf@gnu.org about your system, +$0: including any error possibly output before this +$0: message. Then install a modern shell, or manually run +$0: the script under such a shell if you do have one." + fi + exit 1 +fi +fi +fi +SHELL=${CONFIG_SHELL-/bin/sh} +export SHELL +# Unset more variables known to interfere with behavior of common tools. +CLICOLOR_FORCE= GREP_OPTIONS= +unset CLICOLOR_FORCE GREP_OPTIONS + +## --------------------- ## +## M4sh Shell Functions. ## +## --------------------- ## +# as_fn_unset VAR +# --------------- +# Portably unset VAR. +as_fn_unset () +{ + { eval $1=; unset $1;} +} +as_unset=as_fn_unset + +# as_fn_set_status STATUS +# ----------------------- +# Set $? to STATUS, without forking. +as_fn_set_status () +{ + return $1 +} # as_fn_set_status + +# as_fn_exit STATUS +# ----------------- +# Exit the shell with STATUS, even in a "trap 0" or "set -e" context. +as_fn_exit () +{ + set +e + as_fn_set_status $1 + exit $1 +} # as_fn_exit + +# as_fn_mkdir_p +# ------------- +# Create "$as_dir" as a directory, including parents if necessary. +as_fn_mkdir_p () +{ + + case $as_dir in #( + -*) as_dir=./$as_dir;; + esac + test -d "$as_dir" || eval $as_mkdir_p || { + as_dirs= + while :; do + case $as_dir in #( + *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( + *) as_qdir=$as_dir;; + esac + as_dirs="'$as_qdir' $as_dirs" + as_dir=`$as_dirname -- "$as_dir" || +$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$as_dir" : 'X\(//\)[^/]' \| \ + X"$as_dir" : 'X\(//\)$' \| \ + X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$as_dir" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + test -d "$as_dir" && break + done + test -z "$as_dirs" || eval "mkdir $as_dirs" + } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" + + +} # as_fn_mkdir_p + +# as_fn_executable_p FILE +# ----------------------- +# Test if FILE is an executable regular file. +as_fn_executable_p () +{ + test -f "$1" && test -x "$1" +} # as_fn_executable_p +# as_fn_append VAR VALUE +# ---------------------- +# Append the text in VALUE to the end of the definition contained in VAR. Take +# advantage of any shell optimizations that allow amortized linear growth over +# repeated appends, instead of the typical quadratic growth present in naive +# implementations. +if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : + eval 'as_fn_append () + { + eval $1+=\$2 + }' +else + as_fn_append () + { + eval $1=\$$1\$2 + } +fi # as_fn_append + +# as_fn_arith ARG... +# ------------------ +# Perform arithmetic evaluation on the ARGs, and store the result in the +# global $as_val. Take advantage of shells that can avoid forks. The arguments +# must be portable across $(()) and expr. +if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : + eval 'as_fn_arith () + { + as_val=$(( $* )) + }' +else + as_fn_arith () + { + as_val=`expr "$@" || test $? -eq 1` + } +fi # as_fn_arith + + +# as_fn_error STATUS ERROR [LINENO LOG_FD] +# ---------------------------------------- +# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are +# provided, also output the error to LOG_FD, referencing LINENO. Then exit the +# script with STATUS, using 1 if that was 0. +as_fn_error () +{ + as_status=$1; test $as_status -eq 0 && as_status=1 + if test "$4"; then + as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 + fi + $as_echo "$as_me: error: $2" >&2 + as_fn_exit $as_status +} # as_fn_error + +if expr a : '\(a\)' >/dev/null 2>&1 && + test "X`expr 00001 : '.*\(...\)'`" = X001; then + as_expr=expr +else + as_expr=false +fi + +if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then + as_basename=basename +else + as_basename=false +fi + +if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then + as_dirname=dirname +else + as_dirname=false +fi + +as_me=`$as_basename -- "$0" || +$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ + X"$0" : 'X\(//\)$' \| \ + X"$0" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X/"$0" | + sed '/^.*\/\([^/][^/]*\)\/*$/{ + s//\1/ + q + } + /^X\/\(\/\/\)$/{ + s//\1/ + q + } + /^X\/\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + +# Avoid depending upon Character Ranges. +as_cr_letters='abcdefghijklmnopqrstuvwxyz' +as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' +as_cr_Letters=$as_cr_letters$as_cr_LETTERS +as_cr_digits='0123456789' +as_cr_alnum=$as_cr_Letters$as_cr_digits + + + as_lineno_1=$LINENO as_lineno_1a=$LINENO + as_lineno_2=$LINENO as_lineno_2a=$LINENO + eval 'test "x$as_lineno_1'$as_run'" != "x$as_lineno_2'$as_run'" && + test "x`expr $as_lineno_1'$as_run' + 1`" = "x$as_lineno_2'$as_run'"' || { + # Blame Lee E. McMahon (1931-1989) for sed's syntax. :-) + sed -n ' + p + /[$]LINENO/= + ' <$as_myself | + sed ' + s/[$]LINENO.*/&-/ + t lineno + b + :lineno + N + :loop + s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/ + t loop + s/-\n.*// + ' >$as_me.lineno && + chmod +x "$as_me.lineno" || + { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; } + + # If we had to re-execute with $CONFIG_SHELL, we're ensured to have + # already done that, so ensure we don't try to do so again and fall + # in an infinite loop. This has already happened in practice. + _as_can_reexec=no; export _as_can_reexec + # Don't try to exec as it changes $[0], causing all sort of problems + # (the dirname of $[0] is not the place where we might find the + # original and so on. Autoconf is especially sensitive to this). + . "./$as_me.lineno" + # Exit status is that of the last command. + exit +} + +ECHO_C= ECHO_N= ECHO_T= +case `echo -n x` in #((((( +-n*) + case `echo 'xy\c'` in + *c*) ECHO_T=' ';; # ECHO_T is single tab character. + xy) ECHO_C='\c';; + *) echo `echo ksh88 bug on AIX 6.1` > /dev/null + ECHO_T=' ';; + esac;; +*) + ECHO_N='-n';; +esac + +rm -f conf$$ conf$$.exe conf$$.file +if test -d conf$$.dir; then + rm -f conf$$.dir/conf$$.file +else + rm -f conf$$.dir + mkdir conf$$.dir 2>/dev/null +fi +if (echo >conf$$.file) 2>/dev/null; then + if ln -s conf$$.file conf$$ 2>/dev/null; then + as_ln_s='ln -s' + # ... but there are two gotchas: + # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. + # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. + # In both cases, we have to default to `cp -pR'. + ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || + as_ln_s='cp -pR' + elif ln conf$$.file conf$$ 2>/dev/null; then + as_ln_s=ln + else + as_ln_s='cp -pR' + fi +else + as_ln_s='cp -pR' +fi +rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file +rmdir conf$$.dir 2>/dev/null + +if mkdir -p . 2>/dev/null; then + as_mkdir_p='mkdir -p "$as_dir"' +else + test -d ./-p && rmdir ./-p + as_mkdir_p=false +fi + +as_test_x='test -x' +as_executable_p=as_fn_executable_p + +# Sed expression to map a string onto a valid CPP name. +as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" + +# Sed expression to map a string onto a valid variable name. +as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" + + +test -n "$DJDIR" || exec 7<&0 </dev/null +exec 6>&1 + +# Name of the host. +# hostname on some systems (SVR3.2, old GNU/Linux) returns a bogus exit status, +# so uname gets run too. +ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q` + +# +# Initializations. +# +ac_default_prefix=/usr/local +ac_clean_files= +ac_config_libobj_dir=. +LIBOBJS= +cross_compiling=no +subdirs= +MFLAGS= +MAKEFLAGS= + +# Identity of this package. +PACKAGE_NAME= +PACKAGE_TARNAME= +PACKAGE_VERSION= +PACKAGE_STRING= +PACKAGE_BUGREPORT= +PACKAGE_URL= + +ac_unique_file="nsock_core.c" +# Factoring default headers for most tests. +ac_includes_default="\ +#include <stdio.h> +#ifdef HAVE_SYS_TYPES_H +# include <sys/types.h> +#endif +#ifdef HAVE_SYS_STAT_H +# include <sys/stat.h> +#endif +#ifdef STDC_HEADERS +# include <stdlib.h> +# include <stddef.h> +#else +# ifdef HAVE_STDLIB_H +# include <stdlib.h> +# endif +#endif +#ifdef HAVE_STRING_H +# if !defined STDC_HEADERS && defined HAVE_MEMORY_H +# include <memory.h> +# endif +# include <string.h> +#endif +#ifdef HAVE_STRINGS_H +# include <strings.h> +#endif +#ifdef HAVE_INTTYPES_H +# include <inttypes.h> +#endif +#ifdef HAVE_STDINT_H +# include <stdint.h> +#endif +#ifdef HAVE_UNISTD_H +# include <unistd.h> +#endif" + +ac_subst_vars='LTLIBOBJS +LIBOBJS +NSOCKTESTDIR +NBASEDIR +LIBNBASE_LIBS +OPENSSL_LIBS +RANLIB +LIBPCAP_LIBS +EGREP +GREP +CPP +OBJEXT +EXEEXT +ac_ct_CC +CPPFLAGS +LDFLAGS +CFLAGS +CC +host_os +host_vendor +host_cpu +host +build_os +build_vendor +build_cpu +build +target_alias +host_alias +build_alias +LIBS +ECHO_T +ECHO_N +ECHO_C +DEFS +mandir +localedir +libdir +psdir +pdfdir +dvidir +htmldir +infodir +docdir +oldincludedir +includedir +runstatedir +localstatedir +sharedstatedir +sysconfdir +datadir +datarootdir +libexecdir +sbindir +bindir +program_transform_name +prefix +exec_prefix +PACKAGE_URL +PACKAGE_BUGREPORT +PACKAGE_STRING +PACKAGE_VERSION +PACKAGE_TARNAME +PACKAGE_NAME +PATH_SEPARATOR +SHELL' +ac_subst_files='' +ac_user_opts=' +enable_option_checking +with_localdirs +with_libpcap +with_openssl +with_libnbase +' + ac_precious_vars='build_alias +host_alias +target_alias +CC +CFLAGS +LDFLAGS +LIBS +CPPFLAGS +CPP' + + +# Initialize some variables set by options. +ac_init_help= +ac_init_version=false +ac_unrecognized_opts= +ac_unrecognized_sep= +# The variables have the same names as the options, with +# dashes changed to underlines. +cache_file=/dev/null +exec_prefix=NONE +no_create= +no_recursion= +prefix=NONE +program_prefix=NONE +program_suffix=NONE +program_transform_name=s,x,x, +silent= +site= +srcdir= +verbose= +x_includes=NONE +x_libraries=NONE + +# Installation directory options. +# These are left unexpanded so users can "make install exec_prefix=/foo" +# and all the variables that are supposed to be based on exec_prefix +# by default will actually change. +# Use braces instead of parens because sh, perl, etc. also accept them. +# (The list follows the same order as the GNU Coding Standards.) +bindir='${exec_prefix}/bin' +sbindir='${exec_prefix}/sbin' +libexecdir='${exec_prefix}/libexec' +datarootdir='${prefix}/share' +datadir='${datarootdir}' +sysconfdir='${prefix}/etc' +sharedstatedir='${prefix}/com' +localstatedir='${prefix}/var' +runstatedir='${localstatedir}/run' +includedir='${prefix}/include' +oldincludedir='/usr/include' +docdir='${datarootdir}/doc/${PACKAGE}' +infodir='${datarootdir}/info' +htmldir='${docdir}' +dvidir='${docdir}' +pdfdir='${docdir}' +psdir='${docdir}' +libdir='${exec_prefix}/lib' +localedir='${datarootdir}/locale' +mandir='${datarootdir}/man' + +ac_prev= +ac_dashdash= +for ac_option +do + # If the previous option needs an argument, assign it. + if test -n "$ac_prev"; then + eval $ac_prev=\$ac_option + ac_prev= + continue + fi + + case $ac_option in + *=?*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;; + *=) ac_optarg= ;; + *) ac_optarg=yes ;; + esac + + # Accept the important Cygnus configure options, so we can diagnose typos. + + case $ac_dashdash$ac_option in + --) + ac_dashdash=yes ;; + + -bindir | --bindir | --bindi | --bind | --bin | --bi) + ac_prev=bindir ;; + -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*) + bindir=$ac_optarg ;; + + -build | --build | --buil | --bui | --bu) + ac_prev=build_alias ;; + -build=* | --build=* | --buil=* | --bui=* | --bu=*) + build_alias=$ac_optarg ;; + + -cache-file | --cache-file | --cache-fil | --cache-fi \ + | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) + ac_prev=cache_file ;; + -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ + | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) + cache_file=$ac_optarg ;; + + --config-cache | -C) + cache_file=config.cache ;; + + -datadir | --datadir | --datadi | --datad) + ac_prev=datadir ;; + -datadir=* | --datadir=* | --datadi=* | --datad=*) + datadir=$ac_optarg ;; + + -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \ + | --dataroo | --dataro | --datar) + ac_prev=datarootdir ;; + -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \ + | --dataroot=* | --dataroo=* | --dataro=* | --datar=*) + datarootdir=$ac_optarg ;; + + -disable-* | --disable-*) + ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && + as_fn_error $? "invalid feature name: $ac_useropt" + ac_useropt_orig=$ac_useropt + ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` + case $ac_user_opts in + *" +"enable_$ac_useropt" +"*) ;; + *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--disable-$ac_useropt_orig" + ac_unrecognized_sep=', ';; + esac + eval enable_$ac_useropt=no ;; + + -docdir | --docdir | --docdi | --doc | --do) + ac_prev=docdir ;; + -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*) + docdir=$ac_optarg ;; + + -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv) + ac_prev=dvidir ;; + -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*) + dvidir=$ac_optarg ;; + + -enable-* | --enable-*) + ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && + as_fn_error $? "invalid feature name: $ac_useropt" + ac_useropt_orig=$ac_useropt + ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` + case $ac_user_opts in + *" +"enable_$ac_useropt" +"*) ;; + *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--enable-$ac_useropt_orig" + ac_unrecognized_sep=', ';; + esac + eval enable_$ac_useropt=\$ac_optarg ;; + + -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ + | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ + | --exec | --exe | --ex) + ac_prev=exec_prefix ;; + -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ + | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ + | --exec=* | --exe=* | --ex=*) + exec_prefix=$ac_optarg ;; + + -gas | --gas | --ga | --g) + # Obsolete; use --with-gas. + with_gas=yes ;; + + -help | --help | --hel | --he | -h) + ac_init_help=long ;; + -help=r* | --help=r* | --hel=r* | --he=r* | -hr*) + ac_init_help=recursive ;; + -help=s* | --help=s* | --hel=s* | --he=s* | -hs*) + ac_init_help=short ;; + + -host | --host | --hos | --ho) + ac_prev=host_alias ;; + -host=* | --host=* | --hos=* | --ho=*) + host_alias=$ac_optarg ;; + + -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht) + ac_prev=htmldir ;; + -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \ + | --ht=*) + htmldir=$ac_optarg ;; + + -includedir | --includedir | --includedi | --included | --include \ + | --includ | --inclu | --incl | --inc) + ac_prev=includedir ;; + -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \ + | --includ=* | --inclu=* | --incl=* | --inc=*) + includedir=$ac_optarg ;; + + -infodir | --infodir | --infodi | --infod | --info | --inf) + ac_prev=infodir ;; + -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*) + infodir=$ac_optarg ;; + + -libdir | --libdir | --libdi | --libd) + ac_prev=libdir ;; + -libdir=* | --libdir=* | --libdi=* | --libd=*) + libdir=$ac_optarg ;; + + -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \ + | --libexe | --libex | --libe) + ac_prev=libexecdir ;; + -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \ + | --libexe=* | --libex=* | --libe=*) + libexecdir=$ac_optarg ;; + + -localedir | --localedir | --localedi | --localed | --locale) + ac_prev=localedir ;; + -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*) + localedir=$ac_optarg ;; + + -localstatedir | --localstatedir | --localstatedi | --localstated \ + | --localstate | --localstat | --localsta | --localst | --locals) + ac_prev=localstatedir ;; + -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ + | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*) + localstatedir=$ac_optarg ;; + + -mandir | --mandir | --mandi | --mand | --man | --ma | --m) + ac_prev=mandir ;; + -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*) + mandir=$ac_optarg ;; + + -nfp | --nfp | --nf) + # Obsolete; use --without-fp. + with_fp=no ;; + + -no-create | --no-create | --no-creat | --no-crea | --no-cre \ + | --no-cr | --no-c | -n) + no_create=yes ;; + + -no-recursion | --no-recursion | --no-recursio | --no-recursi \ + | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) + no_recursion=yes ;; + + -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \ + | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \ + | --oldin | --oldi | --old | --ol | --o) + ac_prev=oldincludedir ;; + -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \ + | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \ + | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*) + oldincludedir=$ac_optarg ;; + + -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) + ac_prev=prefix ;; + -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) + prefix=$ac_optarg ;; + + -program-prefix | --program-prefix | --program-prefi | --program-pref \ + | --program-pre | --program-pr | --program-p) + ac_prev=program_prefix ;; + -program-prefix=* | --program-prefix=* | --program-prefi=* \ + | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*) + program_prefix=$ac_optarg ;; + + -program-suffix | --program-suffix | --program-suffi | --program-suff \ + | --program-suf | --program-su | --program-s) + ac_prev=program_suffix ;; + -program-suffix=* | --program-suffix=* | --program-suffi=* \ + | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*) + program_suffix=$ac_optarg ;; + + -program-transform-name | --program-transform-name \ + | --program-transform-nam | --program-transform-na \ + | --program-transform-n | --program-transform- \ + | --program-transform | --program-transfor \ + | --program-transfo | --program-transf \ + | --program-trans | --program-tran \ + | --progr-tra | --program-tr | --program-t) + ac_prev=program_transform_name ;; + -program-transform-name=* | --program-transform-name=* \ + | --program-transform-nam=* | --program-transform-na=* \ + | --program-transform-n=* | --program-transform-=* \ + | --program-transform=* | --program-transfor=* \ + | --program-transfo=* | --program-transf=* \ + | --program-trans=* | --program-tran=* \ + | --progr-tra=* | --program-tr=* | --program-t=*) + program_transform_name=$ac_optarg ;; + + -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd) + ac_prev=pdfdir ;; + -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*) + pdfdir=$ac_optarg ;; + + -psdir | --psdir | --psdi | --psd | --ps) + ac_prev=psdir ;; + -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*) + psdir=$ac_optarg ;; + + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil) + silent=yes ;; + + -runstatedir | --runstatedir | --runstatedi | --runstated \ + | --runstate | --runstat | --runsta | --runst | --runs \ + | --run | --ru | --r) + ac_prev=runstatedir ;; + -runstatedir=* | --runstatedir=* | --runstatedi=* | --runstated=* \ + | --runstate=* | --runstat=* | --runsta=* | --runst=* | --runs=* \ + | --run=* | --ru=* | --r=*) + runstatedir=$ac_optarg ;; + + -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) + ac_prev=sbindir ;; + -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ + | --sbi=* | --sb=*) + sbindir=$ac_optarg ;; + + -sharedstatedir | --sharedstatedir | --sharedstatedi \ + | --sharedstated | --sharedstate | --sharedstat | --sharedsta \ + | --sharedst | --shareds | --shared | --share | --shar \ + | --sha | --sh) + ac_prev=sharedstatedir ;; + -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \ + | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \ + | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \ + | --sha=* | --sh=*) + sharedstatedir=$ac_optarg ;; + + -site | --site | --sit) + ac_prev=site ;; + -site=* | --site=* | --sit=*) + site=$ac_optarg ;; + + -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) + ac_prev=srcdir ;; + -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) + srcdir=$ac_optarg ;; + + -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \ + | --syscon | --sysco | --sysc | --sys | --sy) + ac_prev=sysconfdir ;; + -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \ + | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*) + sysconfdir=$ac_optarg ;; + + -target | --target | --targe | --targ | --tar | --ta | --t) + ac_prev=target_alias ;; + -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) + target_alias=$ac_optarg ;; + + -v | -verbose | --verbose | --verbos | --verbo | --verb) + verbose=yes ;; + + -version | --version | --versio | --versi | --vers | -V) + ac_init_version=: ;; + + -with-* | --with-*) + ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && + as_fn_error $? "invalid package name: $ac_useropt" + ac_useropt_orig=$ac_useropt + ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` + case $ac_user_opts in + *" +"with_$ac_useropt" +"*) ;; + *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--with-$ac_useropt_orig" + ac_unrecognized_sep=', ';; + esac + eval with_$ac_useropt=\$ac_optarg ;; + + -without-* | --without-*) + ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && + as_fn_error $? "invalid package name: $ac_useropt" + ac_useropt_orig=$ac_useropt + ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` + case $ac_user_opts in + *" +"with_$ac_useropt" +"*) ;; + *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--without-$ac_useropt_orig" + ac_unrecognized_sep=', ';; + esac + eval with_$ac_useropt=no ;; + + --x) + # Obsolete; use --with-x. + with_x=yes ;; + + -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \ + | --x-incl | --x-inc | --x-in | --x-i) + ac_prev=x_includes ;; + -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \ + | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*) + x_includes=$ac_optarg ;; + + -x-libraries | --x-libraries | --x-librarie | --x-librari \ + | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l) + ac_prev=x_libraries ;; + -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \ + | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) + x_libraries=$ac_optarg ;; + + -*) as_fn_error $? "unrecognized option: \`$ac_option' +Try \`$0 --help' for more information" + ;; + + *=*) + ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='` + # Reject names that are not valid shell variable names. + case $ac_envvar in #( + '' | [0-9]* | *[!_$as_cr_alnum]* ) + as_fn_error $? "invalid variable name: \`$ac_envvar'" ;; + esac + eval $ac_envvar=\$ac_optarg + export $ac_envvar ;; + + *) + # FIXME: should be removed in autoconf 3.0. + $as_echo "$as_me: WARNING: you should use --build, --host, --target" >&2 + expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null && + $as_echo "$as_me: WARNING: invalid host type: $ac_option" >&2 + : "${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}" + ;; + + esac +done + +if test -n "$ac_prev"; then + ac_option=--`echo $ac_prev | sed 's/_/-/g'` + as_fn_error $? "missing argument to $ac_option" +fi + +if test -n "$ac_unrecognized_opts"; then + case $enable_option_checking in + no) ;; + fatal) as_fn_error $? "unrecognized options: $ac_unrecognized_opts" ;; + *) $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;; + esac +fi + +# Check all directory arguments for consistency. +for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \ + datadir sysconfdir sharedstatedir localstatedir includedir \ + oldincludedir docdir infodir htmldir dvidir pdfdir psdir \ + libdir localedir mandir runstatedir +do + eval ac_val=\$$ac_var + # Remove trailing slashes. + case $ac_val in + */ ) + ac_val=`expr "X$ac_val" : 'X\(.*[^/]\)' \| "X$ac_val" : 'X\(.*\)'` + eval $ac_var=\$ac_val;; + esac + # Be sure to have absolute directory names. + case $ac_val in + [\\/$]* | ?:[\\/]* ) continue;; + NONE | '' ) case $ac_var in *prefix ) continue;; esac;; + esac + as_fn_error $? "expected an absolute directory name for --$ac_var: $ac_val" +done + +# There might be people who depend on the old broken behavior: `$host' +# used to hold the argument of --host etc. +# FIXME: To remove some day. +build=$build_alias +host=$host_alias +target=$target_alias + +# FIXME: To remove some day. +if test "x$host_alias" != x; then + if test "x$build_alias" = x; then + cross_compiling=maybe + elif test "x$build_alias" != "x$host_alias"; then + cross_compiling=yes + fi +fi + +ac_tool_prefix= +test -n "$host_alias" && ac_tool_prefix=$host_alias- + +test "$silent" = yes && exec 6>/dev/null + + +ac_pwd=`pwd` && test -n "$ac_pwd" && +ac_ls_di=`ls -di .` && +ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` || + as_fn_error $? "working directory cannot be determined" +test "X$ac_ls_di" = "X$ac_pwd_ls_di" || + as_fn_error $? "pwd does not report name of working directory" + + +# Find the source files, if location was not specified. +if test -z "$srcdir"; then + ac_srcdir_defaulted=yes + # Try the directory containing this script, then the parent directory. + ac_confdir=`$as_dirname -- "$as_myself" || +$as_expr X"$as_myself" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$as_myself" : 'X\(//\)[^/]' \| \ + X"$as_myself" : 'X\(//\)$' \| \ + X"$as_myself" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$as_myself" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + srcdir=$ac_confdir + if test ! -r "$srcdir/$ac_unique_file"; then + srcdir=.. + fi +else + ac_srcdir_defaulted=no +fi +if test ! -r "$srcdir/$ac_unique_file"; then + test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .." + as_fn_error $? "cannot find sources ($ac_unique_file) in $srcdir" +fi +ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work" +ac_abs_confdir=`( + cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error $? "$ac_msg" + pwd)` +# When building in place, set srcdir=. +if test "$ac_abs_confdir" = "$ac_pwd"; then + srcdir=. +fi +# Remove unnecessary trailing slashes from srcdir. +# Double slashes in file names in object file debugging info +# mess up M-x gdb in Emacs. +case $srcdir in +*/) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;; +esac +for ac_var in $ac_precious_vars; do + eval ac_env_${ac_var}_set=\${${ac_var}+set} + eval ac_env_${ac_var}_value=\$${ac_var} + eval ac_cv_env_${ac_var}_set=\${${ac_var}+set} + eval ac_cv_env_${ac_var}_value=\$${ac_var} +done + +# +# Report the --help message. +# +if test "$ac_init_help" = "long"; then + # Omit some internal or obsolete options to make the list less imposing. + # This message is too long to be a string in the A/UX 3.1 sh. + cat <<_ACEOF +\`configure' configures this package to adapt to many kinds of systems. + +Usage: $0 [OPTION]... [VAR=VALUE]... + +To assign environment variables (e.g., CC, CFLAGS...), specify them as +VAR=VALUE. See below for descriptions of some of the useful variables. + +Defaults for the options are specified in brackets. + +Configuration: + -h, --help display this help and exit + --help=short display options specific to this package + --help=recursive display the short help of all the included packages + -V, --version display version information and exit + -q, --quiet, --silent do not print \`checking ...' messages + --cache-file=FILE cache test results in FILE [disabled] + -C, --config-cache alias for \`--cache-file=config.cache' + -n, --no-create do not create output files + --srcdir=DIR find the sources in DIR [configure dir or \`..'] + +Installation directories: + --prefix=PREFIX install architecture-independent files in PREFIX + [$ac_default_prefix] + --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX + [PREFIX] + +By default, \`make install' will install all the files in +\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify +an installation prefix other than \`$ac_default_prefix' using \`--prefix', +for instance \`--prefix=\$HOME'. + +For better control, use the options below. + +Fine tuning of the installation directories: + --bindir=DIR user executables [EPREFIX/bin] + --sbindir=DIR system admin executables [EPREFIX/sbin] + --libexecdir=DIR program executables [EPREFIX/libexec] + --sysconfdir=DIR read-only single-machine data [PREFIX/etc] + --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] + --localstatedir=DIR modifiable single-machine data [PREFIX/var] + --runstatedir=DIR modifiable per-process data [LOCALSTATEDIR/run] + --libdir=DIR object code libraries [EPREFIX/lib] + --includedir=DIR C header files [PREFIX/include] + --oldincludedir=DIR C header files for non-gcc [/usr/include] + --datarootdir=DIR read-only arch.-independent data root [PREFIX/share] + --datadir=DIR read-only architecture-independent data [DATAROOTDIR] + --infodir=DIR info documentation [DATAROOTDIR/info] + --localedir=DIR locale-dependent data [DATAROOTDIR/locale] + --mandir=DIR man documentation [DATAROOTDIR/man] + --docdir=DIR documentation root [DATAROOTDIR/doc/PACKAGE] + --htmldir=DIR html documentation [DOCDIR] + --dvidir=DIR dvi documentation [DOCDIR] + --pdfdir=DIR pdf documentation [DOCDIR] + --psdir=DIR ps documentation [DOCDIR] +_ACEOF + + cat <<\_ACEOF + +System types: + --build=BUILD configure for building on BUILD [guessed] + --host=HOST cross-compile to build programs to run on HOST [BUILD] +_ACEOF +fi + +if test -n "$ac_init_help"; then + + cat <<\_ACEOF + +Optional Packages: + --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] + --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) + --with-localdirs Explicitly ask compiler to use /usr/local/{include,libs} if they exist + --with-libpcap=DIR Look for pcap headers in DIR/include. + --with-libpcap=included Always use version included with Nmap + --without-libpcap Disable pcap functions. + --with-openssl=DIR Use optional openssl libs and includes from + [DIR]/lib/ and [DIR]/include/openssl/) + --with-libnbase=DIR Look for nbase include/libs in DIR + +Some influential environment variables: + CC C compiler command + CFLAGS C compiler flags + LDFLAGS linker flags, e.g. -L<lib dir> if you have libraries in a + nonstandard directory <lib dir> + LIBS libraries to pass to the linker, e.g. -l<library> + CPPFLAGS (Objective) C/C++ preprocessor flags, e.g. -I<include dir> if + you have headers in a nonstandard directory <include dir> + CPP C preprocessor + +Use these variables to override the choices made by `configure' or to help +it to find libraries and programs with nonstandard names/locations. + +Report bugs to the package provider. +_ACEOF +ac_status=$? +fi + +if test "$ac_init_help" = "recursive"; then + # If there are subdirs, report their specific --help. + for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue + test -d "$ac_dir" || + { cd "$srcdir" && ac_pwd=`pwd` && srcdir=. && test -d "$ac_dir"; } || + continue + ac_builddir=. + +case "$ac_dir" in +.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; +*) + ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` + # A ".." for each directory in $ac_dir_suffix. + ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` + case $ac_top_builddir_sub in + "") ac_top_builddir_sub=. ac_top_build_prefix= ;; + *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; + esac ;; +esac +ac_abs_top_builddir=$ac_pwd +ac_abs_builddir=$ac_pwd$ac_dir_suffix +# for backward compatibility: +ac_top_builddir=$ac_top_build_prefix + +case $srcdir in + .) # We are building in place. + ac_srcdir=. + ac_top_srcdir=$ac_top_builddir_sub + ac_abs_top_srcdir=$ac_pwd ;; + [\\/]* | ?:[\\/]* ) # Absolute name. + ac_srcdir=$srcdir$ac_dir_suffix; + ac_top_srcdir=$srcdir + ac_abs_top_srcdir=$srcdir ;; + *) # Relative name. + ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix + ac_top_srcdir=$ac_top_build_prefix$srcdir + ac_abs_top_srcdir=$ac_pwd/$srcdir ;; +esac +ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix + + cd "$ac_dir" || { ac_status=$?; continue; } + # Check for guested configure. + if test -f "$ac_srcdir/configure.gnu"; then + echo && + $SHELL "$ac_srcdir/configure.gnu" --help=recursive + elif test -f "$ac_srcdir/configure"; then + echo && + $SHELL "$ac_srcdir/configure" --help=recursive + else + $as_echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2 + fi || ac_status=$? + cd "$ac_pwd" || { ac_status=$?; break; } + done +fi + +test -n "$ac_init_help" && exit $ac_status +if $ac_init_version; then + cat <<\_ACEOF +configure +generated by GNU Autoconf 2.69 + +Copyright (C) 2012 Free Software Foundation, Inc. +This configure script is free software; the Free Software Foundation +gives unlimited permission to copy, distribute and modify it. +_ACEOF + exit +fi + +## ------------------------ ## +## Autoconf initialization. ## +## ------------------------ ## + +# ac_fn_c_try_compile LINENO +# -------------------------- +# Try to compile conftest.$ac_ext, and return whether this succeeded. +ac_fn_c_try_compile () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + rm -f conftest.$ac_objext + if { { ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_compile") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + grep -v '^ *+' conftest.err >conftest.er1 + cat conftest.er1 >&5 + mv -f conftest.er1 conftest.err + fi + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then : + ac_retval=0 +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_retval=1 +fi + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + as_fn_set_status $ac_retval + +} # ac_fn_c_try_compile + +# ac_fn_c_try_cpp LINENO +# ---------------------- +# Try to preprocess conftest.$ac_ext, and return whether this succeeded. +ac_fn_c_try_cpp () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + if { { ac_try="$ac_cpp conftest.$ac_ext" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_cpp conftest.$ac_ext") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + grep -v '^ *+' conftest.err >conftest.er1 + cat conftest.er1 >&5 + mv -f conftest.er1 conftest.err + fi + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } > conftest.i && { + test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || + test ! -s conftest.err + }; then : + ac_retval=0 +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_retval=1 +fi + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + as_fn_set_status $ac_retval + +} # ac_fn_c_try_cpp + +# ac_fn_c_check_header_mongrel LINENO HEADER VAR INCLUDES +# ------------------------------------------------------- +# Tests whether HEADER exists, giving a warning if it cannot be compiled using +# the include files in INCLUDES and setting the cache variable VAR +# accordingly. +ac_fn_c_check_header_mongrel () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + if eval \${$3+:} false; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 +$as_echo_n "checking for $2... " >&6; } +if eval \${$3+:} false; then : + $as_echo_n "(cached) " >&6 +fi +eval ac_res=\$$3 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } +else + # Is the header compilable? +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 usability" >&5 +$as_echo_n "checking $2 usability... " >&6; } +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$4 +#include <$2> +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_header_compiler=yes +else + ac_header_compiler=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_compiler" >&5 +$as_echo "$ac_header_compiler" >&6; } + +# Is the header present? +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 presence" >&5 +$as_echo_n "checking $2 presence... " >&6; } +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include <$2> +_ACEOF +if ac_fn_c_try_cpp "$LINENO"; then : + ac_header_preproc=yes +else + ac_header_preproc=no +fi +rm -f conftest.err conftest.i conftest.$ac_ext +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_preproc" >&5 +$as_echo "$ac_header_preproc" >&6; } + +# So? What about this header? +case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in #(( + yes:no: ) + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&5 +$as_echo "$as_me: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5 +$as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;} + ;; + no:yes:* ) + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: present but cannot be compiled" >&5 +$as_echo "$as_me: WARNING: $2: present but cannot be compiled" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: check for missing prerequisite headers?" >&5 +$as_echo "$as_me: WARNING: $2: check for missing prerequisite headers?" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: see the Autoconf documentation" >&5 +$as_echo "$as_me: WARNING: $2: see the Autoconf documentation" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&5 +$as_echo "$as_me: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5 +$as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;} + ;; +esac + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 +$as_echo_n "checking for $2... " >&6; } +if eval \${$3+:} false; then : + $as_echo_n "(cached) " >&6 +else + eval "$3=\$ac_header_compiler" +fi +eval ac_res=\$$3 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } +fi + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + +} # ac_fn_c_check_header_mongrel + +# ac_fn_c_try_run LINENO +# ---------------------- +# Try to link conftest.$ac_ext, and return whether this succeeded. Assumes +# that executables *can* be run. +ac_fn_c_try_run () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + if { { ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_link") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && { ac_try='./conftest$ac_exeext' + { { case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; }; then : + ac_retval=0 +else + $as_echo "$as_me: program exited with status $ac_status" >&5 + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_retval=$ac_status +fi + rm -rf conftest.dSYM conftest_ipa8_conftest.oo + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + as_fn_set_status $ac_retval + +} # ac_fn_c_try_run + +# ac_fn_c_check_header_compile LINENO HEADER VAR INCLUDES +# ------------------------------------------------------- +# Tests whether HEADER exists and can be compiled using the include files in +# INCLUDES, setting the cache variable VAR accordingly. +ac_fn_c_check_header_compile () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 +$as_echo_n "checking for $2... " >&6; } +if eval \${$3+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$4 +#include <$2> +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + eval "$3=yes" +else + eval "$3=no" +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +eval ac_res=\$$3 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + +} # ac_fn_c_check_header_compile + +# ac_fn_c_try_link LINENO +# ----------------------- +# Try to link conftest.$ac_ext, and return whether this succeeded. +ac_fn_c_try_link () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + rm -f conftest.$ac_objext conftest$ac_exeext + if { { ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_link") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + grep -v '^ *+' conftest.err >conftest.er1 + cat conftest.er1 >&5 + mv -f conftest.er1 conftest.err + fi + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && { + test "$cross_compiling" = yes || + test -x conftest$ac_exeext + }; then : + ac_retval=0 +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_retval=1 +fi + # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information + # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would + # interfere with the next link command; also delete a directory that is + # left behind by Apple's compiler. We do this before executing the actions. + rm -rf conftest.dSYM conftest_ipa8_conftest.oo + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + as_fn_set_status $ac_retval + +} # ac_fn_c_try_link + +# ac_fn_c_check_func LINENO FUNC VAR +# ---------------------------------- +# Tests whether FUNC exists, setting the cache variable VAR accordingly +ac_fn_c_check_func () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 +$as_echo_n "checking for $2... " >&6; } +if eval \${$3+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +/* Define $2 to an innocuous variant, in case <limits.h> declares $2. + For example, HP-UX 11i <limits.h> declares gettimeofday. */ +#define $2 innocuous_$2 + +/* System header to define __stub macros and hopefully few prototypes, + which can conflict with char $2 (); below. + Prefer <limits.h> to <assert.h> if __STDC__ is defined, since + <limits.h> exists even on freestanding compilers. */ + +#ifdef __STDC__ +# include <limits.h> +#else +# include <assert.h> +#endif + +#undef $2 + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char $2 (); +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined __stub_$2 || defined __stub___$2 +choke me +#endif + +int +main () +{ +return $2 (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + eval "$3=yes" +else + eval "$3=no" +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi +eval ac_res=\$$3 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + +} # ac_fn_c_check_func +cat >config.log <<_ACEOF +This file contains any messages produced by compilers while +running configure, to aid debugging if configure makes a mistake. + +It was created by $as_me, which was +generated by GNU Autoconf 2.69. Invocation command line was + + $ $0 $@ + +_ACEOF +exec 5>>config.log +{ +cat <<_ASUNAME +## --------- ## +## Platform. ## +## --------- ## + +hostname = `(hostname || uname -n) 2>/dev/null | sed 1q` +uname -m = `(uname -m) 2>/dev/null || echo unknown` +uname -r = `(uname -r) 2>/dev/null || echo unknown` +uname -s = `(uname -s) 2>/dev/null || echo unknown` +uname -v = `(uname -v) 2>/dev/null || echo unknown` + +/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown` +/bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown` + +/bin/arch = `(/bin/arch) 2>/dev/null || echo unknown` +/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown` +/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown` +/usr/bin/hostinfo = `(/usr/bin/hostinfo) 2>/dev/null || echo unknown` +/bin/machine = `(/bin/machine) 2>/dev/null || echo unknown` +/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown` +/bin/universe = `(/bin/universe) 2>/dev/null || echo unknown` + +_ASUNAME + +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + $as_echo "PATH: $as_dir" + done +IFS=$as_save_IFS + +} >&5 + +cat >&5 <<_ACEOF + + +## ----------- ## +## Core tests. ## +## ----------- ## + +_ACEOF + + +# Keep a trace of the command line. +# Strip out --no-create and --no-recursion so they do not pile up. +# Strip out --silent because we don't want to record it for future runs. +# Also quote any args containing shell meta-characters. +# Make two passes to allow for proper duplicate-argument suppression. +ac_configure_args= +ac_configure_args0= +ac_configure_args1= +ac_must_keep_next=false +for ac_pass in 1 2 +do + for ac_arg + do + case $ac_arg in + -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;; + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil) + continue ;; + *\'*) + ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; + esac + case $ac_pass in + 1) as_fn_append ac_configure_args0 " '$ac_arg'" ;; + 2) + as_fn_append ac_configure_args1 " '$ac_arg'" + if test $ac_must_keep_next = true; then + ac_must_keep_next=false # Got value, back to normal. + else + case $ac_arg in + *=* | --config-cache | -C | -disable-* | --disable-* \ + | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \ + | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \ + | -with-* | --with-* | -without-* | --without-* | --x) + case "$ac_configure_args0 " in + "$ac_configure_args1"*" '$ac_arg' "* ) continue ;; + esac + ;; + -* ) ac_must_keep_next=true ;; + esac + fi + as_fn_append ac_configure_args " '$ac_arg'" + ;; + esac + done +done +{ ac_configure_args0=; unset ac_configure_args0;} +{ ac_configure_args1=; unset ac_configure_args1;} + +# When interrupted or exit'd, cleanup temporary files, and complete +# config.log. We remove comments because anyway the quotes in there +# would cause problems or look ugly. +# WARNING: Use '\'' to represent an apostrophe within the trap. +# WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug. +trap 'exit_status=$? + # Save into config.log some information that might help in debugging. + { + echo + + $as_echo "## ---------------- ## +## Cache variables. ## +## ---------------- ##" + echo + # The following way of writing the cache mishandles newlines in values, +( + for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do + eval ac_val=\$$ac_var + case $ac_val in #( + *${as_nl}*) + case $ac_var in #( + *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 +$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; + esac + case $ac_var in #( + _ | IFS | as_nl) ;; #( + BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( + *) { eval $ac_var=; unset $ac_var;} ;; + esac ;; + esac + done + (set) 2>&1 | + case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #( + *${as_nl}ac_space=\ *) + sed -n \ + "s/'\''/'\''\\\\'\'''\''/g; + s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p" + ;; #( + *) + sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" + ;; + esac | + sort +) + echo + + $as_echo "## ----------------- ## +## Output variables. ## +## ----------------- ##" + echo + for ac_var in $ac_subst_vars + do + eval ac_val=\$$ac_var + case $ac_val in + *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; + esac + $as_echo "$ac_var='\''$ac_val'\''" + done | sort + echo + + if test -n "$ac_subst_files"; then + $as_echo "## ------------------- ## +## File substitutions. ## +## ------------------- ##" + echo + for ac_var in $ac_subst_files + do + eval ac_val=\$$ac_var + case $ac_val in + *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; + esac + $as_echo "$ac_var='\''$ac_val'\''" + done | sort + echo + fi + + if test -s confdefs.h; then + $as_echo "## ----------- ## +## confdefs.h. ## +## ----------- ##" + echo + cat confdefs.h + echo + fi + test "$ac_signal" != 0 && + $as_echo "$as_me: caught signal $ac_signal" + $as_echo "$as_me: exit $exit_status" + } >&5 + rm -f core *.core core.conftest.* && + rm -f -r conftest* confdefs* conf$$* $ac_clean_files && + exit $exit_status +' 0 +for ac_signal in 1 2 13 15; do + trap 'ac_signal='$ac_signal'; as_fn_exit 1' $ac_signal +done +ac_signal=0 + +# confdefs.h avoids OS command line length limits that DEFS can exceed. +rm -f -r conftest* confdefs.h + +$as_echo "/* confdefs.h */" > confdefs.h + +# Predefined preprocessor variables. + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_NAME "$PACKAGE_NAME" +_ACEOF + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_TARNAME "$PACKAGE_TARNAME" +_ACEOF + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_VERSION "$PACKAGE_VERSION" +_ACEOF + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_STRING "$PACKAGE_STRING" +_ACEOF + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT" +_ACEOF + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_URL "$PACKAGE_URL" +_ACEOF + + +# Let the site file select an alternate cache file if it wants to. +# Prefer an explicitly selected file to automatically selected ones. +ac_site_file1=NONE +ac_site_file2=NONE +if test -n "$CONFIG_SITE"; then + # We do not want a PATH search for config.site. + case $CONFIG_SITE in #(( + -*) ac_site_file1=./$CONFIG_SITE;; + */*) ac_site_file1=$CONFIG_SITE;; + *) ac_site_file1=./$CONFIG_SITE;; + esac +elif test "x$prefix" != xNONE; then + ac_site_file1=$prefix/share/config.site + ac_site_file2=$prefix/etc/config.site +else + ac_site_file1=$ac_default_prefix/share/config.site + ac_site_file2=$ac_default_prefix/etc/config.site +fi +for ac_site_file in "$ac_site_file1" "$ac_site_file2" +do + test "x$ac_site_file" = xNONE && continue + if test /dev/null != "$ac_site_file" && test -r "$ac_site_file"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5 +$as_echo "$as_me: loading site script $ac_site_file" >&6;} + sed 's/^/| /' "$ac_site_file" >&5 + . "$ac_site_file" \ + || { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "failed to load site script $ac_site_file +See \`config.log' for more details" "$LINENO" 5; } + fi +done + +if test -r "$cache_file"; then + # Some versions of bash will fail to source /dev/null (special files + # actually), so we avoid doing that. DJGPP emulates it as a regular file. + if test /dev/null != "$cache_file" && test -f "$cache_file"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5 +$as_echo "$as_me: loading cache $cache_file" >&6;} + case $cache_file in + [\\/]* | ?:[\\/]* ) . "$cache_file";; + *) . "./$cache_file";; + esac + fi +else + { $as_echo "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5 +$as_echo "$as_me: creating cache $cache_file" >&6;} + >$cache_file +fi + +# Check that the precious variables saved in the cache have kept the same +# value. +ac_cache_corrupted=false +for ac_var in $ac_precious_vars; do + eval ac_old_set=\$ac_cv_env_${ac_var}_set + eval ac_new_set=\$ac_env_${ac_var}_set + eval ac_old_val=\$ac_cv_env_${ac_var}_value + eval ac_new_val=\$ac_env_${ac_var}_value + case $ac_old_set,$ac_new_set in + set,) + { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5 +$as_echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;} + ac_cache_corrupted=: ;; + ,set) + { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5 +$as_echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;} + ac_cache_corrupted=: ;; + ,);; + *) + if test "x$ac_old_val" != "x$ac_new_val"; then + # differences in whitespace do not lead to failure. + ac_old_val_w=`echo x $ac_old_val` + ac_new_val_w=`echo x $ac_new_val` + if test "$ac_old_val_w" != "$ac_new_val_w"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5 +$as_echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;} + ac_cache_corrupted=: + else + { $as_echo "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5 +$as_echo "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;} + eval $ac_var=\$ac_old_val + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: former value: \`$ac_old_val'" >&5 +$as_echo "$as_me: former value: \`$ac_old_val'" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: current value: \`$ac_new_val'" >&5 +$as_echo "$as_me: current value: \`$ac_new_val'" >&2;} + fi;; + esac + # Pass precious variables to config.status. + if test "$ac_new_set" = set; then + case $ac_new_val in + *\'*) ac_arg=$ac_var=`$as_echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;; + *) ac_arg=$ac_var=$ac_new_val ;; + esac + case " $ac_configure_args " in + *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy. + *) as_fn_append ac_configure_args " '$ac_arg'" ;; + esac + fi +done +if $ac_cache_corrupted; then + { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5 +$as_echo "$as_me: error: changes in the environment can compromise the build" >&2;} + as_fn_error $? "run \`make distclean' and/or \`rm $cache_file' and start over" "$LINENO" 5 +fi +## -------------------- ## +## Main body of script. ## +## -------------------- ## + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + + +if test "${top_nmap_srcdir+set}" != set; then + top_nmap_srcdir=../.. + export top_nmap_srcdir +fi + +ac_config_files="$ac_config_files Makefile ../tests/Makefile" + + +ac_config_headers="$ac_config_headers ../include/nsock_config.h" + + +ac_aux_dir= +for ac_dir in "$srcdir" "$srcdir/.." "$srcdir/../.."; do + if test -f "$ac_dir/install-sh"; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/install-sh -c" + break + elif test -f "$ac_dir/install.sh"; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/install.sh -c" + break + elif test -f "$ac_dir/shtool"; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/shtool install -c" + break + fi +done +if test -z "$ac_aux_dir"; then + as_fn_error $? "cannot find install-sh, install.sh, or shtool in \"$srcdir\" \"$srcdir/..\" \"$srcdir/../..\"" "$LINENO" 5 +fi + +# These three variables are undocumented and unsupported, +# and are intended to be withdrawn in a future Autoconf release. +# They can cause serious problems if a builder's source tree is in a directory +# whose full name contains unusual characters. +ac_config_guess="$SHELL $ac_aux_dir/config.guess" # Please don't use this var. +ac_config_sub="$SHELL $ac_aux_dir/config.sub" # Please don't use this var. +ac_configure="$SHELL $ac_aux_dir/configure" # Please don't use this var. + + +# Make sure we can run config.sub. +$SHELL "$ac_aux_dir/config.sub" sun4 >/dev/null 2>&1 || + as_fn_error $? "cannot run $SHELL $ac_aux_dir/config.sub" "$LINENO" 5 + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking build system type" >&5 +$as_echo_n "checking build system type... " >&6; } +if ${ac_cv_build+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_build_alias=$build_alias +test "x$ac_build_alias" = x && + ac_build_alias=`$SHELL "$ac_aux_dir/config.guess"` +test "x$ac_build_alias" = x && + as_fn_error $? "cannot guess build type; you must specify one" "$LINENO" 5 +ac_cv_build=`$SHELL "$ac_aux_dir/config.sub" $ac_build_alias` || + as_fn_error $? "$SHELL $ac_aux_dir/config.sub $ac_build_alias failed" "$LINENO" 5 + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_build" >&5 +$as_echo "$ac_cv_build" >&6; } +case $ac_cv_build in +*-*-*) ;; +*) as_fn_error $? "invalid value of canonical build" "$LINENO" 5;; +esac +build=$ac_cv_build +ac_save_IFS=$IFS; IFS='-' +set x $ac_cv_build +shift +build_cpu=$1 +build_vendor=$2 +shift; shift +# Remember, the first character of IFS is used to create $*, +# except with old shells: +build_os=$* +IFS=$ac_save_IFS +case $build_os in *\ *) build_os=`echo "$build_os" | sed 's/ /-/g'`;; esac + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking host system type" >&5 +$as_echo_n "checking host system type... " >&6; } +if ${ac_cv_host+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test "x$host_alias" = x; then + ac_cv_host=$ac_cv_build +else + ac_cv_host=`$SHELL "$ac_aux_dir/config.sub" $host_alias` || + as_fn_error $? "$SHELL $ac_aux_dir/config.sub $host_alias failed" "$LINENO" 5 +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_host" >&5 +$as_echo "$ac_cv_host" >&6; } +case $ac_cv_host in +*-*-*) ;; +*) as_fn_error $? "invalid value of canonical host" "$LINENO" 5;; +esac +host=$ac_cv_host +ac_save_IFS=$IFS; IFS='-' +set x $ac_cv_host +shift +host_cpu=$1 +host_vendor=$2 +shift; shift +# Remember, the first character of IFS is used to create $*, +# except with old shells: +host_os=$* +IFS=$ac_save_IFS +case $host_os in *\ *) host_os=`echo "$host_os" | sed 's/ /-/g'`;; esac + + + + + + +case "$host" in + *alpha-dec-osf*) + +$as_echo "#define DEC 1" >>confdefs.h + + ;; + *-netbsd* | *-knetbsd*-gnu) + +$as_echo "#define NETBSD 1" >>confdefs.h + + ;; + *-openbsd*) + +$as_echo "#define OPENBSD 1" >>confdefs.h + + ;; + *-sgi-irix5*) + $as_echo "#define IRIX 1" >>confdefs.h + + ;; + *-sgi-irix6*) + $as_echo "#define IRIX 1" >>confdefs.h + + ;; + *-hpux*) + +$as_echo "#define HPUX 1" >>confdefs.h + + ;; + *-solaris2.1[1-9]*) + $as_echo "#define SOLARIS 1" >>confdefs.h + + # Solaris 11 and later use BPF packet capture rather than DLPI. + +$as_echo "#define SOLARIS_BPF_PCAP_CAPTURE 1" >>confdefs.h + + ;; + *-solaris2.0*) + $as_echo "#define SOLARIS 1" >>confdefs.h + + ;; + *-solaris2.[1-9][0-9]*) + $as_echo "#define SOLARIS 1" >>confdefs.h + + ;; + *-solaris2.1*) + $as_echo "#define SOLARIS 1" >>confdefs.h + + ;; + *-solaris2.2*) + $as_echo "#define SOLARIS 1" >>confdefs.h + + ;; + *-solaris2.3*) + $as_echo "#define SOLARIS 1" >>confdefs.h + + ;; + *-solaris2.4*) + $as_echo "#define SOLARIS 1" >>confdefs.h + + ;; + *-solaris2.5.1) + $as_echo "#define SOLARIS 1" >>confdefs.h + + ;; + *-solaris*) + $as_echo "#define SOLARIS 1" >>confdefs.h + + ;; + *-sunos4*) + +$as_echo "#define SUNOS 1" >>confdefs.h + + ;; + *-linux*) + +$as_echo "#define LINUX 1" >>confdefs.h + + ;; + *-freebsd* | *-kfreebsd*-gnu | *-dragonfly*) + +$as_echo "#define FREEBSD 1" >>confdefs.h + + ;; + *-bsdi*) + +$as_echo "#define BSDI 1" >>confdefs.h + + ;; + *-apple-darwin*) + +$as_echo "#define MACOSX 1" >>confdefs.h + + ;; +esac + + + +# Check whether --with-localdirs was given. +if test "${with_localdirs+set}" = set; then : + withval=$with_localdirs; case "$with_localdirs" in + yes) + user_localdirs=1 + ;; + no) + user_localdirs=0 + ;; + esac + +else + user_localdirs=0 +fi + + +if test "$user_localdirs" = 1; then + if test -d /usr/local/lib; then + LDFLAGS="$LDFLAGS -L/usr/local/lib" + fi + if test -d /usr/local/include; then + CPPFLAGS="$CPPFLAGS -I/usr/local/include" + fi +fi + +have_libpcap=no + +# By default, search for pcap library +test "${with_libpcap+set}" != "set" && with_libpcap=yes + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args. +set dummy ${ac_tool_prefix}gcc; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_CC+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_CC="${ac_tool_prefix}gcc" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +$as_echo "$CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_CC"; then + ac_ct_CC=$CC + # Extract the first word of "gcc", so it can be a program name with args. +set dummy gcc; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_CC+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_CC"; then + ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_CC="gcc" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_CC=$ac_cv_prog_ac_ct_CC +if test -n "$ac_ct_CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 +$as_echo "$ac_ct_CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_CC" = x; then + CC="" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + CC=$ac_ct_CC + fi +else + CC="$ac_cv_prog_CC" +fi + +if test -z "$CC"; then + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args. +set dummy ${ac_tool_prefix}cc; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_CC+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_CC="${ac_tool_prefix}cc" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +$as_echo "$CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + fi +fi +if test -z "$CC"; then + # Extract the first word of "cc", so it can be a program name with args. +set dummy cc; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_CC+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else + ac_prog_rejected=no +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then + ac_prog_rejected=yes + continue + fi + ac_cv_prog_CC="cc" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +if test $ac_prog_rejected = yes; then + # We found a bogon in the path, so make sure we never use it. + set dummy $ac_cv_prog_CC + shift + if test $# != 0; then + # We chose a different compiler from the bogus one. + # However, it has the same basename, so the bogon will be chosen + # first if we set CC to just the basename; use the full file name. + shift + ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@" + fi +fi +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +$as_echo "$CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$CC"; then + if test -n "$ac_tool_prefix"; then + for ac_prog in cl.exe + do + # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. +set dummy $ac_tool_prefix$ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_CC+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_CC="$ac_tool_prefix$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +$as_echo "$CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$CC" && break + done +fi +if test -z "$CC"; then + ac_ct_CC=$CC + for ac_prog in cl.exe +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_CC+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_CC"; then + ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_CC="$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_CC=$ac_cv_prog_ac_ct_CC +if test -n "$ac_ct_CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 +$as_echo "$ac_ct_CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$ac_ct_CC" && break +done + + if test "x$ac_ct_CC" = x; then + CC="" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + CC=$ac_ct_CC + fi +fi + +fi + + +test -z "$CC" && { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "no acceptable C compiler found in \$PATH +See \`config.log' for more details" "$LINENO" 5; } + +# Provide some information about the compiler. +$as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5 +set X $ac_compile +ac_compiler=$2 +for ac_option in --version -v -V -qversion; do + { { ac_try="$ac_compiler $ac_option >&5" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_compiler $ac_option >&5") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + sed '10a\ +... rest of stderr output deleted ... + 10q' conftest.err >conftest.er1 + cat conftest.er1 >&5 + fi + rm -f conftest.er1 conftest.err + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } +done + +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +ac_clean_files_save=$ac_clean_files +ac_clean_files="$ac_clean_files a.out a.out.dSYM a.exe b.out" +# Try to create an executable without -o first, disregard a.out. +# It will help us diagnose broken compilers, and finding out an intuition +# of exeext. +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler works" >&5 +$as_echo_n "checking whether the C compiler works... " >&6; } +ac_link_default=`$as_echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'` + +# The possible output files: +ac_files="a.out conftest.exe conftest a.exe a_out.exe b.out conftest.*" + +ac_rmfiles= +for ac_file in $ac_files +do + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; + * ) ac_rmfiles="$ac_rmfiles $ac_file";; + esac +done +rm -f $ac_rmfiles + +if { { ac_try="$ac_link_default" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_link_default") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then : + # Autoconf-2.13 could set the ac_cv_exeext variable to `no'. +# So ignore a value of `no', otherwise this would lead to `EXEEXT = no' +# in a Makefile. We should not override ac_cv_exeext if it was cached, +# so that the user can short-circuit this test for compilers unknown to +# Autoconf. +for ac_file in $ac_files '' +do + test -f "$ac_file" || continue + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) + ;; + [ab].out ) + # We found the default executable, but exeext='' is most + # certainly right. + break;; + *.* ) + if test "${ac_cv_exeext+set}" = set && test "$ac_cv_exeext" != no; + then :; else + ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` + fi + # We set ac_cv_exeext here because the later test for it is not + # safe: cross compilers may not add the suffix if given an `-o' + # argument, so we may need to know it at that point already. + # Even if this section looks crufty: it has the advantage of + # actually working. + break;; + * ) + break;; + esac +done +test "$ac_cv_exeext" = no && ac_cv_exeext= + +else + ac_file='' +fi +if test -z "$ac_file"; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +$as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error 77 "C compiler cannot create executables +See \`config.log' for more details" "$LINENO" 5; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler default output file name" >&5 +$as_echo_n "checking for C compiler default output file name... " >&6; } +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5 +$as_echo "$ac_file" >&6; } +ac_exeext=$ac_cv_exeext + +rm -f -r a.out a.out.dSYM a.exe conftest$ac_cv_exeext b.out +ac_clean_files=$ac_clean_files_save +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of executables" >&5 +$as_echo_n "checking for suffix of executables... " >&6; } +if { { ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_link") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then : + # If both `conftest.exe' and `conftest' are `present' (well, observable) +# catch `conftest.exe'. For instance with Cygwin, `ls conftest' will +# work properly (i.e., refer to `conftest.exe'), while it won't with +# `rm'. +for ac_file in conftest.exe conftest conftest.*; do + test -f "$ac_file" || continue + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; + *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` + break;; + * ) break;; + esac +done +else + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "cannot compute suffix of executables: cannot compile and link +See \`config.log' for more details" "$LINENO" 5; } +fi +rm -f conftest conftest$ac_cv_exeext +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5 +$as_echo "$ac_cv_exeext" >&6; } + +rm -f conftest.$ac_ext +EXEEXT=$ac_cv_exeext +ac_exeext=$EXEEXT +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include <stdio.h> +int +main () +{ +FILE *f = fopen ("conftest.out", "w"); + return ferror (f) || fclose (f) != 0; + + ; + return 0; +} +_ACEOF +ac_clean_files="$ac_clean_files conftest.out" +# Check that the compiler produces executables we can run. If not, either +# the compiler is broken, or we cross compile. +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5 +$as_echo_n "checking whether we are cross compiling... " >&6; } +if test "$cross_compiling" != yes; then + { { ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_link") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } + if { ac_try='./conftest$ac_cv_exeext' + { { case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; }; then + cross_compiling=no + else + if test "$cross_compiling" = maybe; then + cross_compiling=yes + else + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "cannot run C compiled programs. +If you meant to cross compile, use \`--host'. +See \`config.log' for more details" "$LINENO" 5; } + fi + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5 +$as_echo "$cross_compiling" >&6; } + +rm -f conftest.$ac_ext conftest$ac_cv_exeext conftest.out +ac_clean_files=$ac_clean_files_save +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5 +$as_echo_n "checking for suffix of object files... " >&6; } +if ${ac_cv_objext+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.o conftest.obj +if { { ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_compile") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then : + for ac_file in conftest.o conftest.obj conftest.*; do + test -f "$ac_file" || continue; + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM ) ;; + *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'` + break;; + esac +done +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "cannot compute suffix of object files: cannot compile +See \`config.log' for more details" "$LINENO" 5; } +fi +rm -f conftest.$ac_cv_objext conftest.$ac_ext +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5 +$as_echo "$ac_cv_objext" >&6; } +OBJEXT=$ac_cv_objext +ac_objext=$OBJEXT +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C compiler" >&5 +$as_echo_n "checking whether we are using the GNU C compiler... " >&6; } +if ${ac_cv_c_compiler_gnu+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ +#ifndef __GNUC__ + choke me +#endif + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_compiler_gnu=yes +else + ac_compiler_gnu=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +ac_cv_c_compiler_gnu=$ac_compiler_gnu + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5 +$as_echo "$ac_cv_c_compiler_gnu" >&6; } +if test $ac_compiler_gnu = yes; then + GCC=yes +else + GCC= +fi +ac_test_CFLAGS=${CFLAGS+set} +ac_save_CFLAGS=$CFLAGS +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5 +$as_echo_n "checking whether $CC accepts -g... " >&6; } +if ${ac_cv_prog_cc_g+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_save_c_werror_flag=$ac_c_werror_flag + ac_c_werror_flag=yes + ac_cv_prog_cc_g=no + CFLAGS="-g" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_prog_cc_g=yes +else + CFLAGS="" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + +else + ac_c_werror_flag=$ac_save_c_werror_flag + CFLAGS="-g" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_prog_cc_g=yes +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_c_werror_flag=$ac_save_c_werror_flag +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5 +$as_echo "$ac_cv_prog_cc_g" >&6; } +if test "$ac_test_CFLAGS" = set; then + CFLAGS=$ac_save_CFLAGS +elif test $ac_cv_prog_cc_g = yes; then + if test "$GCC" = yes; then + CFLAGS="-g -O2" + else + CFLAGS="-g" + fi +else + if test "$GCC" = yes; then + CFLAGS="-O2" + else + CFLAGS= + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C89" >&5 +$as_echo_n "checking for $CC option to accept ISO C89... " >&6; } +if ${ac_cv_prog_cc_c89+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_cv_prog_cc_c89=no +ac_save_CC=$CC +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include <stdarg.h> +#include <stdio.h> +struct stat; +/* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */ +struct buf { int x; }; +FILE * (*rcsopen) (struct buf *, struct stat *, int); +static char *e (p, i) + char **p; + int i; +{ + return p[i]; +} +static char *f (char * (*g) (char **, int), char **p, ...) +{ + char *s; + va_list v; + va_start (v,p); + s = g (p, va_arg (v,int)); + va_end (v); + return s; +} + +/* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has + function prototypes and stuff, but not '\xHH' hex character constants. + These don't provoke an error unfortunately, instead are silently treated + as 'x'. The following induces an error, until -std is added to get + proper ANSI mode. Curiously '\x00'!='x' always comes out true, for an + array size at least. It's necessary to write '\x00'==0 to get something + that's true only with -std. */ +int osf4_cc_array ['\x00' == 0 ? 1 : -1]; + +/* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters + inside strings and character constants. */ +#define FOO(x) 'x' +int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1]; + +int test (int i, double x); +struct s1 {int (*f) (int a);}; +struct s2 {int (*f) (double a);}; +int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int); +int argc; +char **argv; +int +main () +{ +return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]; + ; + return 0; +} +_ACEOF +for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \ + -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" +do + CC="$ac_save_CC $ac_arg" + if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_prog_cc_c89=$ac_arg +fi +rm -f core conftest.err conftest.$ac_objext + test "x$ac_cv_prog_cc_c89" != "xno" && break +done +rm -f conftest.$ac_ext +CC=$ac_save_CC + +fi +# AC_CACHE_VAL +case "x$ac_cv_prog_cc_c89" in + x) + { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 +$as_echo "none needed" >&6; } ;; + xno) + { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 +$as_echo "unsupported" >&6; } ;; + *) + CC="$CC $ac_cv_prog_cc_c89" + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5 +$as_echo "$ac_cv_prog_cc_c89" >&6; } ;; +esac +if test "x$ac_cv_prog_cc_c89" != xno; then : + +fi + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to run the C preprocessor" >&5 +$as_echo_n "checking how to run the C preprocessor... " >&6; } +# On Suns, sometimes $CPP names a directory. +if test -n "$CPP" && test -d "$CPP"; then + CPP= +fi +if test -z "$CPP"; then + if ${ac_cv_prog_CPP+:} false; then : + $as_echo_n "(cached) " >&6 +else + # Double quotes because CPP needs to be expanded + for CPP in "$CC -E" "$CC -E -traditional-cpp" "/lib/cpp" + do + ac_preproc_ok=false +for ac_c_preproc_warn_flag in '' yes +do + # Use a header file that comes with gcc, so configuring glibc + # with a fresh cross-compiler works. + # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since + # <limits.h> exists even on freestanding compilers. + # On the NeXT, cc -E runs the code through the compiler's parser, + # not just through cpp. "Syntax error" is here to catch this case. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#ifdef __STDC__ +# include <limits.h> +#else +# include <assert.h> +#endif + Syntax error +_ACEOF +if ac_fn_c_try_cpp "$LINENO"; then : + +else + # Broken: fails on valid input. +continue +fi +rm -f conftest.err conftest.i conftest.$ac_ext + + # OK, works on sane cases. Now check whether nonexistent headers + # can be detected and how. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include <ac_nonexistent.h> +_ACEOF +if ac_fn_c_try_cpp "$LINENO"; then : + # Broken: success on invalid input. +continue +else + # Passes both tests. +ac_preproc_ok=: +break +fi +rm -f conftest.err conftest.i conftest.$ac_ext + +done +# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. +rm -f conftest.i conftest.err conftest.$ac_ext +if $ac_preproc_ok; then : + break +fi + + done + ac_cv_prog_CPP=$CPP + +fi + CPP=$ac_cv_prog_CPP +else + ac_cv_prog_CPP=$CPP +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $CPP" >&5 +$as_echo "$CPP" >&6; } +ac_preproc_ok=false +for ac_c_preproc_warn_flag in '' yes +do + # Use a header file that comes with gcc, so configuring glibc + # with a fresh cross-compiler works. + # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since + # <limits.h> exists even on freestanding compilers. + # On the NeXT, cc -E runs the code through the compiler's parser, + # not just through cpp. "Syntax error" is here to catch this case. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#ifdef __STDC__ +# include <limits.h> +#else +# include <assert.h> +#endif + Syntax error +_ACEOF +if ac_fn_c_try_cpp "$LINENO"; then : + +else + # Broken: fails on valid input. +continue +fi +rm -f conftest.err conftest.i conftest.$ac_ext + + # OK, works on sane cases. Now check whether nonexistent headers + # can be detected and how. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include <ac_nonexistent.h> +_ACEOF +if ac_fn_c_try_cpp "$LINENO"; then : + # Broken: success on invalid input. +continue +else + # Passes both tests. +ac_preproc_ok=: +break +fi +rm -f conftest.err conftest.i conftest.$ac_ext + +done +# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. +rm -f conftest.i conftest.err conftest.$ac_ext +if $ac_preproc_ok; then : + +else + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "C preprocessor \"$CPP\" fails sanity check +See \`config.log' for more details" "$LINENO" 5; } +fi + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for grep that handles long lines and -e" >&5 +$as_echo_n "checking for grep that handles long lines and -e... " >&6; } +if ${ac_cv_path_GREP+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -z "$GREP"; then + ac_path_GREP_found=false + # Loop through the user's path and test for each of PROGNAME-LIST + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_prog in grep ggrep; do + for ac_exec_ext in '' $ac_executable_extensions; do + ac_path_GREP="$as_dir/$ac_prog$ac_exec_ext" + as_fn_executable_p "$ac_path_GREP" || continue +# Check for GNU ac_path_GREP and select it if it is found. + # Check for GNU $ac_path_GREP +case `"$ac_path_GREP" --version 2>&1` in +*GNU*) + ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_found=:;; +*) + ac_count=0 + $as_echo_n 0123456789 >"conftest.in" + while : + do + cat "conftest.in" "conftest.in" >"conftest.tmp" + mv "conftest.tmp" "conftest.in" + cp "conftest.in" "conftest.nl" + $as_echo 'GREP' >> "conftest.nl" + "$ac_path_GREP" -e 'GREP$' -e '-(cannot match)-' < "conftest.nl" >"conftest.out" 2>/dev/null || break + diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break + as_fn_arith $ac_count + 1 && ac_count=$as_val + if test $ac_count -gt ${ac_path_GREP_max-0}; then + # Best one so far, save it but keep looking for a better one + ac_cv_path_GREP="$ac_path_GREP" + ac_path_GREP_max=$ac_count + fi + # 10*(2^10) chars as input seems more than enough + test $ac_count -gt 10 && break + done + rm -f conftest.in conftest.tmp conftest.nl conftest.out;; +esac + + $ac_path_GREP_found && break 3 + done + done + done +IFS=$as_save_IFS + if test -z "$ac_cv_path_GREP"; then + as_fn_error $? "no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 + fi +else + ac_cv_path_GREP=$GREP +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_GREP" >&5 +$as_echo "$ac_cv_path_GREP" >&6; } + GREP="$ac_cv_path_GREP" + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for egrep" >&5 +$as_echo_n "checking for egrep... " >&6; } +if ${ac_cv_path_EGREP+:} false; then : + $as_echo_n "(cached) " >&6 +else + if echo a | $GREP -E '(a|b)' >/dev/null 2>&1 + then ac_cv_path_EGREP="$GREP -E" + else + if test -z "$EGREP"; then + ac_path_EGREP_found=false + # Loop through the user's path and test for each of PROGNAME-LIST + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_prog in egrep; do + for ac_exec_ext in '' $ac_executable_extensions; do + ac_path_EGREP="$as_dir/$ac_prog$ac_exec_ext" + as_fn_executable_p "$ac_path_EGREP" || continue +# Check for GNU ac_path_EGREP and select it if it is found. + # Check for GNU $ac_path_EGREP +case `"$ac_path_EGREP" --version 2>&1` in +*GNU*) + ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_found=:;; +*) + ac_count=0 + $as_echo_n 0123456789 >"conftest.in" + while : + do + cat "conftest.in" "conftest.in" >"conftest.tmp" + mv "conftest.tmp" "conftest.in" + cp "conftest.in" "conftest.nl" + $as_echo 'EGREP' >> "conftest.nl" + "$ac_path_EGREP" 'EGREP$' < "conftest.nl" >"conftest.out" 2>/dev/null || break + diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break + as_fn_arith $ac_count + 1 && ac_count=$as_val + if test $ac_count -gt ${ac_path_EGREP_max-0}; then + # Best one so far, save it but keep looking for a better one + ac_cv_path_EGREP="$ac_path_EGREP" + ac_path_EGREP_max=$ac_count + fi + # 10*(2^10) chars as input seems more than enough + test $ac_count -gt 10 && break + done + rm -f conftest.in conftest.tmp conftest.nl conftest.out;; +esac + + $ac_path_EGREP_found && break 3 + done + done + done +IFS=$as_save_IFS + if test -z "$ac_cv_path_EGREP"; then + as_fn_error $? "no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 + fi +else + ac_cv_path_EGREP=$EGREP +fi + + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_EGREP" >&5 +$as_echo "$ac_cv_path_EGREP" >&6; } + EGREP="$ac_cv_path_EGREP" + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ANSI C header files" >&5 +$as_echo_n "checking for ANSI C header files... " >&6; } +if ${ac_cv_header_stdc+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include <stdlib.h> +#include <stdarg.h> +#include <string.h> +#include <float.h> + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_header_stdc=yes +else + ac_cv_header_stdc=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + +if test $ac_cv_header_stdc = yes; then + # SunOS 4.x string.h does not declare mem*, contrary to ANSI. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include <string.h> + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "memchr" >/dev/null 2>&1; then : + +else + ac_cv_header_stdc=no +fi +rm -f conftest* + +fi + +if test $ac_cv_header_stdc = yes; then + # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include <stdlib.h> + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "free" >/dev/null 2>&1; then : + +else + ac_cv_header_stdc=no +fi +rm -f conftest* + +fi + +if test $ac_cv_header_stdc = yes; then + # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi. + if test "$cross_compiling" = yes; then : + : +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include <ctype.h> +#include <stdlib.h> +#if ((' ' & 0x0FF) == 0x020) +# define ISLOWER(c) ('a' <= (c) && (c) <= 'z') +# define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c)) +#else +# define ISLOWER(c) \ + (('a' <= (c) && (c) <= 'i') \ + || ('j' <= (c) && (c) <= 'r') \ + || ('s' <= (c) && (c) <= 'z')) +# define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c)) +#endif + +#define XOR(e, f) (((e) && !(f)) || (!(e) && (f))) +int +main () +{ + int i; + for (i = 0; i < 256; i++) + if (XOR (islower (i), ISLOWER (i)) + || toupper (i) != TOUPPER (i)) + return 2; + return 0; +} +_ACEOF +if ac_fn_c_try_run "$LINENO"; then : + +else + ac_cv_header_stdc=no +fi +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ + conftest.$ac_objext conftest.beam conftest.$ac_ext +fi + +fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_stdc" >&5 +$as_echo "$ac_cv_header_stdc" >&6; } +if test $ac_cv_header_stdc = yes; then + +$as_echo "#define STDC_HEADERS 1" >>confdefs.h + +fi + +# On IRIX 5.3, sys/types and inttypes.h are conflicting. +for ac_header in sys/types.h sys/stat.h stdlib.h string.h memory.h strings.h \ + inttypes.h stdint.h unistd.h +do : + as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` +ac_fn_c_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default +" +if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 +_ACEOF + +fi + +done + + + +# Check whether --with-libpcap was given. +if test "${with_libpcap+set}" = set; then : + withval=$with_libpcap; case "$with_libpcap" in + yes) + ac_fn_c_check_header_mongrel "$LINENO" "pcap.h" "ac_cv_header_pcap_h" "$ac_includes_default" +if test "x$ac_cv_header_pcap_h" = xyes; then : + + have_libpcap=yes + LIBPCAP_LIBS=-lpcap +fi + + + ;; + included) + have_libpcap=no + ;; + no) + ;; + *) + _cppflags=$CPPFLAGS + _ldflags=$LDFLAGS + + CPPFLAGS="-I$with_libpcap/include $CPPFLAGS" + LDFLAGS="-L$with_libpcap/lib $LDFLAGS" + + ac_fn_c_check_header_mongrel "$LINENO" "pcap.h" "ac_cv_header_pcap_h" "$ac_includes_default" +if test "x$ac_cv_header_pcap_h" = xyes; then : + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for pcap_create in -lpcap" >&5 +$as_echo_n "checking for pcap_create in -lpcap... " >&6; } +if ${ac_cv_lib_pcap_pcap_create+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lpcap $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char pcap_create (); +int +main () +{ +return pcap_create (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_pcap_pcap_create=yes +else + ac_cv_lib_pcap_pcap_create=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_pcap_pcap_create" >&5 +$as_echo "$ac_cv_lib_pcap_pcap_create" >&6; } +if test "x$ac_cv_lib_pcap_pcap_create" = xyes; then : + have_libpcap=yes + LIBPCAP_LIBS=-lpcap + LIBPCAP_INC=$with_libpcap/include + LIBPCAP_LIB=$with_libpcap/lib +fi + +fi + + + + LDFLAGS=$_ldflags + CPPFLAGS=$_cppflags + ;; + esac + +fi + + +if test "$with_libpcap" != "no" -a "$have_libpcap" = "no"; then + LIBPCAP_INC=${top_nmap_srcdir}/libpcap + LIBPCAP_LIB=${top_nmap_srcdir}/libpcap + LIBPCAP_LIBS=${LIBPCAP_LIB}/libpcap.a + have_libpcap=yes + +$as_echo "#define HAVE_PCAP_SET_IMMEDIATE_MODE 1" >>confdefs.h + +else + # link with -lpcap for the purposes of this test + LIBS_OLD="$LIBS" + LIBS="$LIBS -lpcap" + for ac_func in pcap_set_immediate_mode +do : + ac_fn_c_check_func "$LINENO" "pcap_set_immediate_mode" "ac_cv_func_pcap_set_immediate_mode" +if test "x$ac_cv_func_pcap_set_immediate_mode" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_PCAP_SET_IMMEDIATE_MODE 1 +_ACEOF + +fi +done + + # Restore libs + LIBS="$LIBS_OLD" +fi + +if test "$have_libpcap" != "no"; then + +$as_echo "#define HAVE_PCAP 1" >>confdefs.h + + if test "${LIBPCAP_INC+set}" = "set"; then + CPPFLAGS="-I$LIBPCAP_INC $CPPFLAGS" + LDFLAGS="-L$LIBPCAP_LIB $LDFLAGS" + fi +fi + + + ax_have_epoll_cppflags="${CPPFLAGS}" + ac_fn_c_check_header_mongrel "$LINENO" "linux/version.h" "ac_cv_header_linux_version_h" "$ac_includes_default" +if test "x$ac_cv_header_linux_version_h" = xyes; then : + CPPFLAGS="${CPPFLAGS} -DHAVE_LINUX_VERSION_H" +fi + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for Linux epoll(7) interface" >&5 +$as_echo_n "checking for Linux epoll(7) interface... " >&6; } + if ${ax_cv_have_epoll+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + #include <sys/epoll.h> +#ifdef HAVE_LINUX_VERSION_H +# include <linux/version.h> +# if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,45) +# error linux kernel version is too old to have epoll +# endif +#endif + +int +main () +{ +int fd, rc; +struct epoll_event ev; +fd = epoll_create(128); +rc = epoll_wait(fd, &ev, 1, 0); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ax_cv_have_epoll=yes +else + ax_cv_have_epoll=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi + + CPPFLAGS="${ax_have_epoll_cppflags}" + if test "${ax_cv_have_epoll}" = "yes"; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + +$as_echo "#define HAVE_EPOLL 1" >>confdefs.h + +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + +fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for poll(2)" >&5 +$as_echo_n "checking for poll(2)... " >&6; } + if ${ax_cv_have_poll+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + #include <poll.h> +int +main () +{ +int rc; rc = poll((struct pollfd *)(0), 0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ax_cv_have_poll=yes +else + ax_cv_have_poll=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi + + if test "${ax_cv_have_poll}" = "yes"; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + +$as_echo "#define HAVE_POLL 1" >>confdefs.h + +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + +fi + +for ac_func in kqueue kevent +do : + as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` +ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" +if eval test \"x\$"$as_ac_var"\" = x"yes"; then : + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 +_ACEOF + $as_echo "#define HAVE_KQUEUE 1" >>confdefs.h + +fi +done + + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args. +set dummy ${ac_tool_prefix}gcc; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_CC+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_CC="${ac_tool_prefix}gcc" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +$as_echo "$CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_CC"; then + ac_ct_CC=$CC + # Extract the first word of "gcc", so it can be a program name with args. +set dummy gcc; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_CC+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_CC"; then + ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_CC="gcc" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_CC=$ac_cv_prog_ac_ct_CC +if test -n "$ac_ct_CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 +$as_echo "$ac_ct_CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_CC" = x; then + CC="" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + CC=$ac_ct_CC + fi +else + CC="$ac_cv_prog_CC" +fi + +if test -z "$CC"; then + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args. +set dummy ${ac_tool_prefix}cc; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_CC+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_CC="${ac_tool_prefix}cc" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +$as_echo "$CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + fi +fi +if test -z "$CC"; then + # Extract the first word of "cc", so it can be a program name with args. +set dummy cc; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_CC+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else + ac_prog_rejected=no +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then + ac_prog_rejected=yes + continue + fi + ac_cv_prog_CC="cc" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +if test $ac_prog_rejected = yes; then + # We found a bogon in the path, so make sure we never use it. + set dummy $ac_cv_prog_CC + shift + if test $# != 0; then + # We chose a different compiler from the bogus one. + # However, it has the same basename, so the bogon will be chosen + # first if we set CC to just the basename; use the full file name. + shift + ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@" + fi +fi +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +$as_echo "$CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$CC"; then + if test -n "$ac_tool_prefix"; then + for ac_prog in cl.exe + do + # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. +set dummy $ac_tool_prefix$ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_CC+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_CC="$ac_tool_prefix$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +$as_echo "$CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$CC" && break + done +fi +if test -z "$CC"; then + ac_ct_CC=$CC + for ac_prog in cl.exe +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_CC+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_CC"; then + ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_CC="$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_CC=$ac_cv_prog_ac_ct_CC +if test -n "$ac_ct_CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 +$as_echo "$ac_ct_CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$ac_ct_CC" && break +done + + if test "x$ac_ct_CC" = x; then + CC="" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + CC=$ac_ct_CC + fi +fi + +fi + + +test -z "$CC" && { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "no acceptable C compiler found in \$PATH +See \`config.log' for more details" "$LINENO" 5; } + +# Provide some information about the compiler. +$as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5 +set X $ac_compile +ac_compiler=$2 +for ac_option in --version -v -V -qversion; do + { { ac_try="$ac_compiler $ac_option >&5" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_compiler $ac_option >&5") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + sed '10a\ +... rest of stderr output deleted ... + 10q' conftest.err >conftest.er1 + cat conftest.er1 >&5 + fi + rm -f conftest.er1 conftest.err + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } +done + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C compiler" >&5 +$as_echo_n "checking whether we are using the GNU C compiler... " >&6; } +if ${ac_cv_c_compiler_gnu+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ +#ifndef __GNUC__ + choke me +#endif + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_compiler_gnu=yes +else + ac_compiler_gnu=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +ac_cv_c_compiler_gnu=$ac_compiler_gnu + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5 +$as_echo "$ac_cv_c_compiler_gnu" >&6; } +if test $ac_compiler_gnu = yes; then + GCC=yes +else + GCC= +fi +ac_test_CFLAGS=${CFLAGS+set} +ac_save_CFLAGS=$CFLAGS +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5 +$as_echo_n "checking whether $CC accepts -g... " >&6; } +if ${ac_cv_prog_cc_g+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_save_c_werror_flag=$ac_c_werror_flag + ac_c_werror_flag=yes + ac_cv_prog_cc_g=no + CFLAGS="-g" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_prog_cc_g=yes +else + CFLAGS="" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + +else + ac_c_werror_flag=$ac_save_c_werror_flag + CFLAGS="-g" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_prog_cc_g=yes +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_c_werror_flag=$ac_save_c_werror_flag +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5 +$as_echo "$ac_cv_prog_cc_g" >&6; } +if test "$ac_test_CFLAGS" = set; then + CFLAGS=$ac_save_CFLAGS +elif test $ac_cv_prog_cc_g = yes; then + if test "$GCC" = yes; then + CFLAGS="-g -O2" + else + CFLAGS="-g" + fi +else + if test "$GCC" = yes; then + CFLAGS="-O2" + else + CFLAGS= + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C89" >&5 +$as_echo_n "checking for $CC option to accept ISO C89... " >&6; } +if ${ac_cv_prog_cc_c89+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_cv_prog_cc_c89=no +ac_save_CC=$CC +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include <stdarg.h> +#include <stdio.h> +struct stat; +/* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */ +struct buf { int x; }; +FILE * (*rcsopen) (struct buf *, struct stat *, int); +static char *e (p, i) + char **p; + int i; +{ + return p[i]; +} +static char *f (char * (*g) (char **, int), char **p, ...) +{ + char *s; + va_list v; + va_start (v,p); + s = g (p, va_arg (v,int)); + va_end (v); + return s; +} + +/* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has + function prototypes and stuff, but not '\xHH' hex character constants. + These don't provoke an error unfortunately, instead are silently treated + as 'x'. The following induces an error, until -std is added to get + proper ANSI mode. Curiously '\x00'!='x' always comes out true, for an + array size at least. It's necessary to write '\x00'==0 to get something + that's true only with -std. */ +int osf4_cc_array ['\x00' == 0 ? 1 : -1]; + +/* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters + inside strings and character constants. */ +#define FOO(x) 'x' +int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1]; + +int test (int i, double x); +struct s1 {int (*f) (int a);}; +struct s2 {int (*f) (double a);}; +int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int); +int argc; +char **argv; +int +main () +{ +return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]; + ; + return 0; +} +_ACEOF +for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \ + -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" +do + CC="$ac_save_CC $ac_arg" + if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_prog_cc_c89=$ac_arg +fi +rm -f core conftest.err conftest.$ac_objext + test "x$ac_cv_prog_cc_c89" != "xno" && break +done +rm -f conftest.$ac_ext +CC=$ac_save_CC + +fi +# AC_CACHE_VAL +case "x$ac_cv_prog_cc_c89" in + x) + { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 +$as_echo "none needed" >&6; } ;; + xno) + { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 +$as_echo "unsupported" >&6; } ;; + *) + CC="$CC $ac_cv_prog_cc_c89" + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5 +$as_echo "$ac_cv_prog_cc_c89" >&6; } ;; +esac +if test "x$ac_cv_prog_cc_c89" != xno; then : + +fi + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + if test -n "$GCC"; then + CFLAGS="$CFLAGS -Wall " + fi +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}ranlib", so it can be a program name with args. +set dummy ${ac_tool_prefix}ranlib; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_RANLIB+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$RANLIB"; then + ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_RANLIB="${ac_tool_prefix}ranlib" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +RANLIB=$ac_cv_prog_RANLIB +if test -n "$RANLIB"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $RANLIB" >&5 +$as_echo "$RANLIB" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_RANLIB"; then + ac_ct_RANLIB=$RANLIB + # Extract the first word of "ranlib", so it can be a program name with args. +set dummy ranlib; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_RANLIB+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_RANLIB"; then + ac_cv_prog_ac_ct_RANLIB="$ac_ct_RANLIB" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_RANLIB="ranlib" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_RANLIB=$ac_cv_prog_ac_ct_RANLIB +if test -n "$ac_ct_RANLIB"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_RANLIB" >&5 +$as_echo "$ac_ct_RANLIB" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_RANLIB" = x; then + RANLIB=":" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + RANLIB=$ac_ct_RANLIB + fi +else + RANLIB="$ac_cv_prog_RANLIB" +fi + + + +ac_fn_c_check_func "$LINENO" "gethostent" "ac_cv_func_gethostent" +if test "x$ac_cv_func_gethostent" = xyes; then : + +else + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for gethostent in -lnsl" >&5 +$as_echo_n "checking for gethostent in -lnsl... " >&6; } +if ${ac_cv_lib_nsl_gethostent+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lnsl $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char gethostent (); +int +main () +{ +return gethostent (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_nsl_gethostent=yes +else + ac_cv_lib_nsl_gethostent=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_nsl_gethostent" >&5 +$as_echo "$ac_cv_lib_nsl_gethostent" >&6; } +if test "x$ac_cv_lib_nsl_gethostent" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_LIBNSL 1 +_ACEOF + + LIBS="-lnsl $LIBS" + +fi + +fi + +ac_fn_c_check_func "$LINENO" "setsockopt" "ac_cv_func_setsockopt" +if test "x$ac_cv_func_setsockopt" = xyes; then : + +else + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for setsockopt in -lsocket" >&5 +$as_echo_n "checking for setsockopt in -lsocket... " >&6; } +if ${ac_cv_lib_socket_setsockopt+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lsocket $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char setsockopt (); +int +main () +{ +return setsockopt (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_socket_setsockopt=yes +else + ac_cv_lib_socket_setsockopt=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_socket_setsockopt" >&5 +$as_echo "$ac_cv_lib_socket_setsockopt" >&6; } +if test "x$ac_cv_lib_socket_setsockopt" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_LIBSOCKET 1 +_ACEOF + + LIBS="-lsocket $LIBS" + +fi + +fi + + +ac_fn_c_check_func "$LINENO" "nanosleep" "ac_cv_func_nanosleep" +if test "x$ac_cv_func_nanosleep" = xyes; then : + +else + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for nanosleep in -lposix4" >&5 +$as_echo_n "checking for nanosleep in -lposix4... " >&6; } +if ${ac_cv_lib_posix4_nanosleep+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lposix4 $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char nanosleep (); +int +main () +{ +return nanosleep (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_posix4_nanosleep=yes +else + ac_cv_lib_posix4_nanosleep=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_posix4_nanosleep" >&5 +$as_echo "$ac_cv_lib_posix4_nanosleep" >&6; } +if test "x$ac_cv_lib_posix4_nanosleep" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_LIBPOSIX4 1 +_ACEOF + + LIBS="-lposix4 $LIBS" + +fi + +fi + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ANSI C header files" >&5 +$as_echo_n "checking for ANSI C header files... " >&6; } +if ${ac_cv_header_stdc+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include <stdlib.h> +#include <stdarg.h> +#include <string.h> +#include <float.h> + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_header_stdc=yes +else + ac_cv_header_stdc=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + +if test $ac_cv_header_stdc = yes; then + # SunOS 4.x string.h does not declare mem*, contrary to ANSI. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include <string.h> + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "memchr" >/dev/null 2>&1; then : + +else + ac_cv_header_stdc=no +fi +rm -f conftest* + +fi + +if test $ac_cv_header_stdc = yes; then + # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include <stdlib.h> + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "free" >/dev/null 2>&1; then : + +else + ac_cv_header_stdc=no +fi +rm -f conftest* + +fi + +if test $ac_cv_header_stdc = yes; then + # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi. + if test "$cross_compiling" = yes; then : + : +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include <ctype.h> +#include <stdlib.h> +#if ((' ' & 0x0FF) == 0x020) +# define ISLOWER(c) ('a' <= (c) && (c) <= 'z') +# define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c)) +#else +# define ISLOWER(c) \ + (('a' <= (c) && (c) <= 'i') \ + || ('j' <= (c) && (c) <= 'r') \ + || ('s' <= (c) && (c) <= 'z')) +# define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c)) +#endif + +#define XOR(e, f) (((e) && !(f)) || (!(e) && (f))) +int +main () +{ + int i; + for (i = 0; i < 256; i++) + if (XOR (islower (i), ISLOWER (i)) + || toupper (i) != TOUPPER (i)) + return 2; + return 0; +} +_ACEOF +if ac_fn_c_try_run "$LINENO"; then : + +else + ac_cv_header_stdc=no +fi +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ + conftest.$ac_objext conftest.beam conftest.$ac_ext +fi + +fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_stdc" >&5 +$as_echo "$ac_cv_header_stdc" >&6; } +if test $ac_cv_header_stdc = yes; then + +$as_echo "#define STDC_HEADERS 1" >>confdefs.h + +fi + +for ac_header in net/bpf.h sys/ioctl.h sys/un.h netdb.h +do : + as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` +ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default" +if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 +_ACEOF + +fi + +done + +for ac_header in linux/vm_sockets.h +do : + ac_fn_c_check_header_compile "$LINENO" "linux/vm_sockets.h" "ac_cv_header_linux_vm_sockets_h" "#include <sys/socket.h> +" +if test "x$ac_cv_header_linux_vm_sockets_h" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_LINUX_VM_SOCKETS_H 1 +_ACEOF + +fi + +done + + +# We test whether they specified openssl desires explicitly +use_openssl="yes" +specialssldir="" + +# Check whether --with-openssl was given. +if test "${with_openssl+set}" = set; then : + withval=$with_openssl; case "$with_openssl" in + yes) + ;; + no) + use_openssl="no" + ;; + *) + specialssldir="$with_openssl" + CPPFLAGS="$CPPFLAGS -I$with_openssl/include" + LDFLAGS="$LDFLAGS -L$with_openssl/lib" + ;; + esac + +fi + + +# If they didn't specify it, we try to find it +if test "$use_openssl" = "yes" -a -z "$specialssldir"; then + ac_fn_c_check_header_mongrel "$LINENO" "openssl/ssl.h" "ac_cv_header_openssl_ssl_h" "$ac_includes_default" +if test "x$ac_cv_header_openssl_ssl_h" = xyes; then : + +else + use_openssl="no" + if test "$with_openssl" = "yes"; then + as_fn_error $? "OpenSSL was explicitly requested but openssl/ssl.h was not found. Try the --with-openssl=DIR argument to give the location of OpenSSL or run configure with --without-openssl." "$LINENO" 5 + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Failed to find openssl/ssl.h so OpenSSL will not be used. If it is installed you can try the --with-openssl=DIR argument" >&5 +$as_echo "$as_me: WARNING: Failed to find openssl/ssl.h so OpenSSL will not be used. If it is installed you can try the --with-openssl=DIR argument" >&2;} + +fi + + + +# use_openssl="yes" given explicitly in next 2 rules to avoid adding lib to $LIBS + if test "$use_openssl" = "yes"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for BIO_int_ctrl in -lcrypto" >&5 +$as_echo_n "checking for BIO_int_ctrl in -lcrypto... " >&6; } +if ${ac_cv_lib_crypto_BIO_int_ctrl+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lcrypto $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char BIO_int_ctrl (); +int +main () +{ +return BIO_int_ctrl (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_crypto_BIO_int_ctrl=yes +else + ac_cv_lib_crypto_BIO_int_ctrl=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_crypto_BIO_int_ctrl" >&5 +$as_echo "$ac_cv_lib_crypto_BIO_int_ctrl" >&6; } +if test "x$ac_cv_lib_crypto_BIO_int_ctrl" = xyes; then : + use_openssl="yes" +else + use_openssl="no" + if test "$with_openssl" = "yes"; then + as_fn_error $? "OpenSSL was explicitly requested but libcrypto was not found. Try the --with-openssl=DIR argument to give the location of OpenSSL or run configure with --without-openssl." "$LINENO" 5 + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Failed to find libcrypto so OpenSSL will not be used. If it is installed you can try the --with-openssl=DIR argument" >&5 +$as_echo "$as_me: WARNING: Failed to find libcrypto so OpenSSL will not be used. If it is installed you can try the --with-openssl=DIR argument" >&2;} + +fi + + fi + + if test "$use_openssl" = "yes"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for SSL_new in -lssl" >&5 +$as_echo_n "checking for SSL_new in -lssl... " >&6; } +if ${ac_cv_lib_ssl_SSL_new+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lssl -lcrypto $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char SSL_new (); +int +main () +{ +return SSL_new (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_ssl_SSL_new=yes +else + ac_cv_lib_ssl_SSL_new=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_ssl_SSL_new" >&5 +$as_echo "$ac_cv_lib_ssl_SSL_new" >&6; } +if test "x$ac_cv_lib_ssl_SSL_new" = xyes; then : + use_openssl="yes" +else + use_openssl="no" + if test "$with_openssl" = "yes"; then + as_fn_error $? "OpenSSL was explicitly requested but libssl was not found. Try the --with-openssl=DIR argument to give the location of OpenSSL or run configure with --without-openssl." "$LINENO" 5 + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Failed to find libssl so OpenSSL will not be used. If it is installed you can try the --with-openssl=DIR argument" >&5 +$as_echo "$as_me: WARNING: Failed to find libssl so OpenSSL will not be used. If it is installed you can try the --with-openssl=DIR argument" >&2;} +fi + + fi +fi + +# OpenSSL requires dlopen on some platforms +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing dlopen" >&5 +$as_echo_n "checking for library containing dlopen... " >&6; } +if ${ac_cv_search_dlopen+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_func_search_save_LIBS=$LIBS +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char dlopen (); +int +main () +{ +return dlopen (); + ; + return 0; +} +_ACEOF +for ac_lib in '' dl; do + if test -z "$ac_lib"; then + ac_res="none required" + else + ac_res=-l$ac_lib + LIBS="-l$ac_lib $ac_func_search_save_LIBS" + fi + if ac_fn_c_try_link "$LINENO"; then : + ac_cv_search_dlopen=$ac_res +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext + if ${ac_cv_search_dlopen+:} false; then : + break +fi +done +if ${ac_cv_search_dlopen+:} false; then : + +else + ac_cv_search_dlopen=no +fi +rm conftest.$ac_ext +LIBS=$ac_func_search_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_dlopen" >&5 +$as_echo "$ac_cv_search_dlopen" >&6; } +ac_res=$ac_cv_search_dlopen +if test "$ac_res" != no; then : + test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" + +fi + + +OPENSSL_LIBS= +if test "$use_openssl" = "yes"; then + +$as_echo "#define HAVE_OPENSSL 1" >>confdefs.h + + OPENSSL_LIBS="-lssl -lcrypto" + LIBS_TMP="$LIBS" + LIBS="$OPENSSL_LIBS $LIBS" + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for SSL_set_tlsext_host_name" >&5 +$as_echo_n "checking for SSL_set_tlsext_host_name... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include <openssl/ssl.h> +int +main () +{ +SSL_set_tlsext_host_name(NULL, NULL) + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; }; +$as_echo "#define HAVE_SSL_SET_TLSEXT_HOST_NAME 1" >>confdefs.h + +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for DTLS_client_method" >&5 +$as_echo_n "checking for DTLS_client_method... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include <openssl/ssl.h> +int +main () +{ +DTLS_client_method() + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; }; +$as_echo "#define HAVE_DTLS_CLIENT_METHOD 1" >>confdefs.h + +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for SSL_set_alpn_protos" >&5 +$as_echo_n "checking for SSL_set_alpn_protos... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include <openssl/ssl.h> +int +main () +{ +SSL_set_alpn_protos(NULL, NULL, 0) + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; }; +$as_echo "#define HAVE_ALPN_SUPPORT 1" >>confdefs.h + +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + LIBS="$LIBS_TMP" + +fi + + + + + +# Check whether --with-libnbase was given. +if test "${with_libnbase+set}" = set; then : + withval=$with_libnbase; case "$with_libnbase" in + yes) + ;; + *) + NBASEDIR="$with_libnbase" + ;; + esac +else + NBASEDIR="${top_nmap_srcdir}/nbase" + +fi + + +NSOCKTESTDIR="../tests" + +LDFLAGS="$LDFLAGS -L$NBASEDIR" +CPPFLAGS="$CPPFLAGS -I$NBASEDIR" +LIBNBASE_LIBS="$LIBS -lnbase" + + + + + + + +cat >confcache <<\_ACEOF +# This file is a shell script that caches the results of configure +# tests run on this system so they can be shared between configure +# scripts and configure runs, see configure's option --config-cache. +# It is not useful on other systems. If it contains results you don't +# want to keep, you may remove or edit it. +# +# config.status only pays attention to the cache file if you give it +# the --recheck option to rerun configure. +# +# `ac_cv_env_foo' variables (set or unset) will be overridden when +# loading this file, other *unset* `ac_cv_foo' will be assigned the +# following values. + +_ACEOF + +# The following way of writing the cache mishandles newlines in values, +# but we know of no workaround that is simple, portable, and efficient. +# So, we kill variables containing newlines. +# Ultrix sh set writes to stderr and can't be redirected directly, +# and sets the high bit in the cache file unless we assign to the vars. +( + for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do + eval ac_val=\$$ac_var + case $ac_val in #( + *${as_nl}*) + case $ac_var in #( + *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 +$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; + esac + case $ac_var in #( + _ | IFS | as_nl) ;; #( + BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( + *) { eval $ac_var=; unset $ac_var;} ;; + esac ;; + esac + done + + (set) 2>&1 | + case $as_nl`(ac_space=' '; set) 2>&1` in #( + *${as_nl}ac_space=\ *) + # `set' does not quote correctly, so add quotes: double-quote + # substitution turns \\\\ into \\, and sed turns \\ into \. + sed -n \ + "s/'/'\\\\''/g; + s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p" + ;; #( + *) + # `set' quotes correctly as required by POSIX, so do not add quotes. + sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" + ;; + esac | + sort +) | + sed ' + /^ac_cv_env_/b end + t clear + :clear + s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/ + t end + s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/ + :end' >>confcache +if diff "$cache_file" confcache >/dev/null 2>&1; then :; else + if test -w "$cache_file"; then + if test "x$cache_file" != "x/dev/null"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5 +$as_echo "$as_me: updating cache $cache_file" >&6;} + if test ! -f "$cache_file" || test -h "$cache_file"; then + cat confcache >"$cache_file" + else + case $cache_file in #( + */* | ?:*) + mv -f confcache "$cache_file"$$ && + mv -f "$cache_file"$$ "$cache_file" ;; #( + *) + mv -f confcache "$cache_file" ;; + esac + fi + fi + else + { $as_echo "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5 +$as_echo "$as_me: not updating unwritable cache $cache_file" >&6;} + fi +fi +rm -f confcache + +test "x$prefix" = xNONE && prefix=$ac_default_prefix +# Let make expand exec_prefix. +test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' + +DEFS=-DHAVE_CONFIG_H + +ac_libobjs= +ac_ltlibobjs= +U= +for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue + # 1. Remove the extension, and $U if already installed. + ac_script='s/\$U\././;s/\.o$//;s/\.obj$//' + ac_i=`$as_echo "$ac_i" | sed "$ac_script"` + # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR + # will be set to the directory where LIBOBJS objects are built. + as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext" + as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo' +done +LIBOBJS=$ac_libobjs + +LTLIBOBJS=$ac_ltlibobjs + + + +: "${CONFIG_STATUS=./config.status}" +ac_write_fail=0 +ac_clean_files_save=$ac_clean_files +ac_clean_files="$ac_clean_files $CONFIG_STATUS" +{ $as_echo "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5 +$as_echo "$as_me: creating $CONFIG_STATUS" >&6;} +as_write_fail=0 +cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1 +#! $SHELL +# Generated by $as_me. +# Run this file to recreate the current configuration. +# Compiler output produced by configure, useful for debugging +# configure, is in config.log if it exists. + +debug=false +ac_cs_recheck=false +ac_cs_silent=false + +SHELL=\${CONFIG_SHELL-$SHELL} +export SHELL +_ASEOF +cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1 +## -------------------- ## +## M4sh Initialization. ## +## -------------------- ## + +# Be more Bourne compatible +DUALCASE=1; export DUALCASE # for MKS sh +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : + emulate sh + NULLCMD=: + # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which + # is contrary to our usage. Disable this feature. + alias -g '${1+"$@"}'='"$@"' + setopt NO_GLOB_SUBST +else + case `(set -o) 2>/dev/null` in #( + *posix*) : + set -o posix ;; #( + *) : + ;; +esac +fi + + +as_nl=' +' +export as_nl +# Printing a long string crashes Solaris 7 /usr/bin/printf. +as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' +as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo +as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo +# Prefer a ksh shell builtin over an external printf program on Solaris, +# but without wasting forks for bash or zsh. +if test -z "$BASH_VERSION$ZSH_VERSION" \ + && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then + as_echo='print -r --' + as_echo_n='print -rn --' +elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then + as_echo='printf %s\n' + as_echo_n='printf %s' +else + if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then + as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' + as_echo_n='/usr/ucb/echo -n' + else + as_echo_body='eval expr "X$1" : "X\\(.*\\)"' + as_echo_n_body='eval + arg=$1; + case $arg in #( + *"$as_nl"*) + expr "X$arg" : "X\\(.*\\)$as_nl"; + arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; + esac; + expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" + ' + export as_echo_n_body + as_echo_n='sh -c $as_echo_n_body as_echo' + fi + export as_echo_body + as_echo='sh -c $as_echo_body as_echo' +fi + +# The user is always right. +if test "${PATH_SEPARATOR+set}" != set; then + PATH_SEPARATOR=: + (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { + (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || + PATH_SEPARATOR=';' + } +fi + + +# IFS +# We need space, tab and new line, in precisely that order. Quoting is +# there to prevent editors from complaining about space-tab. +# (If _AS_PATH_WALK were called with IFS unset, it would disable word +# splitting by setting IFS to empty value.) +IFS=" "" $as_nl" + +# Find who we are. Look in the path if we contain no directory separator. +as_myself= +case $0 in #(( + *[\\/]* ) as_myself=$0 ;; + *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break + done +IFS=$as_save_IFS + + ;; +esac +# We did not find ourselves, most probably we were run as `sh COMMAND' +# in which case we are not to be found in the path. +if test "x$as_myself" = x; then + as_myself=$0 +fi +if test ! -f "$as_myself"; then + $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 + exit 1 +fi + +# Unset variables that we do not need and which cause bugs (e.g. in +# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" +# suppresses any "Segmentation fault" message there. '((' could +# trigger a bug in pdksh 5.2.14. +for as_var in BASH_ENV ENV MAIL MAILPATH +do eval test x\${$as_var+set} = xset \ + && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : +done +PS1='$ ' +PS2='> ' +PS4='+ ' + +# NLS nuisances. +LC_ALL=C +export LC_ALL +LANGUAGE=C +export LANGUAGE + +# CDPATH. +(unset CDPATH) >/dev/null 2>&1 && unset CDPATH + + +# as_fn_error STATUS ERROR [LINENO LOG_FD] +# ---------------------------------------- +# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are +# provided, also output the error to LOG_FD, referencing LINENO. Then exit the +# script with STATUS, using 1 if that was 0. +as_fn_error () +{ + as_status=$1; test $as_status -eq 0 && as_status=1 + if test "$4"; then + as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 + fi + $as_echo "$as_me: error: $2" >&2 + as_fn_exit $as_status +} # as_fn_error + + +# as_fn_set_status STATUS +# ----------------------- +# Set $? to STATUS, without forking. +as_fn_set_status () +{ + return $1 +} # as_fn_set_status + +# as_fn_exit STATUS +# ----------------- +# Exit the shell with STATUS, even in a "trap 0" or "set -e" context. +as_fn_exit () +{ + set +e + as_fn_set_status $1 + exit $1 +} # as_fn_exit + +# as_fn_unset VAR +# --------------- +# Portably unset VAR. +as_fn_unset () +{ + { eval $1=; unset $1;} +} +as_unset=as_fn_unset +# as_fn_append VAR VALUE +# ---------------------- +# Append the text in VALUE to the end of the definition contained in VAR. Take +# advantage of any shell optimizations that allow amortized linear growth over +# repeated appends, instead of the typical quadratic growth present in naive +# implementations. +if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : + eval 'as_fn_append () + { + eval $1+=\$2 + }' +else + as_fn_append () + { + eval $1=\$$1\$2 + } +fi # as_fn_append + +# as_fn_arith ARG... +# ------------------ +# Perform arithmetic evaluation on the ARGs, and store the result in the +# global $as_val. Take advantage of shells that can avoid forks. The arguments +# must be portable across $(()) and expr. +if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : + eval 'as_fn_arith () + { + as_val=$(( $* )) + }' +else + as_fn_arith () + { + as_val=`expr "$@" || test $? -eq 1` + } +fi # as_fn_arith + + +if expr a : '\(a\)' >/dev/null 2>&1 && + test "X`expr 00001 : '.*\(...\)'`" = X001; then + as_expr=expr +else + as_expr=false +fi + +if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then + as_basename=basename +else + as_basename=false +fi + +if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then + as_dirname=dirname +else + as_dirname=false +fi + +as_me=`$as_basename -- "$0" || +$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ + X"$0" : 'X\(//\)$' \| \ + X"$0" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X/"$0" | + sed '/^.*\/\([^/][^/]*\)\/*$/{ + s//\1/ + q + } + /^X\/\(\/\/\)$/{ + s//\1/ + q + } + /^X\/\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + +# Avoid depending upon Character Ranges. +as_cr_letters='abcdefghijklmnopqrstuvwxyz' +as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' +as_cr_Letters=$as_cr_letters$as_cr_LETTERS +as_cr_digits='0123456789' +as_cr_alnum=$as_cr_Letters$as_cr_digits + +ECHO_C= ECHO_N= ECHO_T= +case `echo -n x` in #((((( +-n*) + case `echo 'xy\c'` in + *c*) ECHO_T=' ';; # ECHO_T is single tab character. + xy) ECHO_C='\c';; + *) echo `echo ksh88 bug on AIX 6.1` > /dev/null + ECHO_T=' ';; + esac;; +*) + ECHO_N='-n';; +esac + +rm -f conf$$ conf$$.exe conf$$.file +if test -d conf$$.dir; then + rm -f conf$$.dir/conf$$.file +else + rm -f conf$$.dir + mkdir conf$$.dir 2>/dev/null +fi +if (echo >conf$$.file) 2>/dev/null; then + if ln -s conf$$.file conf$$ 2>/dev/null; then + as_ln_s='ln -s' + # ... but there are two gotchas: + # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. + # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. + # In both cases, we have to default to `cp -pR'. + ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || + as_ln_s='cp -pR' + elif ln conf$$.file conf$$ 2>/dev/null; then + as_ln_s=ln + else + as_ln_s='cp -pR' + fi +else + as_ln_s='cp -pR' +fi +rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file +rmdir conf$$.dir 2>/dev/null + + +# as_fn_mkdir_p +# ------------- +# Create "$as_dir" as a directory, including parents if necessary. +as_fn_mkdir_p () +{ + + case $as_dir in #( + -*) as_dir=./$as_dir;; + esac + test -d "$as_dir" || eval $as_mkdir_p || { + as_dirs= + while :; do + case $as_dir in #( + *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( + *) as_qdir=$as_dir;; + esac + as_dirs="'$as_qdir' $as_dirs" + as_dir=`$as_dirname -- "$as_dir" || +$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$as_dir" : 'X\(//\)[^/]' \| \ + X"$as_dir" : 'X\(//\)$' \| \ + X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$as_dir" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + test -d "$as_dir" && break + done + test -z "$as_dirs" || eval "mkdir $as_dirs" + } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" + + +} # as_fn_mkdir_p +if mkdir -p . 2>/dev/null; then + as_mkdir_p='mkdir -p "$as_dir"' +else + test -d ./-p && rmdir ./-p + as_mkdir_p=false +fi + + +# as_fn_executable_p FILE +# ----------------------- +# Test if FILE is an executable regular file. +as_fn_executable_p () +{ + test -f "$1" && test -x "$1" +} # as_fn_executable_p +as_test_x='test -x' +as_executable_p=as_fn_executable_p + +# Sed expression to map a string onto a valid CPP name. +as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" + +# Sed expression to map a string onto a valid variable name. +as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" + + +exec 6>&1 +## ----------------------------------- ## +## Main body of $CONFIG_STATUS script. ## +## ----------------------------------- ## +_ASEOF +test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1 + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +# Save the log message, to keep $0 and so on meaningful, and to +# report actual input values of CONFIG_FILES etc. instead of their +# values after options handling. +ac_log=" +This file was extended by $as_me, which was +generated by GNU Autoconf 2.69. Invocation command line was + + CONFIG_FILES = $CONFIG_FILES + CONFIG_HEADERS = $CONFIG_HEADERS + CONFIG_LINKS = $CONFIG_LINKS + CONFIG_COMMANDS = $CONFIG_COMMANDS + $ $0 $@ + +on `(hostname || uname -n) 2>/dev/null | sed 1q` +" + +_ACEOF + +case $ac_config_files in *" +"*) set x $ac_config_files; shift; ac_config_files=$*;; +esac + +case $ac_config_headers in *" +"*) set x $ac_config_headers; shift; ac_config_headers=$*;; +esac + + +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +# Files that config.status was made for. +config_files="$ac_config_files" +config_headers="$ac_config_headers" + +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +ac_cs_usage="\ +\`$as_me' instantiates files and other configuration actions +from templates according to the current configuration. Unless the files +and actions are specified as TAGs, all are instantiated by default. + +Usage: $0 [OPTION]... [TAG]... + + -h, --help print this help, then exit + -V, --version print version number and configuration settings, then exit + --config print configuration, then exit + -q, --quiet, --silent + do not print progress messages + -d, --debug don't remove temporary files + --recheck update $as_me by reconfiguring in the same conditions + --file=FILE[:TEMPLATE] + instantiate the configuration file FILE + --header=FILE[:TEMPLATE] + instantiate the configuration header FILE + +Configuration files: +$config_files + +Configuration headers: +$config_headers + +Report bugs to the package provider." + +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" +ac_cs_version="\\ +config.status +configured by $0, generated by GNU Autoconf 2.69, + with options \\"\$ac_cs_config\\" + +Copyright (C) 2012 Free Software Foundation, Inc. +This config.status script is free software; the Free Software Foundation +gives unlimited permission to copy, distribute and modify it." + +ac_pwd='$ac_pwd' +srcdir='$srcdir' +test -n "\$AWK" || AWK=awk +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +# The default lists apply if the user does not specify any file. +ac_need_defaults=: +while test $# != 0 +do + case $1 in + --*=?*) + ac_option=`expr "X$1" : 'X\([^=]*\)='` + ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'` + ac_shift=: + ;; + --*=) + ac_option=`expr "X$1" : 'X\([^=]*\)='` + ac_optarg= + ac_shift=: + ;; + *) + ac_option=$1 + ac_optarg=$2 + ac_shift=shift + ;; + esac + + case $ac_option in + # Handling of the options. + -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) + ac_cs_recheck=: ;; + --version | --versio | --versi | --vers | --ver | --ve | --v | -V ) + $as_echo "$ac_cs_version"; exit ;; + --config | --confi | --conf | --con | --co | --c ) + $as_echo "$ac_cs_config"; exit ;; + --debug | --debu | --deb | --de | --d | -d ) + debug=: ;; + --file | --fil | --fi | --f ) + $ac_shift + case $ac_optarg in + *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; + '') as_fn_error $? "missing file argument" ;; + esac + as_fn_append CONFIG_FILES " '$ac_optarg'" + ac_need_defaults=false;; + --header | --heade | --head | --hea ) + $ac_shift + case $ac_optarg in + *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; + esac + as_fn_append CONFIG_HEADERS " '$ac_optarg'" + ac_need_defaults=false;; + --he | --h) + # Conflict between --help and --header + as_fn_error $? "ambiguous option: \`$1' +Try \`$0 --help' for more information.";; + --help | --hel | -h ) + $as_echo "$ac_cs_usage"; exit ;; + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil | --si | --s) + ac_cs_silent=: ;; + + # This is an error. + -*) as_fn_error $? "unrecognized option: \`$1' +Try \`$0 --help' for more information." ;; + + *) as_fn_append ac_config_targets " $1" + ac_need_defaults=false ;; + + esac + shift +done + +ac_configure_extra_args= + +if $ac_cs_silent; then + exec 6>/dev/null + ac_configure_extra_args="$ac_configure_extra_args --silent" +fi + +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +if \$ac_cs_recheck; then + set X $SHELL '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion + shift + \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6 + CONFIG_SHELL='$SHELL' + export CONFIG_SHELL + exec "\$@" +fi + +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +exec 5>>config.log +{ + echo + sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX +## Running $as_me. ## +_ASBOX + $as_echo "$ac_log" +} >&5 + +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 + +# Handling of arguments. +for ac_config_target in $ac_config_targets +do + case $ac_config_target in + "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;; + "../tests/Makefile") CONFIG_FILES="$CONFIG_FILES ../tests/Makefile" ;; + "../include/nsock_config.h") CONFIG_HEADERS="$CONFIG_HEADERS ../include/nsock_config.h" ;; + + *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;; + esac +done + + +# If the user did not use the arguments to specify the items to instantiate, +# then the envvar interface is used. Set only those that are not. +# We use the long form for the default assignment because of an extremely +# bizarre bug on SunOS 4.1.3. +if $ac_need_defaults; then + test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files + test "${CONFIG_HEADERS+set}" = set || CONFIG_HEADERS=$config_headers +fi + +# Have a temporary directory for convenience. Make it in the build tree +# simply because there is no reason against having it here, and in addition, +# creating and moving files from /tmp can sometimes cause problems. +# Hook for its removal unless debugging. +# Note that there is a small window in which the directory will not be cleaned: +# after its creation but before its name has been assigned to `$tmp'. +$debug || +{ + tmp= ac_tmp= + trap 'exit_status=$? + : "${ac_tmp:=$tmp}" + { test ! -d "$ac_tmp" || rm -fr "$ac_tmp"; } && exit $exit_status +' 0 + trap 'as_fn_exit 1' 1 2 13 15 +} +# Create a (secure) tmp directory for tmp files. + +{ + tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` && + test -d "$tmp" +} || +{ + tmp=./conf$$-$RANDOM + (umask 077 && mkdir "$tmp") +} || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5 +ac_tmp=$tmp + +# Set up the scripts for CONFIG_FILES section. +# No need to generate them if there are no CONFIG_FILES. +# This happens for instance with `./config.status config.h'. +if test -n "$CONFIG_FILES"; then + + +ac_cr=`echo X | tr X '\015'` +# On cygwin, bash can eat \r inside `` if the user requested igncr. +# But we know of no other shell where ac_cr would be empty at this +# point, so we can use a bashism as a fallback. +if test "x$ac_cr" = x; then + eval ac_cr=\$\'\\r\' +fi +ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' </dev/null 2>/dev/null` +if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then + ac_cs_awk_cr='\\r' +else + ac_cs_awk_cr=$ac_cr +fi + +echo 'BEGIN {' >"$ac_tmp/subs1.awk" && +_ACEOF + + +{ + echo "cat >conf$$subs.awk <<_ACEOF" && + echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' && + echo "_ACEOF" +} >conf$$subs.sh || + as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 +ac_delim_num=`echo "$ac_subst_vars" | grep -c '^'` +ac_delim='%!_!# ' +for ac_last_try in false false false false false :; do + . ./conf$$subs.sh || + as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 + + ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X` + if test $ac_delim_n = $ac_delim_num; then + break + elif $ac_last_try; then + as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 + else + ac_delim="$ac_delim!$ac_delim _$ac_delim!! " + fi +done +rm -f conf$$subs.sh + +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +cat >>"\$ac_tmp/subs1.awk" <<\\_ACAWK && +_ACEOF +sed -n ' +h +s/^/S["/; s/!.*/"]=/ +p +g +s/^[^!]*!// +:repl +t repl +s/'"$ac_delim"'$// +t delim +:nl +h +s/\(.\{148\}\)..*/\1/ +t more1 +s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/ +p +n +b repl +:more1 +s/["\\]/\\&/g; s/^/"/; s/$/"\\/ +p +g +s/.\{148\}// +t nl +:delim +h +s/\(.\{148\}\)..*/\1/ +t more2 +s/["\\]/\\&/g; s/^/"/; s/$/"/ +p +b +:more2 +s/["\\]/\\&/g; s/^/"/; s/$/"\\/ +p +g +s/.\{148\}// +t delim +' <conf$$subs.awk | sed ' +/^[^""]/{ + N + s/\n// +} +' >>$CONFIG_STATUS || ac_write_fail=1 +rm -f conf$$subs.awk +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +_ACAWK +cat >>"\$ac_tmp/subs1.awk" <<_ACAWK && + for (key in S) S_is_set[key] = 1 + FS = "" + +} +{ + line = $ 0 + nfields = split(line, field, "@") + substed = 0 + len = length(field[1]) + for (i = 2; i < nfields; i++) { + key = field[i] + keylen = length(key) + if (S_is_set[key]) { + value = S[key] + line = substr(line, 1, len) "" value "" substr(line, len + keylen + 3) + len += length(value) + length(field[++i]) + substed = 1 + } else + len += 1 + keylen + } + + print line +} + +_ACAWK +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then + sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g" +else + cat +fi < "$ac_tmp/subs1.awk" > "$ac_tmp/subs.awk" \ + || as_fn_error $? "could not setup config files machinery" "$LINENO" 5 +_ACEOF + +# VPATH may cause trouble with some makes, so we remove sole $(srcdir), +# ${srcdir} and @srcdir@ entries from VPATH if srcdir is ".", strip leading and +# trailing colons and then remove the whole line if VPATH becomes empty +# (actually we leave an empty line to preserve line numbers). +if test "x$srcdir" = x.; then + ac_vpsub='/^[ ]*VPATH[ ]*=[ ]*/{ +h +s/// +s/^/:/ +s/[ ]*$/:/ +s/:\$(srcdir):/:/g +s/:\${srcdir}:/:/g +s/:@srcdir@:/:/g +s/^:*// +s/:*$// +x +s/\(=[ ]*\).*/\1/ +G +s/\n// +s/^[^=]*=[ ]*$// +}' +fi + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +fi # test -n "$CONFIG_FILES" + +# Set up the scripts for CONFIG_HEADERS section. +# No need to generate them if there are no CONFIG_HEADERS. +# This happens for instance with `./config.status Makefile'. +if test -n "$CONFIG_HEADERS"; then +cat >"$ac_tmp/defines.awk" <<\_ACAWK || +BEGIN { +_ACEOF + +# Transform confdefs.h into an awk script `defines.awk', embedded as +# here-document in config.status, that substitutes the proper values into +# config.h.in to produce config.h. + +# Create a delimiter string that does not exist in confdefs.h, to ease +# handling of long lines. +ac_delim='%!_!# ' +for ac_last_try in false false :; do + ac_tt=`sed -n "/$ac_delim/p" confdefs.h` + if test -z "$ac_tt"; then + break + elif $ac_last_try; then + as_fn_error $? "could not make $CONFIG_HEADERS" "$LINENO" 5 + else + ac_delim="$ac_delim!$ac_delim _$ac_delim!! " + fi +done + +# For the awk script, D is an array of macro values keyed by name, +# likewise P contains macro parameters if any. Preserve backslash +# newline sequences. + +ac_word_re=[_$as_cr_Letters][_$as_cr_alnum]* +sed -n ' +s/.\{148\}/&'"$ac_delim"'/g +t rset +:rset +s/^[ ]*#[ ]*define[ ][ ]*/ / +t def +d +:def +s/\\$// +t bsnl +s/["\\]/\\&/g +s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\ +D["\1"]=" \3"/p +s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2"/p +d +:bsnl +s/["\\]/\\&/g +s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\ +D["\1"]=" \3\\\\\\n"\\/p +t cont +s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2\\\\\\n"\\/p +t cont +d +:cont +n +s/.\{148\}/&'"$ac_delim"'/g +t clear +:clear +s/\\$// +t bsnlc +s/["\\]/\\&/g; s/^/"/; s/$/"/p +d +:bsnlc +s/["\\]/\\&/g; s/^/"/; s/$/\\\\\\n"\\/p +b cont +' <confdefs.h | sed ' +s/'"$ac_delim"'/"\\\ +"/g' >>$CONFIG_STATUS || ac_write_fail=1 + +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 + for (key in D) D_is_set[key] = 1 + FS = "" +} +/^[\t ]*#[\t ]*(define|undef)[\t ]+$ac_word_re([\t (]|\$)/ { + line = \$ 0 + split(line, arg, " ") + if (arg[1] == "#") { + defundef = arg[2] + mac1 = arg[3] + } else { + defundef = substr(arg[1], 2) + mac1 = arg[2] + } + split(mac1, mac2, "(") #) + macro = mac2[1] + prefix = substr(line, 1, index(line, defundef) - 1) + if (D_is_set[macro]) { + # Preserve the white space surrounding the "#". + print prefix "define", macro P[macro] D[macro] + next + } else { + # Replace #undef with comments. This is necessary, for example, + # in the case of _POSIX_SOURCE, which is predefined and required + # on some systems where configure will not decide to define it. + if (defundef == "undef") { + print "/*", prefix defundef, macro, "*/" + next + } + } +} +{ print } +_ACAWK +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 + as_fn_error $? "could not setup config headers machinery" "$LINENO" 5 +fi # test -n "$CONFIG_HEADERS" + + +eval set X " :F $CONFIG_FILES :H $CONFIG_HEADERS " +shift +for ac_tag +do + case $ac_tag in + :[FHLC]) ac_mode=$ac_tag; continue;; + esac + case $ac_mode$ac_tag in + :[FHL]*:*);; + :L* | :C*:*) as_fn_error $? "invalid tag \`$ac_tag'" "$LINENO" 5;; + :[FH]-) ac_tag=-:-;; + :[FH]*) ac_tag=$ac_tag:$ac_tag.in;; + esac + ac_save_IFS=$IFS + IFS=: + set x $ac_tag + IFS=$ac_save_IFS + shift + ac_file=$1 + shift + + case $ac_mode in + :L) ac_source=$1;; + :[FH]) + ac_file_inputs= + for ac_f + do + case $ac_f in + -) ac_f="$ac_tmp/stdin";; + *) # Look for the file first in the build tree, then in the source tree + # (if the path is not absolute). The absolute path cannot be DOS-style, + # because $ac_f cannot contain `:'. + test -f "$ac_f" || + case $ac_f in + [\\/$]*) false;; + *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";; + esac || + as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5;; + esac + case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac + as_fn_append ac_file_inputs " '$ac_f'" + done + + # Let's still pretend it is `configure' which instantiates (i.e., don't + # use $as_me), people would be surprised to read: + # /* config.h. Generated by config.status. */ + configure_input='Generated from '` + $as_echo "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g' + `' by configure.' + if test x"$ac_file" != x-; then + configure_input="$ac_file. $configure_input" + { $as_echo "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5 +$as_echo "$as_me: creating $ac_file" >&6;} + fi + # Neutralize special characters interpreted by sed in replacement strings. + case $configure_input in #( + *\&* | *\|* | *\\* ) + ac_sed_conf_input=`$as_echo "$configure_input" | + sed 's/[\\\\&|]/\\\\&/g'`;; #( + *) ac_sed_conf_input=$configure_input;; + esac + + case $ac_tag in + *:-:* | *:-) cat >"$ac_tmp/stdin" \ + || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;; + esac + ;; + esac + + ac_dir=`$as_dirname -- "$ac_file" || +$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$ac_file" : 'X\(//\)[^/]' \| \ + X"$ac_file" : 'X\(//\)$' \| \ + X"$ac_file" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$ac_file" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + as_dir="$ac_dir"; as_fn_mkdir_p + ac_builddir=. + +case "$ac_dir" in +.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; +*) + ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` + # A ".." for each directory in $ac_dir_suffix. + ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` + case $ac_top_builddir_sub in + "") ac_top_builddir_sub=. ac_top_build_prefix= ;; + *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; + esac ;; +esac +ac_abs_top_builddir=$ac_pwd +ac_abs_builddir=$ac_pwd$ac_dir_suffix +# for backward compatibility: +ac_top_builddir=$ac_top_build_prefix + +case $srcdir in + .) # We are building in place. + ac_srcdir=. + ac_top_srcdir=$ac_top_builddir_sub + ac_abs_top_srcdir=$ac_pwd ;; + [\\/]* | ?:[\\/]* ) # Absolute name. + ac_srcdir=$srcdir$ac_dir_suffix; + ac_top_srcdir=$srcdir + ac_abs_top_srcdir=$srcdir ;; + *) # Relative name. + ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix + ac_top_srcdir=$ac_top_build_prefix$srcdir + ac_abs_top_srcdir=$ac_pwd/$srcdir ;; +esac +ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix + + + case $ac_mode in + :F) + # + # CONFIG_FILE + # + +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +# If the template does not know about datarootdir, expand it. +# FIXME: This hack should be removed a few years after 2.60. +ac_datarootdir_hack=; ac_datarootdir_seen= +ac_sed_dataroot=' +/datarootdir/ { + p + q +} +/@datadir@/p +/@docdir@/p +/@infodir@/p +/@localedir@/p +/@mandir@/p' +case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in +*datarootdir*) ac_datarootdir_seen=yes;; +*@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*) + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5 +$as_echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;} +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 + ac_datarootdir_hack=' + s&@datadir@&$datadir&g + s&@docdir@&$docdir&g + s&@infodir@&$infodir&g + s&@localedir@&$localedir&g + s&@mandir@&$mandir&g + s&\\\${datarootdir}&$datarootdir&g' ;; +esac +_ACEOF + +# Neutralize VPATH when `$srcdir' = `.'. +# Shell code in configure.ac might set extrasub. +# FIXME: do we really want to maintain this feature? +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +ac_sed_extra="$ac_vpsub +$extrasub +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +:t +/@[a-zA-Z_][a-zA-Z_0-9]*@/!b +s|@configure_input@|$ac_sed_conf_input|;t t +s&@top_builddir@&$ac_top_builddir_sub&;t t +s&@top_build_prefix@&$ac_top_build_prefix&;t t +s&@srcdir@&$ac_srcdir&;t t +s&@abs_srcdir@&$ac_abs_srcdir&;t t +s&@top_srcdir@&$ac_top_srcdir&;t t +s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t +s&@builddir@&$ac_builddir&;t t +s&@abs_builddir@&$ac_abs_builddir&;t t +s&@abs_top_builddir@&$ac_abs_top_builddir&;t t +$ac_datarootdir_hack +" +eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$ac_tmp/subs.awk" \ + >$ac_tmp/out || as_fn_error $? "could not create $ac_file" "$LINENO" 5 + +test -z "$ac_datarootdir_hack$ac_datarootdir_seen" && + { ac_out=`sed -n '/\${datarootdir}/p' "$ac_tmp/out"`; test -n "$ac_out"; } && + { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' \ + "$ac_tmp/out"`; test -z "$ac_out"; } && + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir' +which seems to be undefined. Please make sure it is defined" >&5 +$as_echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir' +which seems to be undefined. Please make sure it is defined" >&2;} + + rm -f "$ac_tmp/stdin" + case $ac_file in + -) cat "$ac_tmp/out" && rm -f "$ac_tmp/out";; + *) rm -f "$ac_file" && mv "$ac_tmp/out" "$ac_file";; + esac \ + || as_fn_error $? "could not create $ac_file" "$LINENO" 5 + ;; + :H) + # + # CONFIG_HEADER + # + if test x"$ac_file" != x-; then + { + $as_echo "/* $configure_input */" \ + && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" + } >"$ac_tmp/config.h" \ + || as_fn_error $? "could not create $ac_file" "$LINENO" 5 + if diff "$ac_file" "$ac_tmp/config.h" >/dev/null 2>&1; then + { $as_echo "$as_me:${as_lineno-$LINENO}: $ac_file is unchanged" >&5 +$as_echo "$as_me: $ac_file is unchanged" >&6;} + else + rm -f "$ac_file" + mv "$ac_tmp/config.h" "$ac_file" \ + || as_fn_error $? "could not create $ac_file" "$LINENO" 5 + fi + else + $as_echo "/* $configure_input */" \ + && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" \ + || as_fn_error $? "could not create -" "$LINENO" 5 + fi + ;; + + + esac + +done # for ac_tag + + +as_fn_exit 0 +_ACEOF +ac_clean_files=$ac_clean_files_save + +test $ac_write_fail = 0 || + as_fn_error $? "write failure creating $CONFIG_STATUS" "$LINENO" 5 + + +# configure is writing to config.log, and then calls config.status. +# config.status does its own redirection, appending to config.log. +# Unfortunately, on DOS this fails, as config.log is still kept open +# by configure, so config.status won't be able to write to it; its +# output is simply discarded. So we exec the FD to /dev/null, +# effectively closing config.log, so it can be properly (re)opened and +# appended to by config.status. When coming back to configure, we +# need to make the FD available again. +if test "$no_create" != yes; then + ac_cs_success=: + ac_config_status_args= + test "$silent" = yes && + ac_config_status_args="$ac_config_status_args --quiet" + exec 5>/dev/null + $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false + exec 5>>config.log + # Use ||, not &&, to avoid exiting from the if with $? = 1, which + # would make configure fail if this is the last instruction. + $ac_cs_success || as_fn_exit 1 +fi +if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5 +$as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;} +fi + diff --git a/nsock/src/configure.ac b/nsock/src/configure.ac new file mode 100644 index 0000000..1f035cf --- /dev/null +++ b/nsock/src/configure.ac @@ -0,0 +1,317 @@ +# Require autoconf 2.13 -*- mode: fundamental; -*- + +# Because nsock is usually distributed with Nmap, the necessary files +# config.guess, config.guess, and install-sh are not distributed with +# nbase. Rather they are gotten from Nmap. + +AC_PREREQ(2.13) + +dnl Process this file with autoconf to produce a configure script. +AC_INIT(nsock_core.c) + +dnl Find the Nmap source for nbase, etc. +if test "${top_nmap_srcdir+set}" != set; then + top_nmap_srcdir=../.. + export top_nmap_srcdir +fi + +dnl Generate these files +AC_CONFIG_FILES([Makefile ../tests/Makefile]) + +dnl use nsock_config.h instad of -D macros +AC_CONFIG_HEADER(../include/nsock_config.h) + +dnl Host specific hacks +AC_CANONICAL_HOST + +AH_TEMPLATE(SOLARIS, [Sun/Oracle Solaris]) +AH_TEMPLATE(IRIX, [IRIX]) + +case "$host" in + *alpha-dec-osf*) + AC_DEFINE(DEC, 1, [DEC Alpha]) + ;; + *-netbsd* | *-knetbsd*-gnu) + AC_DEFINE(NETBSD, 1, [NetBSD]) + ;; + *-openbsd*) + AC_DEFINE(OPENBSD, 1, [OpenBSD]) + ;; + *-sgi-irix5*) + AC_DEFINE(IRIX) + ;; + *-sgi-irix6*) + AC_DEFINE(IRIX) + ;; + *-hpux*) + AC_DEFINE(HPUX, 1, [HP-UX]) + ;; + *-solaris2.1[[1-9]]*) + AC_DEFINE(SOLARIS) + # Solaris 11 and later use BPF packet capture rather than DLPI. + AC_DEFINE(SOLARIS_BPF_PCAP_CAPTURE, 1, [BPF packet capture on Solaris]) + ;; + *-solaris2.0*) + AC_DEFINE(SOLARIS) + ;; + *-solaris2.[[1-9]][[0-9]]*) + AC_DEFINE(SOLARIS) + ;; + *-solaris2.1*) + AC_DEFINE(SOLARIS) + ;; + *-solaris2.2*) + AC_DEFINE(SOLARIS) + ;; + *-solaris2.3*) + AC_DEFINE(SOLARIS) + ;; + *-solaris2.4*) + AC_DEFINE(SOLARIS) + ;; + *-solaris2.5.1) + AC_DEFINE(SOLARIS) + ;; + *-solaris*) + AC_DEFINE(SOLARIS) + ;; + *-sunos4*) + AC_DEFINE(SUNOS, 1, [SunOS 4]) + ;; + *-linux*) + AC_DEFINE(LINUX, 1, [Linux]) + ;; + *-freebsd* | *-kfreebsd*-gnu | *-dragonfly*) + AC_DEFINE(FREEBSD, 1, [FreeBSD]) + ;; + *-bsdi*) + AC_DEFINE(BSDI, 1, [BSD/OS]) + ;; + *-apple-darwin*) + AC_DEFINE(MACOSX, 1, [Apple OS X]) + ;; +esac + + +AC_ARG_WITH(localdirs, + [ --with-localdirs Explicitly ask compiler to use /usr/local/{include,libs} if they exist ], + [ case "$with_localdirs" in + yes) + user_localdirs=1 + ;; + no) + user_localdirs=0 + ;; + esac + ], + [ user_localdirs=0 ] ) + +if test "$user_localdirs" = 1; then + if test -d /usr/local/lib; then + LDFLAGS="$LDFLAGS -L/usr/local/lib" + fi + if test -d /usr/local/include; then + CPPFLAGS="$CPPFLAGS -I/usr/local/include" + fi +fi + +dnl Check whether libpcap is already available +have_libpcap=no + +# By default, search for pcap library +test "${with_libpcap+set}" != "set" && with_libpcap=yes + +AC_ARG_WITH(libpcap, +AC_HELP_STRING([--with-libpcap=DIR], [Look for pcap headers in DIR/include.]) +AC_HELP_STRING([--with-libpcap=included], [Always use version included with Nmap]) +AC_HELP_STRING([--without-libpcap], [Disable pcap functions.]), +[ case "$with_libpcap" in + yes) + AC_CHECK_HEADER(pcap.h,[ + have_libpcap=yes + LIBPCAP_LIBS=-lpcap ]) + ;; + included) + have_libpcap=no + ;; + no) + ;; + *) + _cppflags=$CPPFLAGS + _ldflags=$LDFLAGS + + CPPFLAGS="-I$with_libpcap/include $CPPFLAGS" + LDFLAGS="-L$with_libpcap/lib $LDFLAGS" + + AC_CHECK_HEADER(pcap.h,[ + AC_CHECK_LIB(pcap, pcap_create, + [have_libpcap=yes + LIBPCAP_LIBS=-lpcap + LIBPCAP_INC=$with_libpcap/include + LIBPCAP_LIB=$with_libpcap/lib])]) + + LDFLAGS=$_ldflags + CPPFLAGS=$_cppflags + ;; + esac] +) + +if test "$with_libpcap" != "no" -a "$have_libpcap" = "no"; then + LIBPCAP_INC=${top_nmap_srcdir}/libpcap + LIBPCAP_LIB=${top_nmap_srcdir}/libpcap + LIBPCAP_LIBS=${LIBPCAP_LIB}/libpcap.a + have_libpcap=yes + AC_DEFINE(HAVE_PCAP_SET_IMMEDIATE_MODE, 1, [Included libpcap has pcap_set_immediate_mode]) +else + # link with -lpcap for the purposes of this test + LIBS_OLD="$LIBS" + LIBS="$LIBS -lpcap" + AC_CHECK_FUNCS([pcap_set_immediate_mode]) + # Restore libs + LIBS="$LIBS_OLD" +fi + +if test "$have_libpcap" != "no"; then + AC_DEFINE(HAVE_PCAP, 1, [libpcap is available]) + if test "${LIBPCAP_INC+set}" = "set"; then + CPPFLAGS="-I$LIBPCAP_INC $CPPFLAGS" + LDFLAGS="-L$LIBPCAP_LIB $LDFLAGS" + fi +fi +AC_SUBST(LIBPCAP_LIBS) + +AX_HAVE_EPOLL([AC_DEFINE(HAVE_EPOLL, 1, [epoll is available])], ) +AX_HAVE_POLL([AC_DEFINE(HAVE_POLL, 1, [poll is available])], ) +AC_CHECK_FUNCS(kqueue kevent, [AC_DEFINE(HAVE_KQUEUE)], ) + +dnl Checks for programs. +AC_PROG_CC + if test -n "$GCC"; then + CFLAGS="$CFLAGS -Wall " + fi +AC_PROG_RANLIB +dnl AC_PROG_INSTALL +dnl AC_PATH_PROG(MAKEDEPEND, makedepend) + +dnl Checks for libraries. +dnl AC_CHECK_LIB(m, pow) + +dnl If any socket libraries needed +AC_CHECK_FUNC(gethostent, , AC_CHECK_LIB(nsl, gethostent)) +AC_CHECK_FUNC(setsockopt, , AC_CHECK_LIB(socket, setsockopt)) + +dnl need posix4/nanosleep for solaris 2.4 +AC_CHECK_FUNC(nanosleep, , AC_CHECK_LIB(posix4, nanosleep)) + +dnl Checks for header files. +AC_HEADER_STDC +AC_CHECK_HEADERS(net/bpf.h sys/ioctl.h sys/un.h netdb.h) +AC_CHECK_HEADERS([linux/vm_sockets.h], , , [#include <sys/socket.h>]) + +# We test whether they specified openssl desires explicitly +use_openssl="yes" +specialssldir="" +AC_ARG_WITH(openssl, +AC_HELP_STRING([--with-openssl=DIR],[Use optional openssl libs and includes from [DIR]/lib/ and [DIR]/include/openssl/)]), +[ case "$with_openssl" in + yes) + ;; + no) + use_openssl="no" + ;; + *) + specialssldir="$with_openssl" + CPPFLAGS="$CPPFLAGS -I$with_openssl/include" + LDFLAGS="$LDFLAGS -L$with_openssl/lib" + ;; + esac] +) + +# If they didn't specify it, we try to find it +if test "$use_openssl" = "yes" -a -z "$specialssldir"; then + AC_CHECK_HEADER(openssl/ssl.h,, + [ use_openssl="no" + if test "$with_openssl" = "yes"; then + AC_MSG_ERROR([OpenSSL was explicitly requested but openssl/ssl.h was not found. Try the --with-openssl=DIR argument to give the location of OpenSSL or run configure with --without-openssl.]) + fi + AC_MSG_WARN([Failed to find openssl/ssl.h so OpenSSL will not be used. If it is installed you can try the --with-openssl=DIR argument]) + ]) + +# use_openssl="yes" given explicitly in next 2 rules to avoid adding lib to $LIBS + if test "$use_openssl" = "yes"; then + AC_CHECK_LIB(crypto, BIO_int_ctrl, + [ use_openssl="yes"], + [ use_openssl="no" + if test "$with_openssl" = "yes"; then + AC_MSG_ERROR([OpenSSL was explicitly requested but libcrypto was not found. Try the --with-openssl=DIR argument to give the location of OpenSSL or run configure with --without-openssl.]) + fi + AC_MSG_WARN([Failed to find libcrypto so OpenSSL will not be used. If it is installed you can try the --with-openssl=DIR argument]) + ]) + fi + + if test "$use_openssl" = "yes"; then + AC_CHECK_LIB(ssl, SSL_new, + [ use_openssl="yes" ], + [ use_openssl="no" + if test "$with_openssl" = "yes"; then + AC_MSG_ERROR([OpenSSL was explicitly requested but libssl was not found. Try the --with-openssl=DIR argument to give the location of OpenSSL or run configure with --without-openssl.]) + fi + AC_MSG_WARN([Failed to find libssl so OpenSSL will not be used. If it is installed you can try the --with-openssl=DIR argument]) ], + [ -lcrypto ]) + fi +fi + +# OpenSSL requires dlopen on some platforms +AC_SEARCH_LIBS(dlopen, dl) + +OPENSSL_LIBS= +if test "$use_openssl" = "yes"; then + AC_DEFINE(HAVE_OPENSSL, 1, [openssl is available]) + OPENSSL_LIBS="-lssl -lcrypto" + LIBS_TMP="$LIBS" + LIBS="$OPENSSL_LIBS $LIBS" + AC_MSG_CHECKING([for SSL_set_tlsext_host_name]) + AC_TRY_LINK([#include <openssl/ssl.h>], [SSL_set_tlsext_host_name(NULL, NULL)], + [AC_MSG_RESULT([yes]); AC_DEFINE(HAVE_SSL_SET_TLSEXT_HOST_NAME, 1, [SSL_set_tlsext_host_name available])], + [AC_MSG_RESULT([no])]) + AC_MSG_CHECKING([for DTLS_client_method]) + AC_TRY_LINK([#include <openssl/ssl.h>], [DTLS_client_method()], + [AC_MSG_RESULT([yes]); AC_DEFINE(HAVE_DTLS_CLIENT_METHOD, 1, [DTLS_client_method available])], + [AC_MSG_RESULT([no])]) + AC_MSG_CHECKING([for SSL_set_alpn_protos]) + AC_TRY_LINK([#include <openssl/ssl.h>], [SSL_set_alpn_protos(NULL, NULL, 0)], + [AC_MSG_RESULT([yes]); AC_DEFINE(HAVE_ALPN_SUPPORT, 1, [SSL ALPN protos support])], + [AC_MSG_RESULT([no])]) + LIBS="$LIBS_TMP" + +fi + +AC_SUBST(OPENSSL_LIBS) + +dnl Checks for typedefs, structures, and compiler characteristics. + +AC_ARG_WITH(libnbase, +[ --with-libnbase=DIR Look for nbase include/libs in DIR], +[ case "$with_libnbase" in + yes) + ;; + *) + NBASEDIR="$with_libnbase" + ;; + esac], +NBASEDIR="${top_nmap_srcdir}/nbase" +) + +NSOCKTESTDIR="../tests" + +LDFLAGS="$LDFLAGS -L$NBASEDIR" +CPPFLAGS="$CPPFLAGS -I$NBASEDIR" +LIBNBASE_LIBS="$LIBS -lnbase" + +AC_SUBST(LIBNBASE_LIBS) +AC_SUBST(NBASEDIR) +AC_SUBST(NSOCKTESTDIR) + +AC_SUBST(CFLAGS) + +AC_OUTPUT() diff --git a/nsock/src/engine_epoll.c b/nsock/src/engine_epoll.c new file mode 100644 index 0000000..1bc285c --- /dev/null +++ b/nsock/src/engine_epoll.c @@ -0,0 +1,354 @@ +/*************************************************************************** + * engine_epoll.c -- epoll(7) based IO engine. * + * * + ***********************IMPORTANT NSOCK LICENSE TERMS*********************** + * + * The nsock parallel socket event library is (C) 1999-2023 Nmap Software LLC + * This library is free software; you may redistribute and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation; Version 2. This guarantees your right to use, modify, and + * redistribute this software under certain conditions. If this license is + * unacceptable to you, Nmap Software LLC may be willing to sell alternative + * licenses (contact sales@nmap.com ). + * + * As a special exception to the GPL terms, Nmap Software LLC grants permission + * to link the code of this program with any version of the OpenSSL library + * which is distributed under a license identical to that listed in the included + * docs/licenses/OpenSSL.txt file, and distribute linked combinations including + * the two. You must obey the GNU GPL in all respects for all of the code used + * other than OpenSSL. If you modify this file, you may extend this exception to + * your version of the file, but you are not obligated to do so. + * + * If you received these files with a written license agreement stating terms + * other than the (GPL) terms above, then that alternative license agreement + * takes precedence over this comment. + * + * Source is provided to this software because we believe users have a right to + * know exactly what a program is going to do before they run it. This also + * allows you to audit the software for security holes. + * + * Source code also allows you to port Nmap to new platforms, fix bugs, and add + * new features. You are highly encouraged to send your changes to the + * dev@nmap.org mailing list for possible incorporation into the main + * distribution. By sending these changes to Fyodor or one of the Insecure.Org + * development mailing lists, or checking them into the Nmap source code + * repository, it is understood (unless you specify otherwise) that you are + * offering the Nmap Project (Nmap Software LLC) the unlimited, non-exclusive + * right to reuse, modify, and relicense the code. Nmap will always be available + * Open Source, but this is important because the inability to relicense code + * has caused devastating problems for other Free Software projects (such as KDE + * and NASM). We also occasionally relicense the code to third parties as + * discussed above. If you wish to specify special license conditions of your + * contributions, just say so when you send them. + * + * 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 v2.0 for more + * details (http://www.gnu.org/licenses/gpl-2.0.html). + * + ***************************************************************************/ + +/* $Id$ */ + +#ifdef HAVE_CONFIG_H +#include "nsock_config.h" +#endif + +#if HAVE_EPOLL + +#include <sys/epoll.h> +#include <errno.h> + +#include "nsock_internal.h" +#include "nsock_log.h" + +#if HAVE_PCAP +#include "nsock_pcap.h" +#endif + +#define INITIAL_EV_COUNT 128 + +#define EPOLL_R_FLAGS (EPOLLIN | EPOLLPRI) +#define EPOLL_W_FLAGS EPOLLOUT + +/* EPOLLRDHUP was introduced later and might be unavailable on older systems. */ +#ifndef EPOLLRDHUP + #define EPOLLRDHUP 0 +#endif +#define EPOLL_X_FLAGS (EPOLLERR | EPOLLRDHUP| EPOLLHUP) + + +/* --- ENGINE INTERFACE PROTOTYPES --- */ +static int epoll_init(struct npool *nsp); +static void epoll_destroy(struct npool *nsp); +static int epoll_iod_register(struct npool *nsp, struct niod *iod, struct nevent *nse, int ev); +static int epoll_iod_unregister(struct npool *nsp, struct niod *iod); +static int epoll_iod_modify(struct npool *nsp, struct niod *iod, struct nevent *nse, int ev_set, int ev_clr); +static int epoll_loop(struct npool *nsp, int msec_timeout); + +extern struct io_operations posix_io_operations; + +/* ---- ENGINE DEFINITION ---- */ +struct io_engine engine_epoll = { + "epoll", + epoll_init, + epoll_destroy, + epoll_iod_register, + epoll_iod_unregister, + epoll_iod_modify, + epoll_loop, + &posix_io_operations +}; + + +/* --- INTERNAL PROTOTYPES --- */ +static void iterate_through_event_lists(struct npool *nsp, int evcount); + +/* defined in nsock_core.c */ +void process_iod_events(struct npool *nsp, struct niod *nsi, int ev); +void process_event(struct npool *nsp, gh_list_t *evlist, struct nevent *nse, int ev); +void process_expired_events(struct npool *nsp); +#if HAVE_PCAP +#ifndef PCAP_CAN_DO_SELECT +int pcap_read_on_nonselect(struct npool *nsp); +#endif +#endif + +/* defined in nsock_event.c */ +void update_first_events(struct nevent *nse); + + +extern struct timeval nsock_tod; + + +/* + * Engine specific data structure + */ +struct epoll_engine_info { + /* file descriptor corresponding to our epoll instance */ + int epfd; + /* number of epoll_events we can deal with */ + int evlen; + /* list of epoll events, resized if necessary (when polling over large numbers of IODs) */ + struct epoll_event *events; +}; + + +int epoll_init(struct npool *nsp) { + struct epoll_engine_info *einfo; + + einfo = (struct epoll_engine_info *)safe_malloc(sizeof(struct epoll_engine_info)); + + einfo->epfd = epoll_create(10); /* argument is ignored */ + einfo->evlen = INITIAL_EV_COUNT; + einfo->events = (struct epoll_event *)safe_malloc(einfo->evlen * sizeof(struct epoll_event)); + + nsp->engine_data = (void *)einfo; + + return 1; +} + +void epoll_destroy(struct npool *nsp) { + struct epoll_engine_info *einfo = (struct epoll_engine_info *)nsp->engine_data; + + assert(einfo != NULL); + close(einfo->epfd); + free(einfo->events); + free(einfo); +} + +int epoll_iod_register(struct npool *nsp, struct niod *iod, struct nevent *nse, int ev) { + int sd; + struct epoll_event epev; + struct epoll_engine_info *einfo = (struct epoll_engine_info *)nsp->engine_data; + + assert(!IOD_PROPGET(iod, IOD_REGISTERED)); + + iod->watched_events = ev; + + memset(&epev, 0x00, sizeof(struct epoll_event)); + epev.events = EPOLLET; + epev.data.ptr = (void *)iod; + + if (ev & EV_READ) + epev.events |= EPOLL_R_FLAGS; + if (ev & EV_WRITE) + epev.events |= EPOLL_W_FLAGS; + + sd = nsock_iod_get_sd(iod); + if (epoll_ctl(einfo->epfd, EPOLL_CTL_ADD, sd, &epev) < 0) + fatal("Unable to register IOD #%lu: %s", iod->id, strerror(errno)); + + IOD_PROPSET(iod, IOD_REGISTERED); + return 1; +} + +int epoll_iod_unregister(struct npool *nsp, struct niod *iod) { + iod->watched_events = EV_NONE; + + /* some IODs can be unregistered here if they're associated to an event that was + * immediately completed */ + if (IOD_PROPGET(iod, IOD_REGISTERED)) { + struct epoll_engine_info *einfo = (struct epoll_engine_info *)nsp->engine_data; + int sd; + + sd = nsock_iod_get_sd(iod); + epoll_ctl(einfo->epfd, EPOLL_CTL_DEL, sd, NULL); + + IOD_PROPCLR(iod, IOD_REGISTERED); + } + return 1; +} + +int epoll_iod_modify(struct npool *nsp, struct niod *iod, struct nevent *nse, int ev_set, int ev_clr) { + int sd; + struct epoll_event epev; + int new_events; + struct epoll_engine_info *einfo = (struct epoll_engine_info *)nsp->engine_data; + + assert((ev_set & ev_clr) == 0); + assert(IOD_PROPGET(iod, IOD_REGISTERED)); + + memset(&epev, 0x00, sizeof(struct epoll_event)); + epev.events = EPOLLET; + epev.data.ptr = (void *)iod; + + new_events = iod->watched_events; + new_events |= ev_set; + new_events &= ~ev_clr; + + if (new_events == iod->watched_events) + return 1; /* nothing to do */ + + iod->watched_events = new_events; + + /* regenerate the current set of events for this IOD */ + if (iod->watched_events & EV_READ) + epev.events |= EPOLL_R_FLAGS; + if (iod->watched_events & EV_WRITE) + epev.events |= EPOLL_W_FLAGS; + + sd = nsock_iod_get_sd(iod); + + if (epoll_ctl(einfo->epfd, EPOLL_CTL_MOD, sd, &epev) < 0) + fatal("Unable to update events for IOD #%lu: %s", iod->id, strerror(errno)); + + return 1; +} + +int epoll_loop(struct npool *nsp, int msec_timeout) { + int results_left = 0; + int event_msecs; /* msecs before an event goes off */ + int combined_msecs; + int sock_err = 0; + unsigned int iod_count; + struct epoll_engine_info *einfo = (struct epoll_engine_info *)nsp->engine_data; + + assert(msec_timeout >= -1); + + if (nsp->events_pending == 0) + return 0; /* No need to wait on 0 events ... */ + + + iod_count = gh_list_count(&nsp->active_iods); + if (iod_count > einfo->evlen) { + einfo->evlen = iod_count * 2; + einfo->events = (struct epoll_event *)safe_realloc(einfo->events, einfo->evlen * sizeof(struct epoll_event)); + } + + do { + struct nevent *nse; + + nsock_log_debug_all("wait for events"); + + nse = next_expirable_event(nsp); + if (!nse) + event_msecs = -1; /* None of the events specified a timeout */ + else + event_msecs = MAX(0, TIMEVAL_MSEC_SUBTRACT(nse->timeout, nsock_tod)); + +#if HAVE_PCAP +#ifndef PCAP_CAN_DO_SELECT + /* Force a low timeout when capturing packets on systems where + * the pcap descriptor is not select()able. */ + if (gh_list_count(&nsp->pcap_read_events) > 0) + if (event_msecs > PCAP_POLL_INTERVAL) + event_msecs = PCAP_POLL_INTERVAL; +#endif +#endif + + /* We cast to unsigned because we want -1 to be very high (since it means no + * timeout) */ + combined_msecs = MIN((unsigned)event_msecs, (unsigned)msec_timeout); + +#if HAVE_PCAP +#ifndef PCAP_CAN_DO_SELECT + /* do non-blocking read on pcap devices that doesn't support select() + * If there is anything read, just leave this loop. */ + if (pcap_read_on_nonselect(nsp)) { + /* okay, something was read. */ + } else +#endif +#endif + { + results_left = epoll_wait(einfo->epfd, einfo->events, einfo->evlen, combined_msecs); + if (results_left == -1) + sock_err = socket_errno(); + } + + gettimeofday(&nsock_tod, NULL); /* Due to epoll delay */ + } while (results_left == -1 && sock_err == EINTR); /* repeat only if signal occurred */ + + if (results_left == -1 && sock_err != EINTR) { + nsock_log_error("nsock_loop error %d: %s", sock_err, socket_strerror(sock_err)); + nsp->errnum = sock_err; + return -1; + } + + iterate_through_event_lists(nsp, results_left); + + return 1; +} + + +/* ---- INTERNAL FUNCTIONS ---- */ +static inline int get_evmask(struct epoll_engine_info *einfo, int n) { + int evmask = EV_NONE; + + if (einfo->events[n].events & EPOLL_R_FLAGS) + evmask |= EV_READ; + if (einfo->events[n].events & EPOLL_W_FLAGS) + evmask |= EV_WRITE; + if (einfo->events[n].events & EPOLL_X_FLAGS) + evmask |= EV_EXCEPT; + + return evmask; +} + +/* Iterate through all the event lists (such as connect_events, read_events, + * timer_events, etc) and take action for those that have completed (due to + * timeout, i/o, etc) */ +void iterate_through_event_lists(struct npool *nsp, int evcount) { + struct epoll_engine_info *einfo = (struct epoll_engine_info *)nsp->engine_data; + int n; + + for (n = 0; n < evcount; n++) { + struct niod *nsi = (struct niod *)einfo->events[n].data.ptr; + + assert(nsi); + + /* process all the pending events for this IOD */ + process_iod_events(nsp, nsi, get_evmask(einfo, n)); + + if (nsi->state == NSIOD_STATE_DELETED) { + gh_list_remove(&nsp->active_iods, &nsi->nodeq); + gh_list_prepend(&nsp->free_iods, &nsi->nodeq); + } + } + + /* iterate through timers and expired events */ + process_expired_events(nsp); +} + +#endif /* HAVE_EPOLL */ + diff --git a/nsock/src/engine_iocp.c b/nsock/src/engine_iocp.c new file mode 100644 index 0000000..b1d4302 --- /dev/null +++ b/nsock/src/engine_iocp.c @@ -0,0 +1,788 @@ +/*************************************************************************** + * engine_iocp.c -- I/O Completion Ports based IO engine. * + * * + ***********************IMPORTANT NSOCK LICENSE TERMS*********************** + * + * The nsock parallel socket event library is (C) 1999-2023 Nmap Software LLC + * This library is free software; you may redistribute and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation; Version 2. This guarantees your right to use, modify, and + * redistribute this software under certain conditions. If this license is + * unacceptable to you, Nmap Software LLC may be willing to sell alternative + * licenses (contact sales@nmap.com ). + * + * As a special exception to the GPL terms, Nmap Software LLC grants permission + * to link the code of this program with any version of the OpenSSL library + * which is distributed under a license identical to that listed in the included + * docs/licenses/OpenSSL.txt file, and distribute linked combinations including + * the two. You must obey the GNU GPL in all respects for all of the code used + * other than OpenSSL. If you modify this file, you may extend this exception to + * your version of the file, but you are not obligated to do so. + * + * If you received these files with a written license agreement stating terms + * other than the (GPL) terms above, then that alternative license agreement + * takes precedence over this comment. + * + * Source is provided to this software because we believe users have a right to + * know exactly what a program is going to do before they run it. This also + * allows you to audit the software for security holes. + * + * Source code also allows you to port Nmap to new platforms, fix bugs, and add + * new features. You are highly encouraged to send your changes to the + * dev@nmap.org mailing list for possible incorporation into the main + * distribution. By sending these changes to Fyodor or one of the Insecure.Org + * development mailing lists, or checking them into the Nmap source code + * repository, it is understood (unless you specify otherwise) that you are + * offering the Nmap Project (Nmap Software LLC) the unlimited, non-exclusive + * right to reuse, modify, and relicense the code. Nmap will always be available + * Open Source, but this is important because the inability to relicense code + * has caused devastating problems for other Free Software projects (such as KDE + * and NASM). We also occasionally relicense the code to third parties as + * discussed above. If you wish to specify special license conditions of your + * contributions, just say so when you send them. + * + * 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 v2.0 for more + * details (http://www.gnu.org/licenses/gpl-2.0.html). + * + ***************************************************************************/ + +/* $Id$ */ + +#if WIN32 +#include "nsock_winconfig.h" +#endif + +#if HAVE_IOCP + +#include <Winsock2.h> +#include <Mswsock.h> + +#include "nsock_internal.h" +#include "nsock_log.h" + +#if HAVE_PCAP +#include "nsock_pcap.h" +#endif + + +/* --- ENGINE INTERFACE PROTOTYPES --- */ +static int iocp_init(struct npool *nsp); +static void iocp_destroy(struct npool *nsp); +static int iocp_iod_register(struct npool *nsp, struct niod *iod, struct nevent *nse, int ev); +static int iocp_iod_unregister(struct npool *nsp, struct niod *iod); +static int iocp_iod_modify(struct npool *nsp, struct niod *iod, struct nevent *nse, int ev_set, int ev_clr); +static int iocp_loop(struct npool *nsp, int msec_timeout); + +int iocp_iod_connect(struct npool *nsp, int sockfd, const struct sockaddr *addr, socklen_t addrlen); +int iocp_iod_read(struct npool *nsp, int sockfd, void *buf, size_t len, int flags, struct sockaddr *src_addr, socklen_t *addrlen); +int iocp_iod_write(struct npool *nsp, int sockfd, const void *buf, size_t len, int flags, const struct sockaddr *dest_addr, socklen_t addrlen); + +struct io_operations iocp_io_operations = { + iocp_iod_connect, + iocp_iod_read, + iocp_iod_write +}; + +/* ---- ENGINE DEFINITION ---- */ +struct io_engine engine_iocp = { + "iocp", + iocp_init, + iocp_destroy, + iocp_iod_register, + iocp_iod_unregister, + iocp_iod_modify, + iocp_loop, + &iocp_io_operations +}; + +/* +* Engine specific data structure +*/ +struct iocp_engine_info { + /* The handle to the Completion Port*/ + HANDLE iocp; + + /* We put the current eov to be processed here in order to be retrieved by nsock_core */ + struct extended_overlapped *eov; + + /* The overlapped_entry list used to retrieve completed packets from the port */ + OVERLAPPED_ENTRY *eov_list; + unsigned long capacity; + + /* How many Completion Packets we actually retreieved */ + unsigned long entries_removed; + + gh_list_t active_eovs; + gh_list_t free_eovs; +}; + +struct extended_overlapped { + /* Overlapped structure used for overlapped operations */ + OVERLAPPED ov; + + /* Did we get an error when we initiated the operation? + Put the error code here and post it to the main loop */ + int err; + + /* The event may have expired and was recycled, we can't trust + a pointer to the nevent structure to tell us the real nevent */ + nsock_event_id nse_id; + + /* A pointer to the event */ + struct nevent *nse; + + /* Needed for WSARecv/WSASend */ + WSABUF wsabuf; + + /* This is the buffer we will read data in */ + char *readbuf; + + /* The struct npool keeps track of EOVs that have been allocated so that it + * can destroy them if the msp is deleted. This pointer makes it easy to + * remove this struct extended_overlapped from the allocated list when necessary */ + gh_lnode_t nodeq; +}; + +/* --- INTERNAL PROTOTYPES --- */ +static void iterate_through_event_lists(struct npool *nsp); +static void iterate_through_pcap_events(struct npool *nsp); +static void terminate_overlapped_event(struct npool *nsp, struct nevent *nse); +static void initiate_overlapped_event(struct npool *nsp, struct nevent *nse); +static int get_overlapped_result(struct npool *nsp, int fd, const void *buffer, size_t count); +static void force_operation(struct npool *nsp, struct nevent *nse); +static void free_eov(struct npool *nsp, struct extended_overlapped *eov); +static int map_faulty_errors(int err); + +/* defined in nsock_core.c */ +void process_iod_events(struct npool *nsp, struct niod *nsi, int ev); +void process_event(struct npool *nsp, gh_list_t *evlist, struct nevent *nse, int ev); +void process_expired_events(struct npool *nsp); +#if HAVE_PCAP +#ifndef PCAP_CAN_DO_SELECT +int pcap_read_on_nonselect(struct npool *nsp); +#endif +#endif + +/* defined in nsock_event.c */ +void update_first_events(struct nevent *nse); + + +extern struct timeval nsock_tod; + +int iocp_init(struct npool *nsp) { + struct iocp_engine_info *iinfo; + + iinfo = (struct iocp_engine_info *)safe_malloc(sizeof(struct iocp_engine_info)); + + gh_list_init(&iinfo->active_eovs); + gh_list_init(&iinfo->free_eovs); + + iinfo->iocp = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, NULL, 0); + iinfo->capacity = 10; + iinfo->eov = NULL; + iinfo->entries_removed = 0; + iinfo->eov_list = (OVERLAPPED_ENTRY *)safe_malloc(iinfo->capacity * sizeof(OVERLAPPED_ENTRY)); + nsp->engine_data = (void *)iinfo; + + return 1; +} + +void iocp_destroy(struct npool *nsp) { + struct iocp_engine_info *iinfo = (struct iocp_engine_info *)nsp->engine_data; + + assert(iinfo != NULL); + + struct extended_overlapped *eov; + gh_lnode_t *current; + + while ((current = gh_list_pop(&iinfo->active_eovs))) { + eov = container_of(current, struct extended_overlapped, nodeq); + if (eov->readbuf) { + free(eov->readbuf); + eov->readbuf = NULL; + } + free(eov); + } + + while ((current = gh_list_pop(&iinfo->free_eovs))) { + eov = container_of(current, struct extended_overlapped, nodeq); + free(eov); + } + + gh_list_free(&iinfo->active_eovs); + gh_list_free(&iinfo->free_eovs); + + CloseHandle(iinfo->iocp); + free(iinfo->eov_list); + + free(iinfo); +} + +int iocp_iod_register(struct npool *nsp, struct niod *iod, struct nevent *nse, int ev) { + struct iocp_engine_info *iinfo = (struct iocp_engine_info *)nsp->engine_data; + HANDLE result; + + assert(!IOD_PROPGET(iod, IOD_REGISTERED)); + iod->watched_events = ev; + result = CreateIoCompletionPort((HANDLE)iod->sd, iinfo->iocp, NULL, 0); + assert(result); + + IOD_PROPSET(iod, IOD_REGISTERED); + + initiate_overlapped_event(nsp, nse); + + return 1; +} + +/* Sadly a socket can't be unassociated with a completion port */ +int iocp_iod_unregister(struct npool *nsp, struct niod *iod) { + + if (IOD_PROPGET(iod, IOD_REGISTERED)) { + /* Nuke all uncompleted operations on that iod */ + CancelIo((HANDLE)iod->sd); + IOD_PROPCLR(iod, IOD_REGISTERED); + } + + return 1; +} + +int iocp_iod_modify(struct npool *nsp, struct niod *iod, struct nevent *nse, int ev_set, int ev_clr) { + int new_events; + struct iocp_engine_info *iinfo = (struct iocp_engine_info *)nsp->engine_data; + + assert((ev_set & ev_clr) == 0); + assert(IOD_PROPGET(iod, IOD_REGISTERED)); + + new_events = iod->watched_events; + new_events |= ev_set; + new_events &= ~ev_clr; + + if (ev_set != EV_NONE) + initiate_overlapped_event(nsp, nse); + else if (ev_clr != EV_NONE) + terminate_overlapped_event(nsp, nse); + + if (new_events == iod->watched_events) + return 1; /* nothing to do */ + + iod->watched_events = new_events; + + return 1; +} + +int iocp_loop(struct npool *nsp, int msec_timeout) { + int event_msecs; /* msecs before an event goes off */ + int combined_msecs; + int sock_err = 0; + BOOL bRet; + unsigned long total_events; + struct iocp_engine_info *iinfo = (struct iocp_engine_info *)nsp->engine_data; + + assert(msec_timeout >= -1); + + if (nsp->events_pending == 0) + return 0; /* No need to wait on 0 events ... */ + + + struct nevent *nse; + + /* Make sure the preallocated space for the retrieved events is big enough */ + total_events = gh_list_count(&nsp->connect_events) + gh_list_count(&nsp->read_events) + gh_list_count(&nsp->write_events); + if (iinfo->capacity < total_events) { + iinfo->capacity *= 2; + iinfo->eov_list = (OVERLAPPED_ENTRY *)safe_realloc(iinfo->eov_list, iinfo->capacity * sizeof(OVERLAPPED_ENTRY)); + } + + nsock_log_debug_all("wait for events"); + + nse = next_expirable_event(nsp); + if (!nse) + event_msecs = -1; /* None of the events specified a timeout */ + else + event_msecs = MAX(0, TIMEVAL_MSEC_SUBTRACT(nse->timeout, nsock_tod)); + +#if HAVE_PCAP +#ifndef PCAP_CAN_DO_SELECT + /* Force a low timeout when capturing packets on systems where + * the pcap descriptor is not select()able. */ + if (gh_list_count(&nsp->pcap_read_events) > 0) + if (event_msecs > PCAP_POLL_INTERVAL) + event_msecs = PCAP_POLL_INTERVAL; +#endif +#endif + + /* We cast to unsigned because we want -1 to be very high (since it means no + * timeout) */ + combined_msecs = MIN((unsigned)event_msecs, (unsigned)msec_timeout); + +#if HAVE_PCAP +#ifndef PCAP_CAN_DO_SELECT + /* do non-blocking read on pcap devices that doesn't support select() + * If there is anything read, just leave this loop. */ + if (pcap_read_on_nonselect(nsp)) { + /* okay, something was read. */ + gettimeofday(&nsock_tod, NULL); + iterate_through_pcap_events(nsp); + } + else +#endif +#endif + { + /* It is mandatory these values are reset before calling GetQueuedCompletionStatusEx */ + iinfo->entries_removed = 0; + memset(iinfo->eov_list, 0, iinfo->capacity * sizeof(OVERLAPPED_ENTRY)); + bRet = GetQueuedCompletionStatusEx(iinfo->iocp, iinfo->eov_list, iinfo->capacity, &iinfo->entries_removed, combined_msecs, FALSE); + + gettimeofday(&nsock_tod, NULL); /* Due to iocp delay */ + if (!bRet) { + sock_err = socket_errno(); + if (!iinfo->eov && sock_err != WAIT_TIMEOUT) { + nsock_log_error("nsock_loop error %d: %s", sock_err, socket_strerror(sock_err)); + nsp->errnum = sock_err; + return -1; + } + } + } + + iterate_through_event_lists(nsp); + + return 1; +} + + +/* ---- INTERNAL FUNCTIONS ---- */ + +#if HAVE_PCAP +/* Iterate through pcap events separately, since these are not tracked in iocp_engine_info */ +void iterate_through_pcap_events(struct npool *nsp) { + gh_lnode_t *current, *next, *last; + + last = gh_list_last_elem(&nsp->active_iods); + + for (current = gh_list_first_elem(&nsp->active_iods); + current != NULL && gh_lnode_prev(current) != last; + current = next) { + struct niod *nsi = container_of(current, struct niod, nodeq); + + if (nsi->pcap && nsi->state != NSIOD_STATE_DELETED && nsi->events_pending) + { + process_iod_events(nsp, nsi, EV_READ); + } + + next = gh_lnode_next(current); + if (nsi->state == NSIOD_STATE_DELETED) { + gh_list_remove(&nsp->active_iods, current); + gh_list_prepend(&nsp->free_iods, current); + } + } +} +#endif + +/* Iterate through all the event lists (such as connect_events, read_events, +* timer_events, etc) and take action for those that have completed (due to +* timeout, i/o, etc) */ +void iterate_through_event_lists(struct npool *nsp) { + struct iocp_engine_info *iinfo = (struct iocp_engine_info *)nsp->engine_data; + + for (unsigned long i = 0; i < iinfo->entries_removed; i++) { + + iinfo->eov = (struct extended_overlapped *)iinfo->eov_list[i].lpOverlapped; + /* We can't rely on iinfo->entries_removed to tell us the real number of + * events to process */ + if (!iinfo->eov || !iinfo->eov->nse) + continue; + + /* We check if this is from a cancelled operation */ + if (iinfo->eov->nse->id != iinfo->eov->nse_id || + iinfo->eov->nse->event_done) { + free_eov(nsp, iinfo->eov); + iinfo->eov = NULL; + continue; + } + + if (!HasOverlappedIoCompleted((OVERLAPPED *)iinfo->eov)) + continue; + + struct niod *nsi = iinfo->eov->nse->iod; + struct nevent *nse = iinfo->eov->nse; + gh_list_t *evlist = NULL; + int ev = 0; + + switch (nse->type) { + case NSE_TYPE_CONNECT: + case NSE_TYPE_CONNECT_SSL: + ev = EV_READ; + evlist = &nsp->connect_events; + break; + case NSE_TYPE_READ: + ev = EV_READ; + evlist = &nsp->read_events; + break; + case NSE_TYPE_WRITE: + ev = EV_WRITE; + evlist = &nsp->write_events; + break; + } + + /* Setting the connect error for nsock_core to get in handle_connect_result */ + if (nse->type == NSE_TYPE_CONNECT || nse->type == NSE_TYPE_CONNECT_SSL) { + setsockopt(nse->iod->sd, SOL_SOCKET, SO_UPDATE_CONNECT_CONTEXT, NULL, 0); + DWORD dwRes; + if (!GetOverlappedResult((HANDLE)nse->iod->sd, (LPOVERLAPPED)iinfo->eov, &dwRes, FALSE)) {
+ int err = map_faulty_errors(socket_errno()); + if (err) + setsockopt(nse->iod->sd, SOL_SOCKET, SO_ERROR, (char *)&err, sizeof(err)); + } + } + + process_event(nsp, evlist, nse, ev); + + if (nse->event_done) { + /* event is done, remove it from the event list and update IOD pointers + * to the first events of each kind */ + update_first_events(nse); + gh_list_remove(evlist, &nse->nodeq_io); + gh_list_append(&nsp->free_events, &nse->nodeq_io); + + if (nse->timeout.tv_sec) + gh_heap_remove(&nsp->expirables, &nse->expire); + } else + initiate_overlapped_event(nsp, nse); + + if (nsi->state == NSIOD_STATE_DELETED) { + gh_list_remove(&nsp->active_iods, &nsi->nodeq); + gh_list_prepend(&nsp->free_iods, &nsi->nodeq); + } + + iinfo->eov = NULL; + } + + /* iterate through timers and expired events */ + process_expired_events(nsp); +} + +static int errcode_is_failure(int err) { +#ifndef WIN32 + return err != EINTR && err != EAGAIN && err != EBUSY; +#else + return err != EINTR && err != EAGAIN && err != WSA_IO_PENDING && err != ERROR_NETNAME_DELETED; +#endif +} + +static int map_faulty_errors(int err) { + /* This actually happens https://svn.boost.org/trac/boost/ticket/10744 */ + switch (err) { + case ERROR_NETWORK_UNREACHABLE: return WSAENETUNREACH; + case ERROR_HOST_UNREACHABLE: return WSAEHOSTUNREACH; + case ERROR_CONNECTION_REFUSED: return WSAECONNREFUSED; + case ERROR_SEM_TIMEOUT: return WSAETIMEDOUT; + } + return err; +} + +static struct extended_overlapped *new_eov(struct npool *nsp, struct nevent *nse) { + struct extended_overlapped *eov; + gh_lnode_t *lnode; + struct iocp_engine_info *iinfo = (struct iocp_engine_info *)nsp->engine_data; + + lnode = gh_list_pop(&iinfo->free_eovs);
+ if (!lnode) + eov = (struct extended_overlapped *)safe_malloc(sizeof(struct extended_overlapped)); + else + eov = container_of(lnode, struct extended_overlapped, nodeq); + + memset(eov, 0, sizeof(struct extended_overlapped)); + nse->eov = eov; + eov->nse = nse; + eov->nse_id = nse->id; + eov->err = 0; + gh_list_prepend(&iinfo->active_eovs, &eov->nodeq); + + /* Make the read buffer equal to the size of the buffer in do_actual_read() */ + if (nse->type == NSE_TYPE_READ && !eov->readbuf && !nse->iod->ssl) + eov->readbuf = (char*)safe_malloc(READ_BUFFER_SZ * sizeof(char)); + + return eov; +} + +/* This needs to be called after getting the overlapped event in */ +static void free_eov(struct npool *nsp, struct extended_overlapped *eov) { + struct iocp_engine_info *iinfo = (struct iocp_engine_info *)nsp->engine_data; + struct nevent *nse = eov->nse; + + gh_list_remove(&iinfo->active_eovs, &eov->nodeq); + + if (eov->readbuf) { + free(eov->readbuf); + eov->readbuf = NULL; + } + + gh_list_prepend(&iinfo->free_eovs, &eov->nodeq); + + eov->nse = NULL; + if (nse) + nse->eov = NULL; +} + + +static void call_connect_overlapped(struct npool *nsp, struct nevent *nse) { + BOOL ok; + DWORD numBytes = 0; + int one = 1; + SOCKET sock = nse->iod->sd; + GUID guid = WSAID_CONNECTEX; + struct sockaddr_in addr; + LPFN_CONNECTEX ConnectExPtr = NULL; + struct iocp_engine_info *iinfo = (struct iocp_engine_info *)nse->iod->nsp->engine_data; + struct extended_overlapped *eov = new_eov(nsp, nse); + int ret; + struct sockaddr_storage *ss = &nse->iod->peer; + size_t sslen = nse->iod->peerlen; + + if (nse->iod->lastproto != IPPROTO_TCP) { + if (connect(sock, (struct sockaddr *)ss, sslen) == -1) { + int err = socket_errno(); + nse->event_done = 1; + nse->status = NSE_STATUS_ERROR; + nse->errnum = err; + } else { + force_operation(nsp, nse); + } + return; + } + + ret = WSAIoctl(sock, SIO_GET_EXTENSION_FUNCTION_POINTER, + (void*)&guid, sizeof(guid), (void*)&ConnectExPtr, sizeof(ConnectExPtr), + &numBytes, NULL, NULL); + if (ret) + fatal("Error initiating event type(%d)", nse->type); + + ret = setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (const char *)&one, sizeof(one));
+ if (ret == -1) {
+ int err = socket_errno(); + nse->event_done = 1; + nse->status = NSE_STATUS_ERROR; + nse->errnum = err; + return; + } + + /* ConnectEx doesn't automatically bind the socket */ + memset(&addr, 0, sizeof(addr)); + addr.sin_family = AF_INET; + addr.sin_addr.s_addr = INADDR_ANY; + addr.sin_port = 0; + if (!nse->iod->locallen) { + ret = bind(sock, (SOCKADDR*)&addr, sizeof(addr)); + if (ret) { + int err = socket_errno(); + nse->event_done = 1; + nse->status = NSE_STATUS_ERROR; + nse->errnum = err; + return; + } + } + + ok = ConnectExPtr(sock, (SOCKADDR*)ss, sslen, NULL, 0, NULL, (LPOVERLAPPED)eov); + if (!ok) { + int err = socket_errno(); + if (err != ERROR_IO_PENDING) { + nse->event_done = 1; + nse->status = NSE_STATUS_ERROR; + nse->errnum = err; + } + } +} + +static void call_read_overlapped(struct nevent *nse) { + DWORD flags = 0; + int err = 0; + struct iocp_engine_info *iinfo = (struct iocp_engine_info *)nse->iod->nsp->engine_data; + + struct extended_overlapped *eov = new_eov(nse->iod->nsp, nse); + + eov->wsabuf.buf = eov->readbuf; + eov->wsabuf.len = READ_BUFFER_SZ; + + err = WSARecvFrom(nse->iod->sd, &eov->wsabuf, 1, NULL, &flags, + (struct sockaddr *)&nse->iod->peer, (LPINT)&nse->iod->peerlen, (LPOVERLAPPED)eov, NULL); + if (err) { + err = socket_errno(); + if (errcode_is_failure(err)) { + // WSARecvFrom with overlapped I/O may generate ERROR_PORT_UNREACHABLE on ICMP error. + // We'll translate that so Nsock-using software doesn't have to know about it. + eov->err = (err == ERROR_PORT_UNREACHABLE ? ECONNREFUSED : err); + /* Send the error to the main loop to be picked up by the appropriate handler */ + BOOL bRet = PostQueuedCompletionStatus(iinfo->iocp, -1, (ULONG_PTR)nse->iod, (LPOVERLAPPED)eov); + if (!bRet) + fatal("Error initiating event type(%d)", nse->type); + } + } +} + +static void call_write_overlapped(struct nevent *nse) { + int err; + char *str; + int bytesleft; + struct iocp_engine_info *iinfo = (struct iocp_engine_info *)nse->iod->nsp->engine_data; + + struct extended_overlapped *eov = new_eov(nse->iod->nsp, nse); + + str = fs_str(&nse->iobuf) + nse->writeinfo.written_so_far; + bytesleft = fs_length(&nse->iobuf) - nse->writeinfo.written_so_far; + + eov->wsabuf.buf = str; + eov->wsabuf.len = bytesleft; + + if (nse->writeinfo.dest.ss_family == AF_UNSPEC) + err = WSASend(nse->iod->sd, &eov->wsabuf, 1, NULL, 0, (LPWSAOVERLAPPED)eov, NULL); + else + err = WSASendTo(nse->iod->sd, &eov->wsabuf, 1, NULL, 0, + (struct sockaddr *)&nse->writeinfo.dest, (int)nse->writeinfo.destlen, + (LPWSAOVERLAPPED)eov, NULL); + if (err) { + err = socket_errno(); + if (errcode_is_failure(err)) { + eov->err = err; + /* Send the error to the main loop to be picked up by the appropriate handler */ + BOOL bRet = PostQueuedCompletionStatus(iinfo->iocp, -1, (ULONG_PTR)nse->iod, (LPOVERLAPPED)eov); + if (!bRet) + fatal("Error initiating event type(%d)", nse->type); + } + } +} + +/* Anything that isn't an overlapped operation uses this to get processed by the main loop */ +static void force_operation(struct npool *nsp, struct nevent *nse) { + BOOL bRet; + struct extended_overlapped *eov; + + struct iocp_engine_info *iinfo = (struct iocp_engine_info *)nsp->engine_data; + eov = new_eov(nse->iod->nsp, nse); + + bRet = PostQueuedCompletionStatus(iinfo->iocp, 0, (ULONG_PTR)nse->iod, (LPOVERLAPPED)eov); + if (!bRet) + fatal("Error initiating event type(%d)", nse->type); +} + +/* Either initiate a I/O read or force a SSL_read */ +static void initiate_read(struct npool *nsp, struct nevent *nse) { + if (!nse->iod->ssl) + call_read_overlapped(nse); + else + force_operation(nsp, nse); +} + +/* Either initiate a I/O write or force a SSL_write */ +static void initiate_write(struct npool *nsp, struct nevent *nse) { + if (!nse->iod->ssl) + call_write_overlapped(nse); + else + force_operation(nsp, nse); +} + +/* Force a PCAP read */ +static void initiate_pcap_read(struct npool *nsp, struct nevent *nse) { + force_operation(nsp, nse); +} + +static void initiate_connect(struct npool *nsp, struct nevent *nse) { + int sslconnect_inprogress = 0; + struct iocp_engine_info *iinfo = (struct iocp_engine_info *)nsp->engine_data; + +#if HAVE_OPENSSL + sslconnect_inprogress = nse->type == NSE_TYPE_CONNECT_SSL && nse->iod && + (nse->sslinfo.ssl_desire == SSL_ERROR_WANT_READ || + nse->sslinfo.ssl_desire == SSL_ERROR_WANT_WRITE); +#endif + + if (sslconnect_inprogress) + force_operation(nsp, nse); + else + call_connect_overlapped(nsp, nse); +} + +/* Start the overlapped I/O operation */ +static void initiate_overlapped_event(struct npool *nsp, struct nevent *nse) { + if (nse->eov) + terminate_overlapped_event(nsp, nse); + + switch (nse->type) { + case NSE_TYPE_CONNECT: + case NSE_TYPE_CONNECT_SSL: + initiate_connect(nsp, nse); + break; + case NSE_TYPE_READ: + initiate_read(nsp, nse); + break; + case NSE_TYPE_WRITE: + initiate_write(nsp, nse); + break; +#if HAVE_PCAP + case NSE_TYPE_PCAP_READ: + initiate_pcap_read(nsp, nse); + break; +#endif + default: fatal("Event type(%d) not supported by engine IOCP\n", nse->type); + } +} + +/* Terminate an overlapped I/O operation that expired */ +static void terminate_overlapped_event(struct npool *nsp, struct nevent *nse) { + bool eov_done = true; + + if (nse->eov) { + if (!HasOverlappedIoCompleted((LPOVERLAPPED)nse->eov)) { + CancelIoEx((HANDLE)nse->iod->sd, (LPOVERLAPPED)nse->eov); + eov_done = false; + } + + if (eov_done) + free_eov(nsp, nse->eov); + } +} + +/* Retrieve the amount of bytes transferred or set the appropriate error */ +static int get_overlapped_result(struct npool *nsp, int fd, const void *buffer, size_t count) { + char *buf = (char *)buffer; + DWORD dwRes = 0; + int err; + struct iocp_engine_info *iinfo = (struct iocp_engine_info *)nsp->engine_data; + + struct extended_overlapped *eov = iinfo->eov; + struct nevent *nse = eov->nse; + + /* If the operation failed at initialization, set the error for nsock_core.c to see */ + if (eov->err) { + SetLastError(map_faulty_errors(eov->err)); + return -1; + } + + if (!GetOverlappedResult((HANDLE)fd, (LPOVERLAPPED)eov, &dwRes, FALSE)) { + err = socket_errno(); + if (errcode_is_failure(err)) { + SetLastError(map_faulty_errors(err)); + return -1; + } + } + + if (nse->type == NSE_TYPE_READ && buf) + memcpy(buf, eov->wsabuf.buf, dwRes); + + return dwRes; +} + +int iocp_iod_connect(struct npool *nsp, int sockfd, const struct sockaddr *addr, socklen_t addrlen) { + return 0; +} + +int iocp_iod_read(struct npool *nsp, int sockfd, void *buf, size_t len, int flags, struct sockaddr *src_addr, socklen_t *addrlen) { + return get_overlapped_result(nsp, sockfd, buf, len); +} + +int iocp_iod_write(struct npool *nsp, int sockfd, const void *buf, size_t len, int flags, const struct sockaddr *dest_addr, socklen_t addrlen) { + return get_overlapped_result(nsp, sockfd, buf, len); +} + +#endif /* HAVE_IOCP */ diff --git a/nsock/src/engine_kqueue.c b/nsock/src/engine_kqueue.c new file mode 100644 index 0000000..aa992bb --- /dev/null +++ b/nsock/src/engine_kqueue.c @@ -0,0 +1,368 @@ +/*************************************************************************** + * engine_kqueue.c -- BSD kqueue(2) based IO engine. * + * * + ***********************IMPORTANT NSOCK LICENSE TERMS*********************** + * + * The nsock parallel socket event library is (C) 1999-2023 Nmap Software LLC + * This library is free software; you may redistribute and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation; Version 2. This guarantees your right to use, modify, and + * redistribute this software under certain conditions. If this license is + * unacceptable to you, Nmap Software LLC may be willing to sell alternative + * licenses (contact sales@nmap.com ). + * + * As a special exception to the GPL terms, Nmap Software LLC grants permission + * to link the code of this program with any version of the OpenSSL library + * which is distributed under a license identical to that listed in the included + * docs/licenses/OpenSSL.txt file, and distribute linked combinations including + * the two. You must obey the GNU GPL in all respects for all of the code used + * other than OpenSSL. If you modify this file, you may extend this exception to + * your version of the file, but you are not obligated to do so. + * + * If you received these files with a written license agreement stating terms + * other than the (GPL) terms above, then that alternative license agreement + * takes precedence over this comment. + * + * Source is provided to this software because we believe users have a right to + * know exactly what a program is going to do before they run it. This also + * allows you to audit the software for security holes. + * + * Source code also allows you to port Nmap to new platforms, fix bugs, and add + * new features. You are highly encouraged to send your changes to the + * dev@nmap.org mailing list for possible incorporation into the main + * distribution. By sending these changes to Fyodor or one of the Insecure.Org + * development mailing lists, or checking them into the Nmap source code + * repository, it is understood (unless you specify otherwise) that you are + * offering the Nmap Project (Nmap Software LLC) the unlimited, non-exclusive + * right to reuse, modify, and relicense the code. Nmap will always be available + * Open Source, but this is important because the inability to relicense code + * has caused devastating problems for other Free Software projects (such as KDE + * and NASM). We also occasionally relicense the code to third parties as + * discussed above. If you wish to specify special license conditions of your + * contributions, just say so when you send them. + * + * 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 v2.0 for more + * details (http://www.gnu.org/licenses/gpl-2.0.html). + * + ***************************************************************************/ + +/* $Id$ */ + +#ifdef HAVE_CONFIG_H +#include "nsock_config.h" +#endif + +#if HAVE_KQUEUE + +#include <sys/types.h> +#include <sys/event.h> +#include <sys/time.h> +#include <errno.h> + +#include "nsock_internal.h" +#include "nsock_log.h" + +#if HAVE_PCAP +#include "nsock_pcap.h" +#endif + +#define INITIAL_EV_COUNT 128 + + +/* --- ENGINE INTERFACE PROTOTYPES --- */ +static int kqueue_init(struct npool *nsp); +static void kqueue_destroy(struct npool *nsp); +static int kqueue_iod_register(struct npool *nsp, struct niod *iod, struct nevent *nse, int ev); +static int kqueue_iod_unregister(struct npool *nsp, struct niod *iod); +static int kqueue_iod_modify(struct npool *nsp, struct niod *iod, struct nevent *nse, int ev_set, int ev_clr); +static int kqueue_loop(struct npool *nsp, int msec_timeout); + +extern struct io_operations posix_io_operations; + +/* ---- ENGINE DEFINITION ---- */ +struct io_engine engine_kqueue = { + "kqueue", + kqueue_init, + kqueue_destroy, + kqueue_iod_register, + kqueue_iod_unregister, + kqueue_iod_modify, + kqueue_loop, + &posix_io_operations +}; + + +/* --- INTERNAL PROTOTYPES --- */ +static void iterate_through_event_lists(struct npool *nsp, int evcount); + +/* defined in nsock_core.c */ +void process_iod_events(struct npool *nsp, struct niod *nsi, int ev); +void process_event(struct npool *nsp, gh_list_t *evlist, struct nevent *nse, int ev); +void process_expired_events(struct npool *nsp); +#if HAVE_PCAP +#ifndef PCAP_CAN_DO_SELECT +int pcap_read_on_nonselect(struct npool *nsp); +#endif +#endif + +/* defined in nsock_event.c */ +void update_first_events(struct nevent *nse); + + +extern struct timeval nsock_tod; + + +/* + * Engine specific data structure + */ +struct kqueue_engine_info { + int kqfd; + int maxfd; + size_t evlen; + struct kevent *events; +}; + + +int kqueue_init(struct npool *nsp) { + struct kqueue_engine_info *kinfo; + + kinfo = (struct kqueue_engine_info *)safe_malloc(sizeof(struct kqueue_engine_info)); + + kinfo->kqfd = kqueue(); + kinfo->maxfd = -1; + kinfo->evlen = INITIAL_EV_COUNT; + kinfo->events = (struct kevent *)safe_malloc(INITIAL_EV_COUNT * sizeof(struct kevent)); + + nsp->engine_data = (void *)kinfo; + + return 1; +} + +void kqueue_destroy(struct npool *nsp) { + struct kqueue_engine_info *kinfo = (struct kqueue_engine_info *)nsp->engine_data; + + assert(kinfo != NULL); + close(kinfo->kqfd); + free(kinfo->events); + free(kinfo); +} + +int kqueue_iod_register(struct npool *nsp, struct niod *iod, struct nevent *nse, int ev) { + struct kqueue_engine_info *kinfo = (struct kqueue_engine_info *)nsp->engine_data; + + assert(!IOD_PROPGET(iod, IOD_REGISTERED)); + + IOD_PROPSET(iod, IOD_REGISTERED); + iod->watched_events = EV_NONE; + + kqueue_iod_modify(nsp, iod, nse, ev, EV_NONE); + + if (nsock_iod_get_sd(iod) > kinfo->maxfd) + kinfo->maxfd = nsock_iod_get_sd(iod); + + return 1; +} + +int kqueue_iod_unregister(struct npool *nsp, struct niod *iod) { + struct kqueue_engine_info *kinfo = (struct kqueue_engine_info *)nsp->engine_data; + + /* some IODs can be unregistered here if they're associated to an event that was + * immediately completed */ + if (IOD_PROPGET(iod, IOD_REGISTERED)) { + kqueue_iod_modify(nsp, iod, NULL, EV_NONE, EV_READ|EV_WRITE); + IOD_PROPCLR(iod, IOD_REGISTERED); + + if (nsock_iod_get_sd(iod) == kinfo->maxfd) + kinfo->maxfd--; + } + iod->watched_events = EV_NONE; + return 1; +} + +#define EV_SETFLAG(_set, _ev) (((_set) & (_ev)) ? (EV_ADD|EV_ENABLE) : (EV_ADD|EV_DISABLE)) + +int kqueue_iod_modify(struct npool *nsp, struct niod *iod, struct nevent *nse, int ev_set, int ev_clr) { + struct kevent kev[2]; + int new_events, i; + struct kqueue_engine_info *kinfo = (struct kqueue_engine_info *)nsp->engine_data; + + assert((ev_set & ev_clr) == 0); + assert(IOD_PROPGET(iod, IOD_REGISTERED)); + + new_events = iod->watched_events; + new_events |= ev_set; + new_events &= ~ev_clr; + + if (new_events == iod->watched_events) + return 1; /* nothing to do */ + + i = 0; + if ((ev_set ^ ev_clr) & EV_READ) { + EV_SET(&kev[i], nsock_iod_get_sd(iod), EVFILT_READ, EV_SETFLAG(ev_set, EV_READ), 0, 0, (void *)iod); + i++; + } + if ((ev_set ^ ev_clr) & EV_WRITE) { + EV_SET(&kev[i], nsock_iod_get_sd(iod), EVFILT_WRITE, EV_SETFLAG(ev_set, EV_WRITE), 0, 0, (void *)iod); + i++; + } + + if (i > 0 && kevent(kinfo->kqfd, kev, i, NULL, 0, NULL) < 0) + fatal("Unable to update events for IOD #%lu: %s", iod->id, strerror(errno)); + + iod->watched_events = new_events; + return 1; +} + +int kqueue_loop(struct npool *nsp, int msec_timeout) { + int results_left = 0; + int event_msecs; /* msecs before an event goes off */ + int combined_msecs; + struct timespec ts, *ts_p; + int sock_err = 0; + struct kqueue_engine_info *kinfo = (struct kqueue_engine_info *)nsp->engine_data; + + assert(msec_timeout >= -1); + + if (nsp->events_pending == 0) + return 0; /* No need to wait on 0 events ... */ + + + if (gh_list_count(&nsp->active_iods) > kinfo->evlen) { + kinfo->evlen = gh_list_count(&nsp->active_iods) * 2; + kinfo->events = (struct kevent *)safe_realloc(kinfo->events, kinfo->evlen * sizeof(struct kevent)); + } + + do { + struct nevent *nse; + + nsock_log_debug_all("wait for events"); + + nse = next_expirable_event(nsp); + if (!nse) + event_msecs = -1; /* None of the events specified a timeout */ + else + event_msecs = MAX(0, TIMEVAL_MSEC_SUBTRACT(nse->timeout, nsock_tod)); + +#if HAVE_PCAP +#ifndef PCAP_CAN_DO_SELECT + /* Force a low timeout when capturing packets on systems where + * the pcap descriptor is not select()able. */ + if (gh_list_count(&nsp->pcap_read_events) > 0) + if (event_msecs > PCAP_POLL_INTERVAL) + event_msecs = PCAP_POLL_INTERVAL; +#endif +#endif + + /* We cast to unsigned because we want -1 to be very high (since it means no + * timeout) */ + combined_msecs = MIN((unsigned)event_msecs, (unsigned)msec_timeout); + + /* Set up the timeval pointer we will give to kevent() */ + memset(&ts, 0, sizeof(struct timespec)); + if (combined_msecs >= 0) { + ts.tv_sec = combined_msecs / 1000; + ts.tv_nsec = (combined_msecs % 1000) * 1000000L; + ts_p = &ts; + } else { + ts_p = NULL; + } + +#if HAVE_PCAP +#ifndef PCAP_CAN_DO_SELECT + /* do non-blocking read on pcap devices that doesn't support select() + * If there is anything read, just leave this loop. */ + if (pcap_read_on_nonselect(nsp)) { + /* okay, something was read. */ + } else +#endif +#endif + { + results_left = kevent(kinfo->kqfd, NULL, 0, kinfo->events, kinfo->evlen, ts_p); + if (results_left == -1) + sock_err = socket_errno(); + } + + gettimeofday(&nsock_tod, NULL); /* Due to kevent delay */ + } while (results_left == -1 && sock_err == EINTR); /* repeat only if signal occurred */ + + if (results_left == -1 && sock_err != EINTR) { + nsock_log_error("nsock_loop error %d: %s", sock_err, socket_strerror(sock_err)); + nsp->errnum = sock_err; + return -1; + } + + iterate_through_event_lists(nsp, results_left); + + return 1; +} + + +/* ---- INTERNAL FUNCTIONS ---- */ + +static inline int get_evmask(struct niod *nsi, const struct kevent *kev) { + int evmask = EV_NONE; + + /* generate the corresponding event mask with nsock event flags */ + if (kev->flags & EV_ERROR) { + evmask |= EV_EXCEPT; + + if (kev->data == EPIPE && (nsi->watched_events & EV_READ)) + evmask |= EV_READ; + } else { + switch (kev->filter) { + case EVFILT_READ: + evmask |= EV_READ; + break; + + case EVFILT_WRITE: + evmask |= EV_WRITE; + break; + + default: + fatal("Unsupported filter value: %d\n", (int)kev->filter); + } + } + return evmask; +} + +/* Iterate through all the event lists (such as connect_events, read_events, + * timer_events, etc) and take action for those that have completed (due to + * timeout, i/o, etc) */ +void iterate_through_event_lists(struct npool *nsp, int evcount) { + int n; + struct kqueue_engine_info *kinfo = (struct kqueue_engine_info *)nsp->engine_data; + struct niod *nsi; + + for (n = 0; n < evcount; n++) { + struct kevent *kev = &kinfo->events[n]; + + nsi = (struct niod *)kev->udata; + + /* process all the pending events for this IOD */ + process_iod_events(nsp, nsi, get_evmask(nsi, kev)); + + IOD_PROPSET(nsi, IOD_PROCESSED); + } + + for (n = 0; n < evcount; n++) { + struct kevent *kev = &kinfo->events[n]; + + nsi = (struct niod *)kev->udata; + + if (nsi->state == NSIOD_STATE_DELETED) { + if (IOD_PROPGET(nsi, IOD_PROCESSED)) { + IOD_PROPCLR(nsi, IOD_PROCESSED); + gh_list_remove(&nsp->active_iods, &nsi->nodeq); + gh_list_prepend(&nsp->free_iods, &nsi->nodeq); + } + } + } + + /* iterate through timers and expired events */ + process_expired_events(nsp); +} + +#endif /* HAVE_KQUEUE */ + diff --git a/nsock/src/engine_poll.c b/nsock/src/engine_poll.c new file mode 100644 index 0000000..5a2262a --- /dev/null +++ b/nsock/src/engine_poll.c @@ -0,0 +1,429 @@ +/*************************************************************************** + * engine_poll.c -- poll(2) based IO engine. * + * * + ***********************IMPORTANT NSOCK LICENSE TERMS*********************** + * + * The nsock parallel socket event library is (C) 1999-2023 Nmap Software LLC + * This library is free software; you may redistribute and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation; Version 2. This guarantees your right to use, modify, and + * redistribute this software under certain conditions. If this license is + * unacceptable to you, Nmap Software LLC may be willing to sell alternative + * licenses (contact sales@nmap.com ). + * + * As a special exception to the GPL terms, Nmap Software LLC grants permission + * to link the code of this program with any version of the OpenSSL library + * which is distributed under a license identical to that listed in the included + * docs/licenses/OpenSSL.txt file, and distribute linked combinations including + * the two. You must obey the GNU GPL in all respects for all of the code used + * other than OpenSSL. If you modify this file, you may extend this exception to + * your version of the file, but you are not obligated to do so. + * + * If you received these files with a written license agreement stating terms + * other than the (GPL) terms above, then that alternative license agreement + * takes precedence over this comment. + * + * Source is provided to this software because we believe users have a right to + * know exactly what a program is going to do before they run it. This also + * allows you to audit the software for security holes. + * + * Source code also allows you to port Nmap to new platforms, fix bugs, and add + * new features. You are highly encouraged to send your changes to the + * dev@nmap.org mailing list for possible incorporation into the main + * distribution. By sending these changes to Fyodor or one of the Insecure.Org + * development mailing lists, or checking them into the Nmap source code + * repository, it is understood (unless you specify otherwise) that you are + * offering the Nmap Project (Nmap Software LLC) the unlimited, non-exclusive + * right to reuse, modify, and relicense the code. Nmap will always be available + * Open Source, but this is important because the inability to relicense code + * has caused devastating problems for other Free Software projects (such as KDE + * and NASM). We also occasionally relicense the code to third parties as + * discussed above. If you wish to specify special license conditions of your + * contributions, just say so when you send them. + * + * 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 v2.0 for more + * details (http://www.gnu.org/licenses/gpl-2.0.html). + * + ***************************************************************************/ + +/* $Id$ */ + +#ifndef WIN32 +/* Allow the use of POLLRDHUP, if available. */ +#define _GNU_SOURCE +#endif + +#ifdef HAVE_CONFIG_H +#include "nsock_config.h" +#elif WIN32 +#include "nsock_winconfig.h" +#endif + +#if HAVE_POLL + +#include <errno.h> + +#ifndef WIN32 +#include <poll.h> +#else +#include <Winsock2.h> +#endif /* ^WIN32 */ + +#include "nsock_internal.h" +#include "nsock_log.h" + +#if HAVE_PCAP +#include "nsock_pcap.h" +#endif + +#define EV_LIST_INIT_SIZE 1024 + +#ifdef WIN32 + #define Poll WSAPoll + #define POLLFD WSAPOLLFD +#else + #define Poll poll + #define POLLFD struct pollfd +#endif + +#ifdef WIN32 + #define POLL_R_FLAGS (POLLIN) +#else + #define POLL_R_FLAGS (POLLIN | POLLPRI) +#endif /* WIN32 */ + +#define POLL_W_FLAGS POLLOUT +#ifdef POLLRDHUP + #define POLL_X_FLAGS (POLLERR | POLLHUP | POLLRDHUP) +#else + /* POLLRDHUP was introduced later and might be unavailable on older systems. */ + #define POLL_X_FLAGS (POLLERR | POLLHUP) +#endif /* POLLRDHUP */ + +extern struct io_operations posix_io_operations; + +/* --- ENGINE INTERFACE PROTOTYPES --- */ +static int poll_init(struct npool *nsp); +static void poll_destroy(struct npool *nsp); +static int poll_iod_register(struct npool *nsp, struct niod *iod, struct nevent *nse, int ev); +static int poll_iod_unregister(struct npool *nsp, struct niod *iod); +static int poll_iod_modify(struct npool *nsp, struct niod *iod, struct nevent *nse, int ev_set, int ev_clr); +static int poll_loop(struct npool *nsp, int msec_timeout); + + +/* ---- ENGINE DEFINITION ---- */ +struct io_engine engine_poll = { + "poll", + poll_init, + poll_destroy, + poll_iod_register, + poll_iod_unregister, + poll_iod_modify, + poll_loop, + &posix_io_operations +}; + + +/* --- INTERNAL PROTOTYPES --- */ +static void iterate_through_event_lists(struct npool *nsp); + +/* defined in nsock_core.c */ +void process_iod_events(struct npool *nsp, struct niod *nsi, int ev); +void process_event(struct npool *nsp, gh_list_t *evlist, struct nevent *nse, int ev); +void process_expired_events(struct npool *nsp); +#if HAVE_PCAP +#ifndef PCAP_CAN_DO_SELECT +int pcap_read_on_nonselect(struct npool *nsp); +#endif +#endif + +/* defined in nsock_event.c */ +void update_first_events(struct nevent *nse); + + +extern struct timeval nsock_tod; + + +/* + * Engine specific data structure + */ +struct poll_engine_info { + int capacity; + int max_fd; + /* index of the highest poll event */ + POLLFD *events; +}; + + + +static inline int lower_max_fd(struct poll_engine_info *pinfo) { + do { + pinfo->max_fd--; + } while (pinfo->max_fd >= 0 && pinfo->events[pinfo->max_fd].fd == -1); + + return pinfo->max_fd; +} + +static inline int evlist_grow(struct poll_engine_info *pinfo) { + int i; + + i = pinfo->capacity; + + if (pinfo->capacity == 0) { + pinfo->capacity = EV_LIST_INIT_SIZE; + pinfo->events = (POLLFD *)safe_malloc(sizeof(POLLFD) * pinfo->capacity); + } else { + pinfo->capacity *= 2; + pinfo->events = (POLLFD *)safe_realloc(pinfo->events, sizeof(POLLFD) * pinfo->capacity); + } + + while (i < pinfo->capacity) { + pinfo->events[i].fd = -1; + pinfo->events[i].events = 0; + pinfo->events[i].revents = 0; + i++; + } + return pinfo->capacity; +} + + +int poll_init(struct npool *nsp) { + struct poll_engine_info *pinfo; + + pinfo = (struct poll_engine_info *)safe_malloc(sizeof(struct poll_engine_info)); + pinfo->capacity = 0; + pinfo->max_fd = -1; + evlist_grow(pinfo); + + nsp->engine_data = (void *)pinfo; + + return 1; +} + +void poll_destroy(struct npool *nsp) { + struct poll_engine_info *pinfo = (struct poll_engine_info *)nsp->engine_data; + + assert(pinfo != NULL); + free(pinfo->events); + free(pinfo); +} + +int poll_iod_register(struct npool *nsp, struct niod *iod, struct nevent *nse, int ev) { + struct poll_engine_info *pinfo = (struct poll_engine_info *)nsp->engine_data; + int sd; + + assert(!IOD_PROPGET(iod, IOD_REGISTERED)); + + iod->watched_events = ev; + + sd = nsock_iod_get_sd(iod); + while (pinfo->capacity < sd + 1) + evlist_grow(pinfo); + + pinfo->events[sd].fd = sd; + pinfo->events[sd].events = 0; + pinfo->events[sd].revents = 0; + + pinfo->max_fd = MAX(pinfo->max_fd, sd); + + if (ev & EV_READ) + pinfo->events[sd].events |= POLL_R_FLAGS; + if (ev & EV_WRITE) + pinfo->events[sd].events |= POLL_W_FLAGS; +#ifndef WIN32 + if (ev & EV_EXCEPT) + pinfo->events[sd].events |= POLL_X_FLAGS; +#endif + + IOD_PROPSET(iod, IOD_REGISTERED); + return 1; +} + +int poll_iod_unregister(struct npool *nsp, struct niod *iod) { + iod->watched_events = EV_NONE; + + /* some IODs can be unregistered here if they're associated to an event that was + * immediately completed */ + if (IOD_PROPGET(iod, IOD_REGISTERED)) { + struct poll_engine_info *pinfo = (struct poll_engine_info *)nsp->engine_data; + int sd; + + sd = nsock_iod_get_sd(iod); + pinfo->events[sd].fd = -1; + pinfo->events[sd].events = 0; + pinfo->events[sd].revents = 0; + + if (pinfo->max_fd == sd) + lower_max_fd(pinfo); + + IOD_PROPCLR(iod, IOD_REGISTERED); + } + return 1; +} + +int poll_iod_modify(struct npool *nsp, struct niod *iod, struct nevent *nse, int ev_set, int ev_clr) { + int sd; + int new_events; + struct poll_engine_info *pinfo = (struct poll_engine_info *)nsp->engine_data; + + assert((ev_set & ev_clr) == 0); + assert(IOD_PROPGET(iod, IOD_REGISTERED)); + + new_events = iod->watched_events; + new_events |= ev_set; + new_events &= ~ev_clr; + + if (new_events == iod->watched_events) + return 1; /* nothing to do */ + + iod->watched_events = new_events; + + sd = nsock_iod_get_sd(iod); + + pinfo->events[sd].fd = sd; + pinfo->events[sd].events = 0; + + /* regenerate the current set of events for this IOD */ + if (iod->watched_events & EV_READ) + pinfo->events[sd].events |= POLL_R_FLAGS; + if (iod->watched_events & EV_WRITE) + pinfo->events[sd].events |= POLL_W_FLAGS; + + return 1; +} + +int poll_loop(struct npool *nsp, int msec_timeout) { + int results_left = 0; + int event_msecs; /* msecs before an event goes off */ + int combined_msecs; + int sock_err = 0; + struct poll_engine_info *pinfo = (struct poll_engine_info *)nsp->engine_data; + + assert(msec_timeout >= -1); + + if (nsp->events_pending == 0) + return 0; /* No need to wait on 0 events ... */ + + do { + struct nevent *nse; + + nsock_log_debug_all("wait for events"); + + nse = next_expirable_event(nsp); + if (!nse) + event_msecs = -1; /* None of the events specified a timeout */ + else + event_msecs = MAX(0, TIMEVAL_MSEC_SUBTRACT(nse->timeout, nsock_tod)); + +#if HAVE_PCAP +#ifndef PCAP_CAN_DO_SELECT + /* Force a low timeout when capturing packets on systems where + * the pcap descriptor is not select()able. */ + if (gh_list_count(&nsp->pcap_read_events) > 0) + if (event_msecs > PCAP_POLL_INTERVAL) + event_msecs = PCAP_POLL_INTERVAL; +#endif +#endif + + /* We cast to unsigned because we want -1 to be very high (since it means no + * timeout) */ + combined_msecs = MIN((unsigned)event_msecs, (unsigned)msec_timeout); + +#if HAVE_PCAP +#ifndef PCAP_CAN_DO_SELECT + /* do non-blocking read on pcap devices that doesn't support select() + * If there is anything read, just leave this loop. */ + if (pcap_read_on_nonselect(nsp)) { + /* okay, something was read. */ + } else +#endif +#endif + { + results_left = Poll(pinfo->events, pinfo->max_fd + 1, combined_msecs); + if (results_left == -1) + sock_err = socket_errno(); + } + + gettimeofday(&nsock_tod, NULL); /* Due to poll delay */ + } while (results_left == -1 && sock_err == EINTR); /* repeat only if signal occurred */ + + if (results_left == -1 && sock_err != EINTR) { +#ifdef WIN32 + for (int i = 0; sock_err != EINVAL || i <= pinfo->max_fd; i++) { + if (sock_err != EINVAL || pinfo->events[i].fd != -1) { +#endif + nsock_log_error("nsock_loop error %d: %s", sock_err, socket_strerror(sock_err)); + nsp->errnum = sock_err; + return -1; +#ifdef WIN32 + } + } +#endif + } + + iterate_through_event_lists(nsp); + + return 1; +} + + +/* ---- INTERNAL FUNCTIONS ---- */ + +static inline int get_evmask(struct npool *nsp, struct niod *nsi) { + struct poll_engine_info *pinfo = (struct poll_engine_info *)nsp->engine_data; + int sd, evmask = EV_NONE; + POLLFD *pev; + + if (nsi->state != NSIOD_STATE_DELETED + && nsi->events_pending + && IOD_PROPGET(nsi, IOD_REGISTERED)) { + +#if HAVE_PCAP + if (nsi->pcap) + sd = ((mspcap *)nsi->pcap)->pcap_desc; + else +#endif + sd = nsi->sd; + + assert(sd < pinfo->capacity); + pev = &pinfo->events[sd]; + + if (pev->revents & POLL_R_FLAGS) + evmask |= EV_READ; + if (pev->revents & POLL_W_FLAGS) + evmask |= EV_WRITE; + if (pev->events && (pev->revents & POLL_X_FLAGS)) + evmask |= EV_EXCEPT; + } + return evmask; +} + +/* Iterate through all the event lists (such as connect_events, read_events, + * timer_events, etc) and take action for those that have completed (due to + * timeout, i/o, etc) */ +void iterate_through_event_lists(struct npool *nsp) { + gh_lnode_t *current, *next, *last; + + last = gh_list_last_elem(&nsp->active_iods); + + for (current = gh_list_first_elem(&nsp->active_iods); + current != NULL && gh_lnode_prev(current) != last; + current = next) { + struct niod *nsi = container_of(current, struct niod, nodeq); + + process_iod_events(nsp, nsi, get_evmask(nsp, nsi)); + + next = gh_lnode_next(current); + if (nsi->state == NSIOD_STATE_DELETED) { + gh_list_remove(&nsp->active_iods, current); + gh_list_prepend(&nsp->free_iods, current); + } + } + + /* iterate through timers and expired events */ + process_expired_events(nsp); +} + +#endif /* HAVE_POLL */ diff --git a/nsock/src/engine_select.c b/nsock/src/engine_select.c new file mode 100644 index 0000000..edf1b3d --- /dev/null +++ b/nsock/src/engine_select.c @@ -0,0 +1,395 @@ +/*************************************************************************** + * engine_select.c -- select(2) based IO engine. * + * * + ***********************IMPORTANT NSOCK LICENSE TERMS*********************** + * + * The nsock parallel socket event library is (C) 1999-2023 Nmap Software LLC + * This library is free software; you may redistribute and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation; Version 2. This guarantees your right to use, modify, and + * redistribute this software under certain conditions. If this license is + * unacceptable to you, Nmap Software LLC may be willing to sell alternative + * licenses (contact sales@nmap.com ). + * + * As a special exception to the GPL terms, Nmap Software LLC grants permission + * to link the code of this program with any version of the OpenSSL library + * which is distributed under a license identical to that listed in the included + * docs/licenses/OpenSSL.txt file, and distribute linked combinations including + * the two. You must obey the GNU GPL in all respects for all of the code used + * other than OpenSSL. If you modify this file, you may extend this exception to + * your version of the file, but you are not obligated to do so. + * + * If you received these files with a written license agreement stating terms + * other than the (GPL) terms above, then that alternative license agreement + * takes precedence over this comment. + * + * Source is provided to this software because we believe users have a right to + * know exactly what a program is going to do before they run it. This also + * allows you to audit the software for security holes. + * + * Source code also allows you to port Nmap to new platforms, fix bugs, and add + * new features. You are highly encouraged to send your changes to the + * dev@nmap.org mailing list for possible incorporation into the main + * distribution. By sending these changes to Fyodor or one of the Insecure.Org + * development mailing lists, or checking them into the Nmap source code + * repository, it is understood (unless you specify otherwise) that you are + * offering the Nmap Project (Nmap Software LLC) the unlimited, non-exclusive + * right to reuse, modify, and relicense the code. Nmap will always be available + * Open Source, but this is important because the inability to relicense code + * has caused devastating problems for other Free Software projects (such as KDE + * and NASM). We also occasionally relicense the code to third parties as + * discussed above. If you wish to specify special license conditions of your + * contributions, just say so when you send them. + * + * 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 v2.0 for more + * details (http://www.gnu.org/licenses/gpl-2.0.html). + * + ***************************************************************************/ + +/* $Id$ */ + +#ifndef WIN32 +#include <sys/select.h> +#endif + +#include <errno.h> + +#include "nsock_internal.h" +#include "nsock_log.h" + +#if HAVE_PCAP +#include "nsock_pcap.h" +#endif + +extern struct io_operations posix_io_operations; + + +/* --- ENGINE INTERFACE PROTOTYPES --- */ +static int select_init(struct npool *nsp); +static void select_destroy(struct npool *nsp); +static int select_iod_register(struct npool *nsp, struct niod *iod, struct nevent *nse, int ev); +static int select_iod_unregister(struct npool *nsp, struct niod *iod); +static int select_iod_modify(struct npool *nsp, struct niod *iod, struct nevent *nse, int ev_set, int ev_clr); +static int select_loop(struct npool *nsp, int msec_timeout); + + +/* ---- ENGINE DEFINITION ---- */ +struct io_engine engine_select = { + "select", + select_init, + select_destroy, + select_iod_register, + select_iod_unregister, + select_iod_modify, + select_loop, + &posix_io_operations +}; + + +/* --- INTERNAL PROTOTYPES --- */ +static void iterate_through_event_lists(struct npool *nsp); + +/* defined in nsock_core.c */ +void process_event(struct npool *nsp, gh_list_t *evlist, struct nevent *nse, int ev); +void process_iod_events(struct npool *nsp, struct niod *nsi, int ev); +void process_expired_events(struct npool *nsp); + +#if HAVE_PCAP +#ifndef PCAP_CAN_DO_SELECT +int pcap_read_on_nonselect(struct npool *nsp); +#endif +#endif + +/* defined in nsock_event.c */ +void update_first_events(struct nevent *nse); + + +extern struct timeval nsock_tod; + + +/* + * Engine specific data structure + */ +struct select_engine_info { + /* Descriptors which have pending READ events */ + fd_set fds_master_r; + + /* Descriptors we are trying to WRITE to */ + fd_set fds_master_w; + + /* Looking for exceptional events -- used with connect */ + fd_set fds_master_x; + + /* For keeping track of the select results */ + fd_set fds_results_r, fds_results_w, fds_results_x; + + /* The highest sd we have set in any of our fd_set's (max_sd + 1 is used in + * select() calls). Note that it can be -1, when there are no valid sockets */ + int max_sd; +}; + + +int select_init(struct npool *nsp) { + struct select_engine_info *sinfo; + + sinfo = (struct select_engine_info *)safe_malloc(sizeof(struct select_engine_info)); + + FD_ZERO(&sinfo->fds_master_r); + FD_ZERO(&sinfo->fds_master_w); + FD_ZERO(&sinfo->fds_master_x); + + sinfo->max_sd = -1; + + nsp->engine_data = (void *)sinfo; + + return 1; +} + +void select_destroy(struct npool *nsp) { + assert(nsp->engine_data != NULL); + free(nsp->engine_data); +} + +int select_iod_register(struct npool *nsp, struct niod *iod, struct nevent *nse, int ev) { + assert(!IOD_PROPGET(iod, IOD_REGISTERED)); + + iod->watched_events = ev; + select_iod_modify(nsp, iod, nse, ev, EV_NONE); + IOD_PROPSET(iod, IOD_REGISTERED); + return 1; +} + +int select_iod_unregister(struct npool *nsp, struct niod *iod) { + struct select_engine_info *sinfo = (struct select_engine_info *)nsp->engine_data; + + iod->watched_events = EV_NONE; + + /* some IODs can be unregistered here if they're associated to an event that was + * immediately completed */ + if (IOD_PROPGET(iod, IOD_REGISTERED)) { +#if HAVE_PCAP + if (iod->pcap) { + int sd = ((mspcap *)iod->pcap)->pcap_desc; + if (sd >= 0) { + checked_fd_clr(sd, &sinfo->fds_master_r); + checked_fd_clr(sd, &sinfo->fds_results_r); + } + } else +#endif + { + checked_fd_clr(iod->sd, &sinfo->fds_master_r); + checked_fd_clr(iod->sd, &sinfo->fds_master_w); + checked_fd_clr(iod->sd, &sinfo->fds_master_x); + checked_fd_clr(iod->sd, &sinfo->fds_results_r); + checked_fd_clr(iod->sd, &sinfo->fds_results_w); + checked_fd_clr(iod->sd, &sinfo->fds_results_x); + } + + if (sinfo->max_sd == iod->sd) + sinfo->max_sd--; + + IOD_PROPCLR(iod, IOD_REGISTERED); + } + return 1; +} + +int select_iod_modify(struct npool *nsp, struct niod *iod, struct nevent *nse, int ev_set, int ev_clr) { + int sd; + struct select_engine_info *sinfo = (struct select_engine_info *)nsp->engine_data; + + assert((ev_set & ev_clr) == 0); + + iod->watched_events |= ev_set; + iod->watched_events &= ~ev_clr; + + ev_set |= EV_EXCEPT; + ev_clr &= ~EV_EXCEPT; + + sd = nsock_iod_get_sd(iod); + + /* -- set events -- */ + if (ev_set & EV_READ) + checked_fd_set(sd, &sinfo->fds_master_r); + + if (ev_set & EV_WRITE) + checked_fd_set(sd, &sinfo->fds_master_w); + + if (ev_set & EV_EXCEPT) + checked_fd_set(sd, &sinfo->fds_master_x); + + /* -- clear events -- */ + if (ev_clr & EV_READ) + checked_fd_clr(sd, &sinfo->fds_master_r); + + if (ev_clr & EV_WRITE) + checked_fd_clr(sd, &sinfo->fds_master_w); + + if (ev_clr & EV_EXCEPT) + checked_fd_clr(sd, &sinfo->fds_master_x); + + + /* -- update max_sd -- */ + if (ev_set != EV_NONE) + sinfo->max_sd = MAX(sinfo->max_sd, sd); + else if (ev_clr != EV_NONE && iod->events_pending == 1 && (sinfo->max_sd == sd)) + sinfo->max_sd--; + + return 1; +} + +int select_loop(struct npool *nsp, int msec_timeout) { + int results_left = 0; + int event_msecs; /* msecs before an event goes off */ + int combined_msecs; + int sock_err = 0; + struct timeval select_tv; + struct timeval *select_tv_p; + struct select_engine_info *sinfo = (struct select_engine_info *)nsp->engine_data; + + assert(msec_timeout >= -1); + + if (nsp->events_pending == 0) + return 0; /* No need to wait on 0 events ... */ + + do { + struct nevent *nse; + + nsock_log_debug_all("wait for events"); + + nse = next_expirable_event(nsp); + if (!nse) + event_msecs = -1; /* None of the events specified a timeout */ + else + event_msecs = MAX(0, TIMEVAL_MSEC_SUBTRACT(nse->timeout, nsock_tod)); + +#if HAVE_PCAP +#ifndef PCAP_CAN_DO_SELECT + /* Force a low timeout when capturing packets on systems where + * the pcap descriptor is not select()able. */ + if (gh_list_count(&nsp->pcap_read_events)) + if (event_msecs > PCAP_POLL_INTERVAL) + event_msecs = PCAP_POLL_INTERVAL; +#endif +#endif + + /* We cast to unsigned because we want -1 to be very high (since it means no + * timeout) */ + combined_msecs = MIN((unsigned)event_msecs, (unsigned)msec_timeout); + + /* Set up the timeval pointer we will give to select() */ + memset(&select_tv, 0, sizeof(select_tv)); + if (combined_msecs > 0) { + select_tv.tv_sec = combined_msecs / 1000; + select_tv.tv_usec = (combined_msecs % 1000) * 1000; + select_tv_p = &select_tv; + } else if (combined_msecs == 0) { + /* we want the tv_sec and tv_usec to be zero but they already are from bzero */ + select_tv_p = &select_tv; + } else { + assert(combined_msecs == -1); + select_tv_p = NULL; + } + +#if HAVE_PCAP +#ifndef PCAP_CAN_DO_SELECT + /* do non-blocking read on pcap devices that doesn't support select() + * If there is anything read, just leave this loop. */ + if (pcap_read_on_nonselect(nsp)) { + /* okay, something was read. */ + } else +#endif +#endif + { + /* Set up the descriptors for select */ + sinfo->fds_results_r = sinfo->fds_master_r; + sinfo->fds_results_w = sinfo->fds_master_w; + sinfo->fds_results_x = sinfo->fds_master_x; + + results_left = fselect(sinfo->max_sd + 1, &sinfo->fds_results_r, + &sinfo->fds_results_w, &sinfo->fds_results_x, select_tv_p); + + if (results_left == -1) + sock_err = socket_errno(); + } + + gettimeofday(&nsock_tod, NULL); /* Due to select delay */ + } while (results_left == -1 && sock_err == EINTR); /* repeat only if signal occurred */ + + if (results_left == -1 && sock_err != EINTR) { + nsock_log_error("nsock_loop error %d: %s", sock_err, socket_strerror(sock_err)); + nsp->errnum = sock_err; + return -1; + } + + iterate_through_event_lists(nsp); + + return 1; +} + + +/* ---- INTERNAL FUNCTIONS ---- */ + +static inline int get_evmask(const struct npool *nsp, const struct niod *nsi) { + struct select_engine_info *sinfo = (struct select_engine_info *)nsp->engine_data; + int sd, evmask; + + evmask = EV_NONE; + +#if HAVE_PCAP +#ifndef PCAP_CAN_DO_SELECT + if (nsi->pcap) { + /* Always assume readable for a non-blocking read. We can't check checked_fd_isset + because we don't have a pcap_desc. */ + evmask |= EV_READ; + return evmask; + } +#endif +#endif + +#if HAVE_PCAP + if (nsi->pcap) + sd = ((mspcap *)nsi->pcap)->pcap_desc; + else +#endif + sd = nsi->sd; + + assert(sd >= 0); + + if (checked_fd_isset(sd, &sinfo->fds_results_r)) + evmask |= EV_READ; + if (checked_fd_isset(sd, &sinfo->fds_results_w)) + evmask |= EV_WRITE; + if (checked_fd_isset(sd, &sinfo->fds_results_x)) + evmask |= EV_EXCEPT; + + return evmask; +} + +/* Iterate through all the event lists (such as connect_events, read_events, + * timer_events, etc) and take action for those that have completed (due to + * timeout, i/o, etc) */ +void iterate_through_event_lists(struct npool *nsp) { + gh_lnode_t *current, *next, *last; + + last = gh_list_last_elem(&nsp->active_iods); + + for (current = gh_list_first_elem(&nsp->active_iods); + current != NULL && gh_lnode_prev(current) != last; + current = next) { + struct niod *nsi = container_of(current, struct niod, nodeq); + + if (nsi->state != NSIOD_STATE_DELETED && nsi->events_pending) + process_iod_events(nsp, nsi, get_evmask(nsp, nsi)); + + next = gh_lnode_next(current); + if (nsi->state == NSIOD_STATE_DELETED) { + gh_list_remove(&nsp->active_iods, current); + gh_list_prepend(&nsp->free_iods, current); + } + } + + /* iterate through timers and expired events */ + process_expired_events(nsp); +} diff --git a/nsock/src/error.c b/nsock/src/error.c new file mode 100644 index 0000000..c7ecf98 --- /dev/null +++ b/nsock/src/error.c @@ -0,0 +1,85 @@ +/*************************************************************************** + * error.c -- a few simple routines for dealing with errors (quitting, * + * printing error messages, etc. * + * * + ***********************IMPORTANT NSOCK LICENSE TERMS*********************** + * + * The nsock parallel socket event library is (C) 1999-2023 Nmap Software LLC + * This library is free software; you may redistribute and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation; Version 2. This guarantees your right to use, modify, and + * redistribute this software under certain conditions. If this license is + * unacceptable to you, Nmap Software LLC may be willing to sell alternative + * licenses (contact sales@nmap.com ). + * + * As a special exception to the GPL terms, Nmap Software LLC grants permission + * to link the code of this program with any version of the OpenSSL library + * which is distributed under a license identical to that listed in the included + * docs/licenses/OpenSSL.txt file, and distribute linked combinations including + * the two. You must obey the GNU GPL in all respects for all of the code used + * other than OpenSSL. If you modify this file, you may extend this exception to + * your version of the file, but you are not obligated to do so. + * + * If you received these files with a written license agreement stating terms + * other than the (GPL) terms above, then that alternative license agreement + * takes precedence over this comment. + * + * Source is provided to this software because we believe users have a right to + * know exactly what a program is going to do before they run it. This also + * allows you to audit the software for security holes. + * + * Source code also allows you to port Nmap to new platforms, fix bugs, and add + * new features. You are highly encouraged to send your changes to the + * dev@nmap.org mailing list for possible incorporation into the main + * distribution. By sending these changes to Fyodor or one of the Insecure.Org + * development mailing lists, or checking them into the Nmap source code + * repository, it is understood (unless you specify otherwise) that you are + * offering the Nmap Project (Nmap Software LLC) the unlimited, non-exclusive + * right to reuse, modify, and relicense the code. Nmap will always be available + * Open Source, but this is important because the inability to relicense code + * has caused devastating problems for other Free Software projects (such as KDE + * and NASM). We also occasionally relicense the code to third parties as + * discussed above. If you wish to specify special license conditions of your + * contributions, just say so when you send them. + * + * 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 v2.0 for more + * details (http://www.gnu.org/licenses/gpl-2.0.html). + * + ***************************************************************************/ + +/* $Id$ */ + +#include "error.h" + +#include <stdio.h> +#include <stdlib.h> +#include <stdarg.h> + +void fatal(char *fmt, ...) { + va_list ap; + + va_start(ap, fmt); + fflush(stdout); + vfprintf(stderr, fmt, ap); + fprintf(stderr, "\n"); + va_end(ap); + + exit(1); +} + +void pfatal(char *fmt, ...) { + va_list ap; + + va_start(ap, fmt); + fflush(stdout); + vfprintf(stderr, fmt, ap); + fprintf(stderr, ": "); + perror(""); + fprintf(stderr, "\n"); + va_end(ap); + + exit(1); +} + diff --git a/nsock/src/error.h b/nsock/src/error.h new file mode 100644 index 0000000..48a7684 --- /dev/null +++ b/nsock/src/error.h @@ -0,0 +1,87 @@ +/*************************************************************************** + * error.h -- a few simple routines for dealing with errors (quitting, * + * printing error messages, etc. * + * * + ***********************IMPORTANT NSOCK LICENSE TERMS*********************** + * + * The nsock parallel socket event library is (C) 1999-2023 Nmap Software LLC + * This library is free software; you may redistribute and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation; Version 2. This guarantees your right to use, modify, and + * redistribute this software under certain conditions. If this license is + * unacceptable to you, Nmap Software LLC may be willing to sell alternative + * licenses (contact sales@nmap.com ). + * + * As a special exception to the GPL terms, Nmap Software LLC grants permission + * to link the code of this program with any version of the OpenSSL library + * which is distributed under a license identical to that listed in the included + * docs/licenses/OpenSSL.txt file, and distribute linked combinations including + * the two. You must obey the GNU GPL in all respects for all of the code used + * other than OpenSSL. If you modify this file, you may extend this exception to + * your version of the file, but you are not obligated to do so. + * + * If you received these files with a written license agreement stating terms + * other than the (GPL) terms above, then that alternative license agreement + * takes precedence over this comment. + * + * Source is provided to this software because we believe users have a right to + * know exactly what a program is going to do before they run it. This also + * allows you to audit the software for security holes. + * + * Source code also allows you to port Nmap to new platforms, fix bugs, and add + * new features. You are highly encouraged to send your changes to the + * dev@nmap.org mailing list for possible incorporation into the main + * distribution. By sending these changes to Fyodor or one of the Insecure.Org + * development mailing lists, or checking them into the Nmap source code + * repository, it is understood (unless you specify otherwise) that you are + * offering the Nmap Project (Nmap Software LLC) the unlimited, non-exclusive + * right to reuse, modify, and relicense the code. Nmap will always be available + * Open Source, but this is important because the inability to relicense code + * has caused devastating problems for other Free Software projects (such as KDE + * and NASM). We also occasionally relicense the code to third parties as + * discussed above. If you wish to specify special license conditions of your + * contributions, just say so when you send them. + * + * 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 v2.0 for more + * details (http://www.gnu.org/licenses/gpl-2.0.html). + * + ***************************************************************************/ + +/* $Id$ */ + +#ifndef ERROR_H +#define ERROR_H + +#ifdef HAVE_CONFIG_H +#include "nsock_config.h" +#include "nbase_config.h" +#endif + +#ifdef WIN32 +#include "nbase_winconfig.h" +#endif + +#include <stdarg.h> +#include <stdio.h> +#include <stdlib.h> +#if HAVE_UNISTD_H +#include <unistd.h> +#endif + +#if defined(__GNUC__) +#define NORETURN __attribute__((noreturn)) +#elif defined(_MSC_VER) +#define NORETURN __declspec(noreturn) +#else +#define NORETURN +#endif + +NORETURN void fatal(char *fmt, ...) + __attribute__ ((format (printf, 1, 2))); + +NORETURN void pfatal(char *fmt, ...) + __attribute__ ((format (printf, 1, 2))); + +#endif /* ERROR_H */ diff --git a/nsock/src/filespace.c b/nsock/src/filespace.c new file mode 100644 index 0000000..f4d5638 --- /dev/null +++ b/nsock/src/filespace.c @@ -0,0 +1,114 @@ +/*************************************************************************** + * filespace.c -- a simple mechanism for storing dynamic amounts of data * + * in a simple to use, and quick to append-to structure. * + * * + ***********************IMPORTANT NSOCK LICENSE TERMS*********************** + * + * The nsock parallel socket event library is (C) 1999-2023 Nmap Software LLC + * This library is free software; you may redistribute and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation; Version 2. This guarantees your right to use, modify, and + * redistribute this software under certain conditions. If this license is + * unacceptable to you, Nmap Software LLC may be willing to sell alternative + * licenses (contact sales@nmap.com ). + * + * As a special exception to the GPL terms, Nmap Software LLC grants permission + * to link the code of this program with any version of the OpenSSL library + * which is distributed under a license identical to that listed in the included + * docs/licenses/OpenSSL.txt file, and distribute linked combinations including + * the two. You must obey the GNU GPL in all respects for all of the code used + * other than OpenSSL. If you modify this file, you may extend this exception to + * your version of the file, but you are not obligated to do so. + * + * If you received these files with a written license agreement stating terms + * other than the (GPL) terms above, then that alternative license agreement + * takes precedence over this comment. + * + * Source is provided to this software because we believe users have a right to + * know exactly what a program is going to do before they run it. This also + * allows you to audit the software for security holes. + * + * Source code also allows you to port Nmap to new platforms, fix bugs, and add + * new features. You are highly encouraged to send your changes to the + * dev@nmap.org mailing list for possible incorporation into the main + * distribution. By sending these changes to Fyodor or one of the Insecure.Org + * development mailing lists, or checking them into the Nmap source code + * repository, it is understood (unless you specify otherwise) that you are + * offering the Nmap Project (Nmap Software LLC) the unlimited, non-exclusive + * right to reuse, modify, and relicense the code. Nmap will always be available + * Open Source, but this is important because the inability to relicense code + * has caused devastating problems for other Free Software projects (such as KDE + * and NASM). We also occasionally relicense the code to third parties as + * discussed above. If you wish to specify special license conditions of your + * contributions, just say so when you send them. + * + * 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 v2.0 for more + * details (http://www.gnu.org/licenses/gpl-2.0.html). + * + ***************************************************************************/ + +/* $Id$ */ + +#include "nsock_internal.h" +#include "filespace.h" + +#include <string.h> + +#define FS_INITSIZE_DEFAULT 1024 + + +/* Assumes space for fs has already been allocated */ +int filespace_init(struct filespace *fs, int initial_size) { + memset(fs, 0, sizeof(struct filespace)); + if (initial_size == 0) + initial_size = FS_INITSIZE_DEFAULT; + + fs->current_alloc = initial_size; + fs->str = (char *)safe_malloc(fs->current_alloc); + fs->str[0] = '\0'; + fs->pos = fs->str; + return 0; +} + +int fs_free(struct filespace *fs) { + if (fs->str) + free(fs->str); + + fs->current_alloc = fs->current_size = 0; + fs->pos = fs->str = NULL; + return 0; +} + +/* Concatenate a string to the end of a filespace */ +int fs_cat(struct filespace *fs, const char *str, int len) { + if (len < 0) + return -1; + + if (len == 0) + return 0; + + if (fs->current_alloc - fs->current_size < len + 2) { + char *tmpstr; + + fs->current_alloc = (int)(fs->current_alloc * 1.4 + 1); + fs->current_alloc += 100 + len; + + tmpstr = (char *)safe_malloc(fs->current_alloc); + memcpy(tmpstr, fs->str, fs->current_size); + + fs->pos = (fs->pos - fs->str) + tmpstr; + + if (fs->str) + free(fs->str); + + fs->str = tmpstr; + } + memcpy(fs->str + fs->current_size, str, len); + + fs->current_size += len; + fs->str[fs->current_size] = '\0'; + return 0; +} + diff --git a/nsock/src/filespace.h b/nsock/src/filespace.h new file mode 100644 index 0000000..cc44a9a --- /dev/null +++ b/nsock/src/filespace.h @@ -0,0 +1,102 @@ +/*************************************************************************** + * filespace.h -- a simple mechanism for storing dynamic amounts of data * + * in a simple to use, and quick to append-to structure. * + * * + ***********************IMPORTANT NSOCK LICENSE TERMS*********************** + * + * The nsock parallel socket event library is (C) 1999-2023 Nmap Software LLC + * This library is free software; you may redistribute and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation; Version 2. This guarantees your right to use, modify, and + * redistribute this software under certain conditions. If this license is + * unacceptable to you, Nmap Software LLC may be willing to sell alternative + * licenses (contact sales@nmap.com ). + * + * As a special exception to the GPL terms, Nmap Software LLC grants permission + * to link the code of this program with any version of the OpenSSL library + * which is distributed under a license identical to that listed in the included + * docs/licenses/OpenSSL.txt file, and distribute linked combinations including + * the two. You must obey the GNU GPL in all respects for all of the code used + * other than OpenSSL. If you modify this file, you may extend this exception to + * your version of the file, but you are not obligated to do so. + * + * If you received these files with a written license agreement stating terms + * other than the (GPL) terms above, then that alternative license agreement + * takes precedence over this comment. + * + * Source is provided to this software because we believe users have a right to + * know exactly what a program is going to do before they run it. This also + * allows you to audit the software for security holes. + * + * Source code also allows you to port Nmap to new platforms, fix bugs, and add + * new features. You are highly encouraged to send your changes to the + * dev@nmap.org mailing list for possible incorporation into the main + * distribution. By sending these changes to Fyodor or one of the Insecure.Org + * development mailing lists, or checking them into the Nmap source code + * repository, it is understood (unless you specify otherwise) that you are + * offering the Nmap Project (Nmap Software LLC) the unlimited, non-exclusive + * right to reuse, modify, and relicense the code. Nmap will always be available + * Open Source, but this is important because the inability to relicense code + * has caused devastating problems for other Free Software projects (such as KDE + * and NASM). We also occasionally relicense the code to third parties as + * discussed above. If you wish to specify special license conditions of your + * contributions, just say so when you send them. + * + * 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 v2.0 for more + * details (http://www.gnu.org/licenses/gpl-2.0.html). + * + ***************************************************************************/ + +/* $Id$ */ + +#ifndef FILESPACE_H +#define FILESPACE_H + +#ifdef HAVE_CONFIG_H +#include "nsock_config.h" +#include "nbase_config.h" +#endif + +#ifdef WIN32 +#include "nbase_winconfig.h" +#endif + +#include <stdlib.h> +#include <stdarg.h> +#if HAVE_STRING_H +#include <string.h> +#endif +#if HAVE_STRINGS_H +#include <strings.h> +#endif + + +struct filespace { + int current_size; + int current_alloc; + + /* Current position in the filespace */ + char *pos; + char *str; +}; + + +static inline int fs_length(const struct filespace *fs) { + return fs->current_size; +} + +static inline char *fs_str(const struct filespace *fs) { + return fs->str; +} + + +int filespace_init(struct filespace *fs, int initial_size); + +int fs_free(struct filespace *fs); + +int fs_cat(struct filespace *fs, const char *str, int len); + +#endif /* FILESPACE_H */ + diff --git a/nsock/src/gh_heap.c b/nsock/src/gh_heap.c new file mode 100644 index 0000000..2176574 --- /dev/null +++ b/nsock/src/gh_heap.c @@ -0,0 +1,250 @@ +/*************************************************************************** + * gh_heap.c -- heap based priority queue. * + * * + ***********************IMPORTANT NSOCK LICENSE TERMS*********************** + * + * The nsock parallel socket event library is (C) 1999-2023 Nmap Software LLC + * This library is free software; you may redistribute and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation; Version 2. This guarantees your right to use, modify, and + * redistribute this software under certain conditions. If this license is + * unacceptable to you, Nmap Software LLC may be willing to sell alternative + * licenses (contact sales@nmap.com ). + * + * As a special exception to the GPL terms, Nmap Software LLC grants permission + * to link the code of this program with any version of the OpenSSL library + * which is distributed under a license identical to that listed in the included + * docs/licenses/OpenSSL.txt file, and distribute linked combinations including + * the two. You must obey the GNU GPL in all respects for all of the code used + * other than OpenSSL. If you modify this file, you may extend this exception to + * your version of the file, but you are not obligated to do so. + * + * If you received these files with a written license agreement stating terms + * other than the (GPL) terms above, then that alternative license agreement + * takes precedence over this comment. + * + * Source is provided to this software because we believe users have a right to + * know exactly what a program is going to do before they run it. This also + * allows you to audit the software for security holes. + * + * Source code also allows you to port Nmap to new platforms, fix bugs, and add + * new features. You are highly encouraged to send your changes to the + * dev@nmap.org mailing list for possible incorporation into the main + * distribution. By sending these changes to Fyodor or one of the Insecure.Org + * development mailing lists, or checking them into the Nmap source code + * repository, it is understood (unless you specify otherwise) that you are + * offering the Nmap Project (Nmap Software LLC) the unlimited, non-exclusive + * right to reuse, modify, and relicense the code. Nmap will always be available + * Open Source, but this is important because the inability to relicense code + * has caused devastating problems for other Free Software projects (such as KDE + * and NASM). We also occasionally relicense the code to third parties as + * discussed above. If you wish to specify special license conditions of your + * contributions, just say so when you send them. + * + * 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 v2.0 for more + * details (http://www.gnu.org/licenses/gpl-2.0.html). + * + ***************************************************************************/ + +/* $Id$ */ + +#ifdef HAVE_CONFIG_H +#include "nsock_config.h" +#include "nbase_config.h" +#endif + +#ifdef WIN32 +#include "nbase_winconfig.h" +#endif + +#include <nbase.h> +#include "gh_heap.h" + +#define GH_SLOTS 128 + + +static gh_hnode_t **hnode_ptr(gh_heap_t *heap, unsigned int index) { + assert(index <= heap->count); + gh_hnode_t **ptr = &(heap->slots[index]); + assert(index == heap->count || (*ptr)->index == index); + return ptr; +} + +gh_hnode_t *gh_heap_find(gh_heap_t *heap, unsigned int index) { + if (index >= heap->count) + return NULL; + + return *hnode_ptr(heap, index); +} + +static int hnode_up(gh_heap_t *heap, gh_hnode_t *hnode) +{ + unsigned int cur_idx = hnode->index; + gh_hnode_t **cur_ptr = hnode_ptr(heap, cur_idx); + unsigned int parent_idx; + gh_hnode_t **parent_ptr; + int action = 0; + + assert(*cur_ptr == hnode); + + while (cur_idx > 0) { + parent_idx = (cur_idx - 1) >> 1; + + parent_ptr = hnode_ptr(heap, parent_idx); + + if (heap->cmp_op(*parent_ptr, hnode)) + break; + + (*parent_ptr)->index = cur_idx; + *cur_ptr = *parent_ptr; + cur_ptr = parent_ptr; + cur_idx = parent_idx; + action = 1; + } + + hnode->index = cur_idx; + *cur_ptr = hnode; + + return action; +} + +static int hnode_down(gh_heap_t *heap, gh_hnode_t *hnode) +{ + unsigned int count = heap->count; + unsigned int ch1_idx, ch2_idx, cur_idx; + gh_hnode_t **ch1_ptr, **ch2_ptr, **cur_ptr; + gh_hnode_t *ch1, *ch2; + int action = 0; + + cur_idx = hnode->index; + cur_ptr = hnode_ptr(heap, cur_idx); + assert(*cur_ptr == hnode); + + while (cur_idx < count) { + ch1_idx = (cur_idx << 1) + 1; + if (ch1_idx >= count) + break; + + ch1_ptr = hnode_ptr(heap, ch1_idx); + ch1 = *ch1_ptr; + + ch2_idx = ch1_idx + 1; + if (ch2_idx < count) { + ch2_ptr = hnode_ptr(heap, ch2_idx); + ch2 = *ch2_ptr; + + if (heap->cmp_op(ch2, ch1)) { + ch1_idx = ch2_idx; + ch1_ptr = ch2_ptr; + ch1 = ch2; + } + } + + assert(ch1->index == ch1_idx); + + if (heap->cmp_op(hnode, ch1)) + break; + + ch1->index = cur_idx; + *cur_ptr = ch1; + cur_ptr = ch1_ptr; + cur_idx = ch1_idx; + action = 1; + } + + hnode->index = cur_idx; + *cur_ptr = hnode; + + return action; +} + +static int heap_grow(gh_heap_t *heap) { + int newsize; + + /* Do we really need to grow? */ + assert(heap->count == heap->highwm); + + newsize = heap->count + GH_SLOTS; + heap->slots = (gh_hnode_t **)safe_realloc(heap->slots, + newsize * sizeof(gh_hnode_t *)); + heap->highwm += GH_SLOTS; + memset(heap->slots + heap->count, 0, GH_SLOTS * sizeof(gh_hnode_t *)); + return 0; +} + +int gh_heap_init(gh_heap_t *heap, gh_heap_cmp_t cmp_op) { + int rc; + + if (!cmp_op) + return -1; + + heap->cmp_op = cmp_op; + heap->count = 0; + heap->highwm = 0; + heap->slots = NULL; + + rc = heap_grow(heap); + if (rc) + gh_heap_free(heap); + + return rc; +} + +void gh_heap_free(gh_heap_t *heap) { + if (heap->highwm) { + assert(heap->slots); + free(heap->slots); + } + memset(heap, 0, sizeof(gh_heap_t)); +} + +int gh_heap_push(gh_heap_t *heap, gh_hnode_t *hnode) { + gh_hnode_t **new_ptr; + unsigned int new_index = heap->count; + + assert(!gh_hnode_is_valid(hnode)); + + if (new_index == heap->highwm) + heap_grow(heap); + + hnode->index = new_index; + new_ptr = hnode_ptr(heap, new_index); + assert(*new_ptr == NULL); + heap->count++; + *new_ptr = hnode; + + hnode_up(heap, hnode); + return 0; +} + +int gh_heap_remove(gh_heap_t *heap, gh_hnode_t *hnode) +{ + unsigned int count = heap->count; + unsigned int cur_idx = hnode->index; + gh_hnode_t **cur_ptr; + gh_hnode_t *last; + + assert(gh_hnode_is_valid(hnode)); + assert(cur_idx < count); + + cur_ptr = hnode_ptr(heap, cur_idx); + assert(*cur_ptr == hnode); + + count--; + last = *hnode_ptr(heap, count); + heap->count = count; + if (last != hnode) + { + last->index = cur_idx; + *cur_ptr = last; + if (!hnode_up(heap, *cur_ptr)) + hnode_down(heap, *cur_ptr); + } + + gh_hnode_invalidate(hnode); + cur_ptr = hnode_ptr(heap, count); + *cur_ptr = NULL; + return 0; +} diff --git a/nsock/src/gh_heap.h b/nsock/src/gh_heap.h new file mode 100644 index 0000000..0e67d9c --- /dev/null +++ b/nsock/src/gh_heap.h @@ -0,0 +1,143 @@ +/*************************************************************************** + * gh_heap.h -- heap based priority queues. * + * * + ***********************IMPORTANT NSOCK LICENSE TERMS*********************** + * + * The nsock parallel socket event library is (C) 1999-2023 Nmap Software LLC + * This library is free software; you may redistribute and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation; Version 2. This guarantees your right to use, modify, and + * redistribute this software under certain conditions. If this license is + * unacceptable to you, Nmap Software LLC may be willing to sell alternative + * licenses (contact sales@nmap.com ). + * + * As a special exception to the GPL terms, Nmap Software LLC grants permission + * to link the code of this program with any version of the OpenSSL library + * which is distributed under a license identical to that listed in the included + * docs/licenses/OpenSSL.txt file, and distribute linked combinations including + * the two. You must obey the GNU GPL in all respects for all of the code used + * other than OpenSSL. If you modify this file, you may extend this exception to + * your version of the file, but you are not obligated to do so. + * + * If you received these files with a written license agreement stating terms + * other than the (GPL) terms above, then that alternative license agreement + * takes precedence over this comment. + * + * Source is provided to this software because we believe users have a right to + * know exactly what a program is going to do before they run it. This also + * allows you to audit the software for security holes. + * + * Source code also allows you to port Nmap to new platforms, fix bugs, and add + * new features. You are highly encouraged to send your changes to the + * dev@nmap.org mailing list for possible incorporation into the main + * distribution. By sending these changes to Fyodor or one of the Insecure.Org + * development mailing lists, or checking them into the Nmap source code + * repository, it is understood (unless you specify otherwise) that you are + * offering the Nmap Project (Nmap Software LLC) the unlimited, non-exclusive + * right to reuse, modify, and relicense the code. Nmap will always be available + * Open Source, but this is important because the inability to relicense code + * has caused devastating problems for other Free Software projects (such as KDE + * and NASM). We also occasionally relicense the code to third parties as + * discussed above. If you wish to specify special license conditions of your + * contributions, just say so when you send them. + * + * 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 v2.0 for more + * details (http://www.gnu.org/licenses/gpl-2.0.html). + * + ***************************************************************************/ + +/* $Id$ */ + +#ifndef GH_HEAP_H +#define GH_HEAP_H + +#ifdef HAVE_CONFIG_H +#include "nsock_config.h" +#include "nbase_config.h" +#endif + +#ifdef WIN32 +#include "nbase_winconfig.h" +#endif + +#include "error.h" +#include <assert.h> + + +#if !defined(container_of) +#include <stddef.h> + +#define container_of(ptr, type, member) \ + ((type *)((char *)(ptr) - offsetof(type, member))) +#endif + + +typedef struct { + unsigned int index; +} gh_hnode_t; + +/* POISON value, set heap node index to this value to indicate that the node is + * inactive (not part of a heap) */ +#define GH_HEAP_GUARD 0x19890721 + +/* Node comparison function. + * Here lies all the intelligence of the tree. + * Return 1 if hnode1 < hnode2, 0 otherwise. */ +typedef int (*gh_heap_cmp_t)(gh_hnode_t *hnode1, gh_hnode_t *hnode2); + + +typedef struct gh_heap { + gh_heap_cmp_t cmp_op; + unsigned int count; + unsigned int highwm; + gh_hnode_t **slots; +} gh_heap_t; + + +int gh_heap_init(gh_heap_t *heap, gh_heap_cmp_t cmp_op); + +void gh_heap_free(gh_heap_t *heap); + +int gh_heap_push(gh_heap_t *heap, gh_hnode_t *node); + +int gh_heap_remove(gh_heap_t *heap, gh_hnode_t *node); + +gh_hnode_t *gh_heap_find(gh_heap_t *heap, unsigned int index); + + +static inline gh_hnode_t *gh_heap_min(gh_heap_t *heap) { + if (heap->count == 0) + return NULL; + + return gh_heap_find(heap, 0); +} + +static inline gh_hnode_t *gh_heap_pop(gh_heap_t *heap) { + gh_hnode_t *hnode; + + hnode = gh_heap_find(heap, 0); + if (hnode != NULL) + gh_heap_remove(heap, hnode); + + return hnode; +} + +static inline size_t gh_heap_count(gh_heap_t *heap) { + return heap->count; +} + +static inline int gh_heap_is_empty(gh_heap_t *heap) { + return heap->count == 0; +} + +static inline void gh_hnode_invalidate(gh_hnode_t *node) { + node->index = GH_HEAP_GUARD; +} + +static inline int gh_hnode_is_valid(const gh_hnode_t *node) { + return (node && node->index != GH_HEAP_GUARD); +} + +#endif /* GH_HEAP_H */ diff --git a/nsock/src/gh_list.h b/nsock/src/gh_list.h new file mode 100644 index 0000000..32f383e --- /dev/null +++ b/nsock/src/gh_list.h @@ -0,0 +1,296 @@ +/*************************************************************************** + * gh_list.h -- a simple doubly-linked list implementation. * + * * + ***********************IMPORTANT NSOCK LICENSE TERMS*********************** + * + * The nsock parallel socket event library is (C) 1999-2023 Nmap Software LLC + * This library is free software; you may redistribute and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation; Version 2. This guarantees your right to use, modify, and + * redistribute this software under certain conditions. If this license is + * unacceptable to you, Nmap Software LLC may be willing to sell alternative + * licenses (contact sales@nmap.com ). + * + * As a special exception to the GPL terms, Nmap Software LLC grants permission + * to link the code of this program with any version of the OpenSSL library + * which is distributed under a license identical to that listed in the included + * docs/licenses/OpenSSL.txt file, and distribute linked combinations including + * the two. You must obey the GNU GPL in all respects for all of the code used + * other than OpenSSL. If you modify this file, you may extend this exception to + * your version of the file, but you are not obligated to do so. + * + * If you received these files with a written license agreement stating terms + * other than the (GPL) terms above, then that alternative license agreement + * takes precedence over this comment. + * + * Source is provided to this software because we believe users have a right to + * know exactly what a program is going to do before they run it. This also + * allows you to audit the software for security holes. + * + * Source code also allows you to port Nmap to new platforms, fix bugs, and add + * new features. You are highly encouraged to send your changes to the + * dev@nmap.org mailing list for possible incorporation into the main + * distribution. By sending these changes to Fyodor or one of the Insecure.Org + * development mailing lists, or checking them into the Nmap source code + * repository, it is understood (unless you specify otherwise) that you are + * offering the Nmap Project (Nmap Software LLC) the unlimited, non-exclusive + * right to reuse, modify, and relicense the code. Nmap will always be available + * Open Source, but this is important because the inability to relicense code + * has caused devastating problems for other Free Software projects (such as KDE + * and NASM). We also occasionally relicense the code to third parties as + * discussed above. If you wish to specify special license conditions of your + * contributions, just say so when you send them. + * + * 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 v2.0 for more + * details (http://www.gnu.org/licenses/gpl-2.0.html). + * + ***************************************************************************/ + +/* $Id$ */ + +#ifndef GH_LIST_H +#define GH_LIST_H + +#ifdef HAVE_CONFIG_H +#include "nsock_config.h" +#include "nbase_config.h" +#endif + +#ifdef WIN32 +#include "nbase_winconfig.h" +#endif + +#include "error.h" +#include <assert.h> + +#define GH_LIST_MAGIC 0xBADFACE +#ifndef GH_LIST_PARANOID +#define GH_LIST_PARANOID 0 +#endif + + +typedef struct gh_list_node { + struct gh_list_node *next; + struct gh_list_node *prev; +} gh_lnode_t; + +typedef struct gh_list { + /* Number of elements in the list */ + unsigned int count; + gh_lnode_t *first; + gh_lnode_t *last; +} gh_list_t; + + +/* That one's an efficiency killer but it should reveal + * any inconsistency in nsock's lists management. To be + * called on every list we get and return. */ +static inline void paranoid_list_check(gh_list_t *list) { +#if GH_LIST_PARANOID + switch (list->count) { + case 0: + assert(list->first == NULL); + assert(list->last == NULL); + break; + + case 1: + assert(list->first); + assert(list->last); + assert(list->first == list->last); + break; + + default: + assert(list->first); + assert(list->last); + assert(list->first != list->last); + break; + } +#endif +} + +static inline int gh_list_init(gh_list_t *newlist) { + newlist->count = 0; + newlist->first = NULL; + newlist->last = NULL; + return 0; +} + +static inline int gh_list_append(gh_list_t *list, gh_lnode_t *lnode) { + gh_lnode_t *oldlast; + + paranoid_list_check(list); + + oldlast = list->last; + if (oldlast) + oldlast->next = lnode; + + lnode->prev = oldlast; + lnode->next = NULL; + + list->count++; + list->last = lnode; + + if (list->count == 1) + list->first = lnode; + + paranoid_list_check(list); + return 0; +} + +static inline int gh_list_prepend(gh_list_t *list, gh_lnode_t *lnode) { + gh_lnode_t *oldfirst; + + paranoid_list_check(list); + + oldfirst = list->first; + if (oldfirst) + oldfirst->prev = lnode; + + lnode->next = oldfirst; + lnode->prev = NULL; + + list->count++; + list->first = lnode; + + if (list->count == 1) + list->last = lnode; + + paranoid_list_check(list); + return 0; +} + +static inline int gh_list_insert_before(gh_list_t *list, gh_lnode_t *before, + gh_lnode_t *lnode) { + paranoid_list_check(list); + + lnode->prev = before->prev; + lnode->next = before; + + if (before->prev) + before->prev->next = lnode; + else + list->first = lnode; + + before->prev = lnode; + list->count++; + + paranoid_list_check(list); + return 0; +} + +static inline gh_lnode_t *gh_list_pop(gh_list_t *list) { + gh_lnode_t *elem; + + paranoid_list_check(list); + + elem = list->first; + if (!elem) { + paranoid_list_check(list); + return NULL; + } + + list->first = list->first->next; + if (list->first) + list->first->prev = NULL; + + list->count--; + + if (list->count < 2) + list->last = list->first; + + elem->prev = NULL; + elem->next = NULL; + + paranoid_list_check(list); + return elem; +} + +static inline int gh_list_remove(gh_list_t *list, gh_lnode_t *lnode) { + paranoid_list_check(list); + + if (lnode->prev) { + lnode->prev->next = lnode->next; + } else { + assert(list->first == lnode); + list->first = lnode->next; + } + + if (lnode->next) { + lnode->next->prev = lnode->prev; + } else { + assert(list->last == lnode); + list->last = lnode->prev; + } + + lnode->prev = NULL; + lnode->next = NULL; + + list->count--; + + paranoid_list_check(list); + return 0; +} + +static inline int gh_list_free(gh_list_t *list) { + paranoid_list_check(list); + + while (list->count > 0) + gh_list_pop(list); + + paranoid_list_check(list); + memset(list, 0, sizeof(gh_list_t)); + return 0; +} + +static inline int gh_list_move_front(gh_list_t *list, gh_lnode_t *lnode) { + paranoid_list_check(list); + if (list->first == lnode) + return 0; + + /* remove element from its current position */ + lnode->prev->next = lnode->next; + + if (lnode->next) { + lnode->next->prev = lnode->prev; + } else { + assert(list->last == lnode); + list->last = lnode->prev; + } + + /* add element to the beginning of the list */ + list->first->prev = lnode; + lnode->next = list->first; + lnode->prev = NULL; + list->first = lnode; + + paranoid_list_check(list); + return 0; +} + +/* Take a LIST ELEMENT (not just the data) and return the next one */ +static inline gh_lnode_t *gh_lnode_next(gh_lnode_t *elem) { + return elem->next; +} + +/* Same as above but return the previous element */ +static inline gh_lnode_t *gh_lnode_prev(gh_lnode_t *elem) { + return elem->prev; +} + +/* Take a LIST (not a list element) and return the first element */ +static inline gh_lnode_t *gh_list_first_elem(gh_list_t *list) { + return list->first; +} + +/* Same as above but return the last element */ +static inline gh_lnode_t *gh_list_last_elem(gh_list_t *list) { + return list->last; +} + +static inline unsigned int gh_list_count(gh_list_t *list) { + return list->count; +} + +#endif /* GH_LIST_H */ diff --git a/nsock/src/netutils.c b/nsock/src/netutils.c new file mode 100644 index 0000000..4523203 --- /dev/null +++ b/nsock/src/netutils.c @@ -0,0 +1,183 @@ +/*************************************************************************** + * netutils.c -- This contains some useful little network/socket related * + * utility functions. * + * * + ***********************IMPORTANT NSOCK LICENSE TERMS*********************** + * + * The nsock parallel socket event library is (C) 1999-2023 Nmap Software LLC + * This library is free software; you may redistribute and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation; Version 2. This guarantees your right to use, modify, and + * redistribute this software under certain conditions. If this license is + * unacceptable to you, Nmap Software LLC may be willing to sell alternative + * licenses (contact sales@nmap.com ). + * + * As a special exception to the GPL terms, Nmap Software LLC grants permission + * to link the code of this program with any version of the OpenSSL library + * which is distributed under a license identical to that listed in the included + * docs/licenses/OpenSSL.txt file, and distribute linked combinations including + * the two. You must obey the GNU GPL in all respects for all of the code used + * other than OpenSSL. If you modify this file, you may extend this exception to + * your version of the file, but you are not obligated to do so. + * + * If you received these files with a written license agreement stating terms + * other than the (GPL) terms above, then that alternative license agreement + * takes precedence over this comment. + * + * Source is provided to this software because we believe users have a right to + * know exactly what a program is going to do before they run it. This also + * allows you to audit the software for security holes. + * + * Source code also allows you to port Nmap to new platforms, fix bugs, and add + * new features. You are highly encouraged to send your changes to the + * dev@nmap.org mailing list for possible incorporation into the main + * distribution. By sending these changes to Fyodor or one of the Insecure.Org + * development mailing lists, or checking them into the Nmap source code + * repository, it is understood (unless you specify otherwise) that you are + * offering the Nmap Project (Nmap Software LLC) the unlimited, non-exclusive + * right to reuse, modify, and relicense the code. Nmap will always be available + * Open Source, but this is important because the inability to relicense code + * has caused devastating problems for other Free Software projects (such as KDE + * and NASM). We also occasionally relicense the code to third parties as + * discussed above. If you wish to specify special license conditions of your + * contributions, just say so when you send them. + * + * 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 v2.0 for more + * details (http://www.gnu.org/licenses/gpl-2.0.html). + * + ***************************************************************************/ + +/* $Id$ */ + +#include "netutils.h" +#include "error.h" + +#if WIN32 +#include "Winsock2.h" +#endif + +#if HAVE_SYS_TIME_H +#include <sys/time.h> +#endif +#if HAVE_SYS_RESOURCE_H +#include <sys/resource.h> +#endif +#if HAVE_UNISTD_H +#include <unistd.h> +#endif +#if HAVE_NETINET_IN_H +#include <netinet/in.h> +#endif +#if HAVE_SYS_TYPES_H +#include <sys/types.h> +#endif +#if HAVE_SYS_SOCKET_H +#include <sys/socket.h> +#endif +#if HAVE_FCNTL_H +#include <fcntl.h> +#endif +#if HAVE_SYS_UN_H +#include <sys/un.h> +#endif + +static int netutils_debugging = 0; + +/* maximize the number of file descriptors (including sockets) allowed for this + * process and return that maximum value (note -- you better not actually open + * this many -- stdin, stdout, other files opened by libraries you use, etc. all + * count toward this limit. Leave a little slack */ +rlim_t maximize_fdlimit(void) { + +#ifndef WIN32 + struct rlimit r; + static int maxfds_set = 0; + static rlim_t maxfds = 0; + + if (maxfds_set) + return maxfds; + +#ifndef RLIMIT_NOFILE + #ifdef RLIMIT_OFILE + #define RLIMIT_NOFILE RLIMIT_OFILE + #else + #error Neither RLIMIT_NOFILE nor RLIMIT_OFILE defined + #endif +#endif + if (!getrlimit(RLIMIT_NOFILE, &r)) { + maxfds = r.rlim_cur; + r.rlim_cur = r.rlim_max; + if (!setrlimit(RLIMIT_NOFILE, &r)) + if (netutils_debugging) + perror("setrlimit RLIMIT_NOFILE failed"); + + if (!getrlimit(RLIMIT_NOFILE, &r)) { + maxfds = r.rlim_cur; + } + maxfds_set = 1; + return maxfds; + } +#endif /* !WIN32 */ + return 0; +} + +#if HAVE_SYS_UN_H + #define PEER_STR_LEN sizeof(((struct sockaddr_un *) 0)->sun_path) +#else + #define PEER_STR_LEN sizeof("[ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255]:xxxxx") +#endif + +#if HAVE_SYS_UN_H +/* Get the UNIX domain socket path or empty string if the address family != AF_UNIX. */ +const char *get_unixsock_path(const struct sockaddr_storage *addr) { + struct sockaddr_un *su = (struct sockaddr_un *)addr; + + if (!addr || addr->ss_family != AF_UNIX) + return ""; + + return (const char *)su->sun_path; +} +#endif + +static int get_port(const struct sockaddr_storage *ss) { + if (ss->ss_family == AF_INET) + return ntohs(((struct sockaddr_in *) ss)->sin_port); +#if HAVE_IPV6 + else if (ss->ss_family == AF_INET6) + return ntohs(((struct sockaddr_in6 *) ss)->sin6_port); +#endif + + return -1; +} + +static char *get_addr_string(const struct sockaddr_storage *ss, size_t sslen) { + static char buffer[PEER_STR_LEN]; + +#if HAVE_SYS_UN_H + if (ss->ss_family == AF_UNIX) { + sprintf(buffer, "%s", get_unixsock_path(ss)); + return buffer; + } +#endif + + sprintf(buffer, "%s:%d", inet_ntop_ez(ss, sslen), get_port(ss)); + return buffer; +} + +/* Get the peer/host address string. + * In case we have support for UNIX domain sockets, function returns + * string containing path to UNIX socket if the address family is AF_UNIX, + * otherwise it returns string containing "<address>:<port>". */ +char *get_peeraddr_string(const struct niod *iod) { + if (iod->peerlen > 0) + return get_addr_string(&iod->peer, iod->peerlen); + else + return "peer unspecified"; +} + +/* Get the local bind address string. */ +char *get_localaddr_string(const struct niod *iod) { + return get_addr_string(&iod->local, iod->locallen); +} diff --git a/nsock/src/netutils.h b/nsock/src/netutils.h new file mode 100644 index 0000000..893a9f6 --- /dev/null +++ b/nsock/src/netutils.h @@ -0,0 +1,103 @@ +/*************************************************************************** + * netutils.h -- This contains some useful little network/socket related * + * utility functions. * + * * + ***********************IMPORTANT NSOCK LICENSE TERMS*********************** + * + * The nsock parallel socket event library is (C) 1999-2023 Nmap Software LLC + * This library is free software; you may redistribute and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation; Version 2. This guarantees your right to use, modify, and + * redistribute this software under certain conditions. If this license is + * unacceptable to you, Nmap Software LLC may be willing to sell alternative + * licenses (contact sales@nmap.com ). + * + * As a special exception to the GPL terms, Nmap Software LLC grants permission + * to link the code of this program with any version of the OpenSSL library + * which is distributed under a license identical to that listed in the included + * docs/licenses/OpenSSL.txt file, and distribute linked combinations including + * the two. You must obey the GNU GPL in all respects for all of the code used + * other than OpenSSL. If you modify this file, you may extend this exception to + * your version of the file, but you are not obligated to do so. + * + * If you received these files with a written license agreement stating terms + * other than the (GPL) terms above, then that alternative license agreement + * takes precedence over this comment. + * + * Source is provided to this software because we believe users have a right to + * know exactly what a program is going to do before they run it. This also + * allows you to audit the software for security holes. + * + * Source code also allows you to port Nmap to new platforms, fix bugs, and add + * new features. You are highly encouraged to send your changes to the + * dev@nmap.org mailing list for possible incorporation into the main + * distribution. By sending these changes to Fyodor or one of the Insecure.Org + * development mailing lists, or checking them into the Nmap source code + * repository, it is understood (unless you specify otherwise) that you are + * offering the Nmap Project (Nmap Software LLC) the unlimited, non-exclusive + * right to reuse, modify, and relicense the code. Nmap will always be available + * Open Source, but this is important because the inability to relicense code + * has caused devastating problems for other Free Software projects (such as KDE + * and NASM). We also occasionally relicense the code to third parties as + * discussed above. If you wish to specify special license conditions of your + * contributions, just say so when you send them. + * + * 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 v2.0 for more + * details (http://www.gnu.org/licenses/gpl-2.0.html). + * + ***************************************************************************/ + +/* $Id$ */ + +#ifndef NETUTILS_H +#define NETUTILS_H + +#ifdef HAVE_CONFIG_H +#include "nsock_config.h" +#include "nbase_config.h" +#endif + +#if HAVE_NETINET_IN_H +#include <netinet/in.h> +#endif + +#include "nsock_internal.h" + +#ifdef WIN32 +#include "nbase_winconfig.h" +/* nbase_winunix.h somehow reason.h to get included */ +#include "nbase_winunix.h" +#endif + +#if HAVE_SYS_UN_H +#include <sys/un.h> +#endif + +#if HAVE_SYS_RESOURCE_H +#include <sys/resource.h> +#else +#ifndef rlim_t +#define rlim_t int +#endif +#endif +/* Maximize the number of file descriptors (including sockets) allowed for this + * process and return that maximum value (note -- you better not actually open + * this many -- stdin, stdout, other files opened by libraries you use, etc. all + * count toward this limit. Leave a little slack */ +rlim_t maximize_fdlimit(void); + +/* Get the UNIX domain socket path or empty string if the address family != AF_UNIX. */ +const char *get_unixsock_path(const struct sockaddr_storage *addr); + +/* Get the peer address string. In case of a Unix domain socket, returns the + * path to UNIX socket, otherwise it returns string containing + * "<address>:<port>". */ +char *get_peeraddr_string(const struct niod *iod); + +/* Get the local bind address string. */ +char *get_localaddr_string(const struct niod *iod); + +#endif /* NETUTILS_H */ + diff --git a/nsock/src/nsock_connect.c b/nsock/src/nsock_connect.c new file mode 100644 index 0000000..7d2b523 --- /dev/null +++ b/nsock/src/nsock_connect.c @@ -0,0 +1,652 @@ +/*************************************************************************** + * nsock_connect.c -- This contains the functions for requesting TCP * + * connections from the nsock parallel socket event library * + ***********************IMPORTANT NSOCK LICENSE TERMS*********************** + * + * The nsock parallel socket event library is (C) 1999-2023 Nmap Software LLC + * This library is free software; you may redistribute and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation; Version 2. This guarantees your right to use, modify, and + * redistribute this software under certain conditions. If this license is + * unacceptable to you, Nmap Software LLC may be willing to sell alternative + * licenses (contact sales@nmap.com ). + * + * As a special exception to the GPL terms, Nmap Software LLC grants permission + * to link the code of this program with any version of the OpenSSL library + * which is distributed under a license identical to that listed in the included + * docs/licenses/OpenSSL.txt file, and distribute linked combinations including + * the two. You must obey the GNU GPL in all respects for all of the code used + * other than OpenSSL. If you modify this file, you may extend this exception to + * your version of the file, but you are not obligated to do so. + * + * If you received these files with a written license agreement stating terms + * other than the (GPL) terms above, then that alternative license agreement + * takes precedence over this comment. + * + * Source is provided to this software because we believe users have a right to + * know exactly what a program is going to do before they run it. This also + * allows you to audit the software for security holes. + * + * Source code also allows you to port Nmap to new platforms, fix bugs, and add + * new features. You are highly encouraged to send your changes to the + * dev@nmap.org mailing list for possible incorporation into the main + * distribution. By sending these changes to Fyodor or one of the Insecure.Org + * development mailing lists, or checking them into the Nmap source code + * repository, it is understood (unless you specify otherwise) that you are + * offering the Nmap Project (Nmap Software LLC) the unlimited, non-exclusive + * right to reuse, modify, and relicense the code. Nmap will always be available + * Open Source, but this is important because the inability to relicense code + * has caused devastating problems for other Free Software projects (such as KDE + * and NASM). We also occasionally relicense the code to third parties as + * discussed above. If you wish to specify special license conditions of your + * contributions, just say so when you send them. + * + * 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 v2.0 for more + * details (http://www.gnu.org/licenses/gpl-2.0.html). + * + ***************************************************************************/ + +/* $Id$ */ + +#include "nsock.h" +#include "nsock_internal.h" +#include "nsock_log.h" +#include "nsock_proxy.h" +#include "netutils.h" + +#include <sys/types.h> +#include <errno.h> +#include <string.h> + + +static int mksock_bind_addr(struct npool *ms, struct niod *iod) { + int rc; + int one = 1; + + rc = setsockopt(iod->sd, SOL_SOCKET, SO_REUSEADDR, (const char *)&one, sizeof(one)); + if (rc == -1) { + int err = socket_errno(); + + nsock_log_error("Setting of SO_REUSEADDR failed (#%li): %s (%d)", iod->id, + socket_strerror(err), err); + } + + nsock_log_info("Binding to %s (IOD #%li)", get_localaddr_string(iod), iod->id); + rc = bind(iod->sd, (struct sockaddr *)&iod->local, (int) iod->locallen); + if (rc == -1) { + int err = socket_errno(); + + nsock_log_error("Bind to %s failed (IOD #%li): %s (%d)", + get_localaddr_string(iod), iod->id, + socket_strerror(err), err); + } + return 0; +} + +static int mksock_set_ipopts(struct npool *ms, struct niod *iod) { + int rc; + + errno = 0; + rc = setsockopt(iod->sd, IPPROTO_IP, IP_OPTIONS, (const char *)iod->ipopts, + iod->ipoptslen); + if (rc == -1) { + int err = socket_errno(); + + nsock_log_error("Setting of IP options failed (IOD #%li): %s (%d)", + iod->id, socket_strerror(err), err); + } + return 0; +} + +static int mksock_bind_device(struct npool *ms, struct niod *iod) { + int rc; + + rc = socket_bindtodevice(iod->sd, ms->device); + if (!rc) { + int err = socket_errno(); + + if (err != EPERM) + nsock_log_error("Setting of SO_BINDTODEVICE failed (IOD #%li): %s (%d)", + iod->id, socket_strerror(err), err); + else + nsock_log_debug_all("Setting of SO_BINDTODEVICE failed (IOD #%li): %s (%d)", + iod->id, socket_strerror(err), err); + } + return 0; +} + +static int mksock_set_broadcast(struct npool *ms, struct niod *iod) { + int rc; + int one = 1; + + rc = setsockopt(iod->sd, SOL_SOCKET, SO_BROADCAST, + (const char *)&one, sizeof(one)); + if (rc == -1) { + int err = socket_errno(); + + nsock_log_error("Setting of SO_BROADCAST failed (IOD #%li): %s (%d)", + iod->id, socket_strerror(err), err); + } + return 0; +} +/* Create the actual socket (nse->iod->sd) underlying the iod. This unblocks the + * socket, binds to the localaddr address, sets IP options, and sets the + * broadcast flag. Trying to change these functions after making this call will + * not have an effect. This function needs to be called before you try to read + * or write on the iod. */ +static int nsock_make_socket(struct npool *ms, struct niod *iod, int family, int type, int proto) { + + /* inheritable_socket is from nbase */ + iod->sd = (int)inheritable_socket(family, type, proto); + if (iod->sd == -1) { + nsock_log_error("Socket trouble: %s", socket_strerror(socket_errno())); + return -1; + } + + unblock_socket(iod->sd); + + iod->lastproto = proto; + + if (iod->locallen) + mksock_bind_addr(ms, iod); + + if (iod->ipoptslen && family == AF_INET) + mksock_set_ipopts(ms, iod); + + if (ms->device) + mksock_bind_device(ms, iod); + + if (ms->broadcast && type != SOCK_STREAM) + mksock_set_broadcast(ms, iod); + + /* mksock_* functions can raise warnings/errors + * but we don't let them stop us for now. */ + return iod->sd; +} + +int nsock_setup_udp(nsock_pool nsp, nsock_iod ms_iod, int af) { + struct npool *ms = (struct npool *)nsp; + struct niod *nsi = (struct niod *)ms_iod; + + assert(nsi->state == NSIOD_STATE_INITIAL || nsi->state == NSIOD_STATE_UNKNOWN); + + nsock_log_info("UDP unconnected socket (IOD #%li)", nsi->id); + + if (nsock_make_socket(ms, nsi, af, SOCK_DGRAM, IPPROTO_UDP) == -1) + return -1; + + return nsi->sd; +} + +/* This does the actual logistics of requesting a connection. It is shared + * by nsock_connect_tcp and nsock_connect_ssl, among others */ +void nsock_connect_internal(struct npool *ms, struct nevent *nse, int type, int proto, struct sockaddr_storage *ss, size_t sslen, + unsigned int port) { + + struct sockaddr_in *sin; +#if HAVE_IPV6 + struct sockaddr_in6 *sin6; +#endif + struct niod *iod = nse->iod; + + if (iod->px_ctx /* proxy enabled */ + && proto == IPPROTO_TCP /* restrict proxying to TCP connections */ + && (nse->handler != nsock_proxy_ev_dispatch)) { /* for reentrancy */ + struct proxy_node *current; + + nsock_log_debug_all("TCP connection request (EID %lu) redirected through proxy chain", + (long)nse->id); + + current = iod->px_ctx->px_current; + assert(current != NULL); + + memcpy(&iod->px_ctx->target_ss, ss, sslen); + iod->px_ctx->target_sslen = sslen; + iod->px_ctx->target_port = port; + + ss = ¤t->ss; + sslen = current->sslen; + port = current->port; + + iod->px_ctx->target_handler = nse->handler; + nse->handler = nsock_proxy_ev_dispatch; + + iod->px_ctx->target_ev_type = nse->type; + nse->type = NSE_TYPE_CONNECT; + } + + sin = (struct sockaddr_in *)ss; +#if HAVE_IPV6 + sin6 = (struct sockaddr_in6 *)ss; +#endif + + /* Now it is time to actually attempt the connection */ + if (nsock_make_socket(ms, iod, ss->ss_family, type, proto) == -1) { + nse->event_done = 1; + nse->status = NSE_STATUS_ERROR; + nse->errnum = socket_errno(); + } else { + if (ss->ss_family == AF_INET) { + sin->sin_port = htons(port); + } +#if HAVE_IPV6 + else if (ss->ss_family == AF_INET6) { + sin6->sin6_port = htons(port); + } +#endif +#if HAVE_SYS_UN_H + else if (ss->ss_family == AF_UNIX) { + /* Nothing more to do for Unix socket */ + } +#endif +#if HAVE_LINUX_VM_SOCKETS_H + else if (ss->ss_family == AF_VSOCK) { + struct sockaddr_vm *svm = (struct sockaddr_vm *)ss; + + svm->svm_port = port; + } +#endif + else { + fatal("Unknown address family %d\n", ss->ss_family); + } + + assert(sslen <= sizeof(iod->peer)); + if (&iod->peer != ss) + memcpy(&iod->peer, ss, sslen); + iod->peerlen = sslen; + + if (ms->engine->io_operations->iod_connect(ms, iod->sd, (struct sockaddr *)ss, sslen) == -1) { + int err = socket_errno(); + + if ((proto == IPPROTO_UDP) || (err != EINPROGRESS && err != EAGAIN)) { + nse->event_done = 1; + nse->status = NSE_STATUS_ERROR; + nse->errnum = err; + } + } + /* The callback handle_connect_result handles the connection once it completes. */ + } +} + +#if HAVE_SYS_UN_H + +/* Request a UNIX domain sockets connection to the same system (by path to socket). + * This function connects to the socket of type SOCK_STREAM. ss should be a + * sockaddr_storage, sockaddr_un as appropriate (just like what you would pass to + * connect). sslen should be the sizeof the structure you are passing in. */ +nsock_event_id nsock_connect_unixsock_stream(nsock_pool nsp, nsock_iod nsiod, nsock_ev_handler handler, int timeout_msecs, + void *userdata, struct sockaddr *saddr, size_t sslen) { + struct niod *nsi = (struct niod *)nsiod; + struct npool *ms = (struct npool *)nsp; + struct nevent *nse; + struct sockaddr_storage *ss = (struct sockaddr_storage *)saddr; + + assert(nsi->state == NSIOD_STATE_INITIAL || nsi->state == NSIOD_STATE_UNKNOWN); + + nse = event_new(ms, NSE_TYPE_CONNECT, nsi, timeout_msecs, handler, userdata); + assert(nse); + + nsock_log_info("UNIX domain socket (STREAM) connection requested to %s (IOD #%li) EID %li", + get_unixsock_path(ss), nsi->id, nse->id); + + nsock_connect_internal(ms, nse, SOCK_STREAM, 0, ss, sslen, 0); + nsock_pool_add_event(ms, nse); + + return nse->id; + +} + +/* Request a UNIX domain sockets connection to the same system (by path to socket). + * This function connects to the socket of type SOCK_DGRAM. ss should be a + * sockaddr_storage, sockaddr_un as appropriate (just like what you would pass to + * connect). sslen should be the sizeof the structure you are passing in. */ +nsock_event_id nsock_connect_unixsock_datagram(nsock_pool nsp, nsock_iod nsiod, nsock_ev_handler handler, + void *userdata, struct sockaddr *saddr, size_t sslen) { + struct niod *nsi = (struct niod *)nsiod; + struct npool *ms = (struct npool *)nsp; + struct nevent *nse; + struct sockaddr_storage *ss = (struct sockaddr_storage *)saddr; + + assert(nsi->state == NSIOD_STATE_INITIAL || nsi->state == NSIOD_STATE_UNKNOWN); + + nse = event_new(ms, NSE_TYPE_CONNECT, nsi, -1, handler, userdata); + assert(nse); + + nsock_log_info("UNIX domain socket (DGRAM) connection requested to %s (IOD #%li) EID %li", + get_unixsock_path(ss), nsi->id, nse->id); + + nsock_connect_internal(ms, nse, SOCK_DGRAM, 0, ss, sslen, 0); + nsock_pool_add_event(ms, nse); + + return nse->id; +} + +#endif /* HAVE_SYS_UN_H */ + +#if HAVE_LINUX_VM_SOCKETS_H +/* Request a vsock stream connection to another system. ss should be a + * sockaddr_storage or sockaddr_vm, as appropriate (just like what you would + * pass to connect). sslen should be the sizeof the structure you are passing + * in. */ +nsock_event_id nsock_connect_vsock_stream(nsock_pool nsp, nsock_iod ms_iod, + nsock_ev_handler handler, + int timeout_msecs, void *userdata, + struct sockaddr *saddr, size_t sslen, + unsigned int port) { + struct niod *nsi = (struct niod *)ms_iod; + struct npool *ms = (struct npool *)nsp; + struct nevent *nse; + struct sockaddr_storage *ss = (struct sockaddr_storage *)saddr; + struct sockaddr_vm *svm = (struct sockaddr_vm *)saddr; + + assert(nsi->state == NSIOD_STATE_INITIAL || nsi->state == NSIOD_STATE_UNKNOWN); + + nse = event_new(ms, NSE_TYPE_CONNECT, nsi, timeout_msecs, handler, userdata); + assert(nse); + + nsock_log_info("vsock stream connection requested to %u:%u (IOD #%li) EID %li", + svm->svm_cid, port, nsi->id, nse->id); + + /* Do the actual connect() */ + nsock_connect_internal(ms, nse, SOCK_STREAM, 0, ss, sslen, port); + nsock_pool_add_event(ms, nse); + + return nse->id; +} + +/* Request a vsock datagram "connection" to another system. Since this is a + * datagram socket, no packets are actually sent. The destination CID and port + * are just associated with the nsiod (an actual OS connect() call is made). + * You can then use the normal nsock write calls on the socket. There is no + * timeout since this call always calls your callback at the next opportunity. + * The advantages to having a connected datagram socket (as opposed to just + * specifying an address with sendto() are that we can now use a consistent set + * of write/read calls for stream and datagram sockets, received packets from + * the non-partner are automatically dropped by the OS, and the OS can provide + * asynchronous errors (see Unix Network Programming pp224). ss should be a + * sockaddr_storage or sockaddr_vm, as appropriate (just like what you would + * pass to connect). sslen should be the sizeof the structure you are passing + * in. */ +nsock_event_id nsock_connect_vsock_datagram(nsock_pool nsp, nsock_iod nsiod, + nsock_ev_handler handler, + void *userdata, + struct sockaddr *saddr, + size_t sslen, unsigned int port) { + struct niod *nsi = (struct niod *)nsiod; + struct npool *ms = (struct npool *)nsp; + struct nevent *nse; + struct sockaddr_storage *ss = (struct sockaddr_storage *)saddr; + struct sockaddr_vm *svm = (struct sockaddr_vm *)saddr; + + assert(nsi->state == NSIOD_STATE_INITIAL || nsi->state == NSIOD_STATE_UNKNOWN); + + nse = event_new(ms, NSE_TYPE_CONNECT, nsi, -1, handler, userdata); + assert(nse); + + nsock_log_info("vsock dgram connection requested to %u:%u (IOD #%li) EID %li", + svm->svm_cid, port, nsi->id, nse->id); + + nsock_connect_internal(ms, nse, SOCK_DGRAM, 0, ss, sslen, port); + nsock_pool_add_event(ms, nse); + + return nse->id; +} +#endif /* HAVE_LINUX_VM_SOCKETS_H */ + +/* Request a TCP connection to another system (by IP address). The in_addr is + * normal network byte order, but the port number should be given in HOST BYTE + * ORDER. ss should be a sockaddr_storage, sockaddr_in6, or sockaddr_in as + * appropriate (just like what you would pass to connect). sslen should be the + * sizeof the structure you are passing in. */ +nsock_event_id nsock_connect_tcp(nsock_pool nsp, nsock_iod ms_iod, nsock_ev_handler handler, int timeout_msecs, + void *userdata, struct sockaddr *saddr, size_t sslen, unsigned short port) { + struct niod *nsi = (struct niod *)ms_iod; + struct npool *ms = (struct npool *)nsp; + struct nevent *nse; + struct sockaddr_storage *ss = (struct sockaddr_storage *)saddr; + + assert(nsi->state == NSIOD_STATE_INITIAL || nsi->state == NSIOD_STATE_UNKNOWN); + + nse = event_new(ms, NSE_TYPE_CONNECT, nsi, timeout_msecs, handler, userdata); + assert(nse); + + nsock_log_info("TCP connection requested to %s:%hu (IOD #%li) EID %li", + inet_ntop_ez(ss, sslen), port, nsi->id, nse->id); + + /* Do the actual connect() */ + nsock_connect_internal(ms, nse, SOCK_STREAM, IPPROTO_TCP, ss, sslen, port); + nsock_pool_add_event(ms, nse); + + return nse->id; +} + +/* Request an SCTP association to another system (by IP address). The in_addr + * is normal network byte order, but the port number should be given in HOST + * BYTE ORDER. ss should be a sockaddr_storage, sockaddr_in6, or sockaddr_in as + * appropriate (just like what you would pass to connect). sslen should be the + * sizeof the structure you are passing in. */ +nsock_event_id nsock_connect_sctp(nsock_pool nsp, nsock_iod ms_iod, nsock_ev_handler handler, int timeout_msecs, + void *userdata, struct sockaddr *saddr, size_t sslen, unsigned short port) { + + struct niod *nsi = (struct niod *)ms_iod; + struct npool *ms = (struct npool *)nsp; + struct nevent *nse; + struct sockaddr_storage *ss = (struct sockaddr_storage *)saddr; + + assert(nsi->state == NSIOD_STATE_INITIAL || nsi->state == NSIOD_STATE_UNKNOWN); + + nse = event_new(ms, NSE_TYPE_CONNECT, nsi, timeout_msecs, handler, userdata); + assert(nse); + + nsock_log_info("SCTP association requested to %s:%hu (IOD #%li) EID %li", + inet_ntop_ez(ss, sslen), port, nsi->id, nse->id); + + /* Do the actual connect() */ + nsock_connect_internal(ms, nse, SOCK_STREAM, IPPROTO_SCTP, ss, sslen, port); + nsock_pool_add_event(ms, nse); + + return nse->id; +} + +/* Request an SSL over TCP/SCTP/UDP connection to another system (by IP address). + * The in_addr is normal network byte order, but the port number should be given + * in HOST BYTE ORDER. This function will call back only after it has made the + * connection AND done the initial SSL negotiation. From that point on, you use + * the normal read/write calls and decryption will happen transparently. ss + * should be a sockaddr_storage, sockaddr_in6, or sockaddr_in as appropriate + * (just like what you would pass to connect). sslen should be the sizeof the + * structure you are passing in. */ +nsock_event_id nsock_connect_ssl(nsock_pool nsp, nsock_iod nsiod, nsock_ev_handler handler, int timeout_msecs, + void *userdata, struct sockaddr *saddr, size_t sslen, int proto, unsigned short port, nsock_ssl_session ssl_session) { + +#ifndef HAVE_OPENSSL + fatal("nsock_connect_ssl called - but nsock was built w/o SSL support. QUITTING"); + return (nsock_event_id)0; /* UNREACHED */ +#else + struct sockaddr_storage *ss = (struct sockaddr_storage *)saddr; + struct niod *nsi = (struct niod *)nsiod; + struct npool *ms = (struct npool *)nsp; + struct nevent *nse; + + if (proto == IPPROTO_UDP) + { + if (!ms->dtlsctx) + nsock_pool_dtls_init(ms, 0); + } + else + { + if (!ms->sslctx) + nsock_pool_ssl_init(ms, 0); + } + + assert(nsi->state == NSIOD_STATE_INITIAL || nsi->state == NSIOD_STATE_UNKNOWN); + + nse = event_new(ms, NSE_TYPE_CONNECT_SSL, nsi, timeout_msecs, handler, userdata); + assert(nse); + + /* Set our SSL_SESSION so we can benefit from session-id reuse. */ + /* but not with DTLS; save space in ClientHello message */ + if (proto != IPPROTO_UDP) + nsi_set_ssl_session(nsi, (SSL_SESSION *)ssl_session); + + if (proto == IPPROTO_UDP) + nsock_log_info("DTLS connection requested to %s:%hu/udp (IOD #%li) EID %li", + + inet_ntop_ez(ss, sslen), port, nsi->id, nse->id); + else + nsock_log_info("SSL connection requested to %s:%hu/%s (IOD #%li) EID %li", + inet_ntop_ez(ss, sslen), port, (proto == IPPROTO_TCP ? "tcp" : "sctp"), + nsi->id, nse->id); + + /* Do the actual connect() */ + nsock_connect_internal(ms, nse, (proto == IPPROTO_UDP ? SOCK_DGRAM : SOCK_STREAM), proto, ss, sslen, port); + + nsock_pool_add_event(ms, nse); + + return nse->id; +#endif /* HAVE_OPENSSL */ +} + +/* Request ssl connection over already established connection. nsiod must be + * socket that is already connected to target using nsock_connect_tcp or + * nsock_connect_sctp. All parameters have the same meaning as in + * 'nsock_connect_ssl' */ +nsock_event_id nsock_reconnect_ssl(nsock_pool nsp, nsock_iod nsiod, nsock_ev_handler handler, int timeout_msecs, + void *userdata, nsock_ssl_session ssl_session) { + +#ifndef HAVE_OPENSSL + fatal("nsock_reconnect_ssl called - but nsock was built w/o SSL support. QUITTING"); + return (nsock_event_id) 0; /* UNREACHED */ +#else + struct niod *nsi = (struct niod *)nsiod; + struct npool *ms = (struct npool *)nsp; + struct nevent *nse; + /* nsock_reconnect_ssl not supported for DTLS (yet?) */ + assert(nsi->lastproto != IPPROTO_UDP); + + if (!ms->sslctx) + nsock_pool_ssl_init(ms, 0); + + nse = event_new(ms, NSE_TYPE_CONNECT_SSL, nsi, timeout_msecs, handler, userdata); + assert(nse); + + /* Set our SSL_SESSION so we can benefit from session-id reuse. */ + nsi_set_ssl_session(nsi, (SSL_SESSION *)ssl_session); + + nsock_log_info("SSL reconnection requested (IOD #%li) EID %li", + nsi->id, nse->id); + + /* Do the actual connect() */ + nse->event_done = 0; + nse->status = NSE_STATUS_SUCCESS; + nsock_pool_add_event(ms, nse); + + return nse->id; +#endif /* HAVE_OPENSSL */ +} + +/* Request a UDP "connection" to another system (by IP address). The in_addr is + * normal network byte order, but the port number should be given in HOST BYTE + * ORDER. Since this is UDP, no packets are actually sent. The destination IP + * and port are just associated with the nsiod (an actual OS connect() call is + * made). You can then use the normal nsock write calls on the socket. There + * is no timeout since this call always calls your callback at the next + * opportunity. The advantages to having a connected UDP socket (as opposed to + * just specifying an address with sendto() are that we can now use a consistent + * set of write/read calls for TCP/UDP, received packets from the non-partner + * are automatically dropped by the OS, and the OS can provide asynchronous + * errors (see Unix Network Programming pp224). ss should be a + * sockaddr_storage, sockaddr_in6, or sockaddr_in as appropriate (just like what + * you would pass to connect). sslen should be the sizeof the structure you are + * passing in. */ +nsock_event_id nsock_connect_udp(nsock_pool nsp, nsock_iod nsiod, nsock_ev_handler handler, void *userdata, + struct sockaddr *saddr, size_t sslen, unsigned short port) { + + struct niod *nsi = (struct niod *)nsiod; + struct npool *ms = (struct npool *)nsp; + struct nevent *nse; + struct sockaddr_storage *ss = (struct sockaddr_storage *)saddr; + + assert(nsi->state == NSIOD_STATE_INITIAL || nsi->state == NSIOD_STATE_UNKNOWN); + + nse = event_new(ms, NSE_TYPE_CONNECT, nsi, -1, handler, userdata); + assert(nse); + + nsock_log_info("UDP connection requested to %s:%hu (IOD #%li) EID %li", + inet_ntop_ez(ss, sslen), port, nsi->id, nse->id); + + nsock_connect_internal(ms, nse, SOCK_DGRAM, IPPROTO_UDP, ss, sslen, port); + nsock_pool_add_event(ms, nse); + + return nse->id; +} + +/* Returns that host/port/protocol information for the last communication (or + * comm. attempt) this nsi has been involved with. By "involved" with I mean + * interactions like establishing (or trying to) a connection or sending a UDP + * datagram through an unconnected nsock_iod. AF is the address family (AF_INET + * or AF_INET6), Protocl is IPPROTO_TCP or IPPROTO_UDP. Pass NULL for + * information you do not need. If ANY of the information you requested is not + * available, 0 will be returned and the unavailable sockets are zeroed. If + * protocol or af is requested but not available, it will be set to -1 (and 0 + * returned). The pointers you pass in must be NULL or point to allocated + * address space. The sockaddr members should actually be sockaddr_storage, + * sockaddr_in6, or sockaddr_in with the socklen of them set appropriately (eg + * sizeof(sockaddr_storage) if that is what you are passing). */ +int nsock_iod_get_communication_info(nsock_iod iod, int *protocol, int *af, + struct sockaddr *local, + struct sockaddr *remote, size_t socklen) { + struct niod *nsi = (struct niod *)iod; + int ret = 1; + struct sockaddr_storage ss; + socklen_t slen = sizeof(ss); + int res; + + assert(socklen > 0); + + if (nsi->peerlen > 0) { + if (remote) + memcpy(remote, &(nsi->peer), MIN((unsigned)socklen, nsi->peerlen)); + if (protocol) { + *protocol = nsi->lastproto; + if (*protocol == -1) res = 0; + } + if (af) { + *af = nsi->peer.ss_family; + } + if (local) { + if (nsi->sd >= 0) { + res = getsockname(nsi->sd, (struct sockaddr *)&ss, &slen); + if (res == -1) { + memset(local, 0, socklen); + ret = 0; + } else { + assert(slen > 0); + memcpy(local, &ss, MIN((unsigned)slen, socklen)); + } + } else { + memset(local, 0, socklen); + ret = 0; + } + } + } else { + if (local || remote || protocol || af) + ret = 0; + + if (remote) + memset(remote, 0, socklen); + + if (local) + memset(local, 0, socklen); + + if (protocol) + *protocol = -1; + + if (af) + *af = -1; + } + return ret; +} + diff --git a/nsock/src/nsock_core.c b/nsock/src/nsock_core.c new file mode 100644 index 0000000..fa2aef6 --- /dev/null +++ b/nsock/src/nsock_core.c @@ -0,0 +1,1415 @@ +/*************************************************************************** + * nsock_core.c -- This contains the core engine routines for the nsock * + * parallel socket event library. * + * * + ***********************IMPORTANT NSOCK LICENSE TERMS*********************** + * + * The nsock parallel socket event library is (C) 1999-2023 Nmap Software LLC + * This library is free software; you may redistribute and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation; Version 2. This guarantees your right to use, modify, and + * redistribute this software under certain conditions. If this license is + * unacceptable to you, Nmap Software LLC may be willing to sell alternative + * licenses (contact sales@nmap.com ). + * + * As a special exception to the GPL terms, Nmap Software LLC grants permission + * to link the code of this program with any version of the OpenSSL library + * which is distributed under a license identical to that listed in the included + * docs/licenses/OpenSSL.txt file, and distribute linked combinations including + * the two. You must obey the GNU GPL in all respects for all of the code used + * other than OpenSSL. If you modify this file, you may extend this exception to + * your version of the file, but you are not obligated to do so. + * + * If you received these files with a written license agreement stating terms + * other than the (GPL) terms above, then that alternative license agreement + * takes precedence over this comment. + * + * Source is provided to this software because we believe users have a right to + * know exactly what a program is going to do before they run it. This also + * allows you to audit the software for security holes. + * + * Source code also allows you to port Nmap to new platforms, fix bugs, and add + * new features. You are highly encouraged to send your changes to the + * dev@nmap.org mailing list for possible incorporation into the main + * distribution. By sending these changes to Fyodor or one of the Insecure.Org + * development mailing lists, or checking them into the Nmap source code + * repository, it is understood (unless you specify otherwise) that you are + * offering the Nmap Project (Nmap Software LLC) the unlimited, non-exclusive + * right to reuse, modify, and relicense the code. Nmap will always be available + * Open Source, but this is important because the inability to relicense code + * has caused devastating problems for other Free Software projects (such as KDE + * and NASM). We also occasionally relicense the code to third parties as + * discussed above. If you wish to specify special license conditions of your + * contributions, just say so when you send them. + * + * 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 v2.0 for more + * details (http://www.gnu.org/licenses/gpl-2.0.html). + * + ***************************************************************************/ + +/* $Id$ */ + +#include "nsock_internal.h" +#include "gh_list.h" +#include "filespace.h" +#include "nsock_log.h" + +#include <assert.h> +#if HAVE_ERRNO_H +#include <errno.h> +#endif +#if HAVE_SYS_TYPES_H +#include <sys/types.h> +#endif +#if HAVE_SYS_SOCKET_H +#include <sys/socket.h> +#endif +#if HAVE_NETINET_IN_H +#include <netinet/in.h> +#endif +#if HAVE_ARPA_INET_H +#include <arpa/inet.h> +#endif +#if HAVE_STRING_H +#include <string.h> +#endif + +#include "netutils.h" + +#if HAVE_PCAP +#include "nsock_pcap.h" +#endif + +/* Nsock time of day -- we update this at least once per nsock_loop round (and + * after most calls that are likely to block). Other nsock files should grab + * this */ +struct timeval nsock_tod; + +/* Internal function defined in nsock_event.c + * Update the nse->iod first events, assuming nse is about to be deleted */ +void update_first_events(struct nevent *nse); + + + +/* Each iod has a count of pending socket reads, socket writes, and pcap reads. + * When a descriptor's count is nonzero, its bit must be set in the appropriate + * master fd_set, and when the count is zero the bit must be cleared. What we + * are simulating is an fd_set with a counter for each socket instead of just an + * on/off switch. The fd_set's bits aren't enough by itself because a descriptor + * may for example have two reads pending at once, and the bit must not be + * cleared after the first is completed. + * The socket_count_* functions return the event to transmit to update_events() + */ +int socket_count_zero(struct niod *iod, struct npool *ms) { + iod->readsd_count = 0; + iod->writesd_count = 0; +#if HAVE_PCAP + iod->readpcapsd_count = 0; +#endif + return nsock_engine_iod_unregister(ms, iod); +} + +static int socket_count_read_inc(struct niod *iod) { + assert(iod->readsd_count >= 0); + iod->readsd_count++; + return EV_READ; +} + +static int socket_count_read_dec(struct niod *iod) { + assert(iod->readsd_count > 0); + iod->readsd_count--; + return (iod->readsd_count == 0) ? EV_READ : EV_NONE; +} + +static int socket_count_write_inc(struct niod *iod) { + assert(iod->writesd_count >= 0); + iod->writesd_count++; + return EV_WRITE; +} + +static int socket_count_write_dec(struct niod *iod) { + assert(iod->writesd_count > 0); + iod->writesd_count--; + return (iod->writesd_count == 0) ? EV_WRITE : EV_NONE; +} + +#if HAVE_PCAP +static int socket_count_readpcap_inc(struct niod *iod) { + assert(iod->readpcapsd_count >= 0); + iod->readpcapsd_count++; + return EV_READ; +} + +static int socket_count_readpcap_dec(struct niod *iod) { + assert(iod->readpcapsd_count > 0); + iod->readpcapsd_count--; + return (iod->readpcapsd_count == 0) ? EV_READ : EV_NONE; +} +#endif + +#if HAVE_OPENSSL +/* Call socket_count_read_dec or socket_count_write_dec on nse->iod depending on + * the current value of nse->sslinfo.ssl_desire. */ +static int socket_count_dec_ssl_desire(struct nevent *nse) { + assert(nse->iod->ssl != NULL); + assert(nse->sslinfo.ssl_desire == SSL_ERROR_WANT_READ || + nse->sslinfo.ssl_desire == SSL_ERROR_WANT_WRITE); + + if (nse->sslinfo.ssl_desire == SSL_ERROR_WANT_READ) + return socket_count_read_dec(nse->iod); + else + return socket_count_write_dec(nse->iod); +} +#endif + +static int should_clear_ev_read(const struct niod *iod, int ev_set) { + return (ev_set & EV_READ) && +#if HAVE_PCAP + !iod->readpcapsd_count && +#endif + !iod->readsd_count; +} + +static int should_clear_ev_write(const struct niod *iod, int ev_set) { + return (ev_set & EV_WRITE) && !iod->writesd_count; +} + +/* Update the events that the IO engine should watch for a given IOD. + * + * ev_inc is a set of events for which the event counters should be increased. + * These events will therefore be watched by the IO engine for this IOD. + * + * ev_dec is a set of events for which the event counters should be decreased. + * If this counter reaches zero, the event won't be watched anymore by the + * IO engine for this IOD. + */ +static void update_events(struct niod * iod, struct npool *ms, struct nevent *nse, int ev_inc, int ev_dec) { + int setmask, clrmask, ev_temp; + + /* Filter out events that belong to both sets. */ + ev_temp = ev_inc ^ ev_dec; + ev_inc = ev_inc & ev_temp; + ev_dec = ev_dec & ev_temp; + + setmask = ev_inc; + clrmask = EV_NONE; + + if (should_clear_ev_read(iod, ev_dec)) + clrmask |= EV_READ; + + if (should_clear_ev_write(iod, ev_dec)) + clrmask |= EV_WRITE; + + /* EV_EXCEPT is systematically set and cannot be removed */ + if (ev_inc & EV_EXCEPT) + nsock_log_info("Invalid event set, no need to specify EV_EXCEPT"); + + if (ev_dec & EV_EXCEPT) + nsock_log_info("Invalid event set, refusing to clear EV_EXCEPT"); + + if (!IOD_PROPGET(iod, IOD_REGISTERED)) { + assert(clrmask == EV_NONE); + nsock_engine_iod_register(ms, iod, nse, setmask); + } else { + nsock_engine_iod_modify(ms, iod, nse, setmask, clrmask); + } +} + +/* Add a new event for a given IOD. nevents are stored in separate event lists + * (in the nsock pool) and are grouped by IOD within each list. + * + * This function appends the event _before_ the first similar event we have for + * the given IOD, or append it to the end of the list if no similar event is + * already present. + * + * Note that adding the event before the similar ones is important for + * reentrancy, as it will prevent the new event to be processed in the event + * loop just after its addition. + */ +static int iod_add_event(struct niod *iod, struct nevent *nse) { + struct npool *nsp = iod->nsp; + + switch (nse->type) { + case NSE_TYPE_CONNECT: + case NSE_TYPE_CONNECT_SSL: + if (iod->first_connect) + gh_list_insert_before(&nsp->connect_events, + iod->first_connect, &nse->nodeq_io); + else + gh_list_append(&nsp->connect_events, &nse->nodeq_io); + iod->first_connect = &nse->nodeq_io; + break; + + case NSE_TYPE_READ: + if (iod->first_read) + gh_list_insert_before(&nsp->read_events, iod->first_read, &nse->nodeq_io); + else + gh_list_append(&nsp->read_events, &nse->nodeq_io); + iod->first_read = &nse->nodeq_io; + break; + + case NSE_TYPE_WRITE: + if (iod->first_write) + gh_list_insert_before(&nsp->write_events, iod->first_write, &nse->nodeq_io); + else + gh_list_append(&nsp->write_events, &nse->nodeq_io); + iod->first_write = &nse->nodeq_io; + break; + +#if HAVE_PCAP + case NSE_TYPE_PCAP_READ: { + char add_read = 0, add_pcap_read = 0; + +#if PCAP_BSD_SELECT_HACK + /* BSD hack mode: add event to both read and pcap_read lists */ + add_read = add_pcap_read = 1; +#else + if (((mspcap *)iod->pcap)->pcap_desc >= 0) { + add_read = 1; + } else { + add_pcap_read = 1; + } +#endif + if (add_read) { + if (iod->first_read) + gh_list_insert_before(&nsp->read_events, iod->first_read, &nse->nodeq_io); + else + gh_list_append(&nsp->read_events, &nse->nodeq_io); + iod->first_read = &nse->nodeq_io; + } + if (add_pcap_read) { + if (iod->first_pcap_read) + gh_list_insert_before(&nsp->pcap_read_events, iod->first_pcap_read, + &nse->nodeq_pcap); + else + gh_list_append(&nsp->pcap_read_events, &nse->nodeq_pcap); + iod->first_pcap_read = &nse->nodeq_pcap; + } + break; + } +#endif + + default: + fatal("Unknown event type (%d) for IOD #%lu\n", nse->type, iod->id); + } + + return 0; +} + +/* A handler function is defined for each of the main event types (read, write, + * connect, timer, etc) -- the handler is called when new information is + * available for the event. The handler makes any necessary updates to the + * event based on any new information available. If the event becomes ready for + * delivery, the handler sets nse->event_done and fills out the relevant event + * fields (status, errnum) as applicable. The handlers also take care of event + * type specific teardown (such as clearing socket descriptors from select/poll + * lists). If event_done is not set, the handler will be called again in the + * case of more information or an event timeout */ + +/* The event type handlers -- the first three arguments of each are the same: + * struct npool *ms struct nevent *nse -- the event we have new info on enum nse_status -- + * The reason for the call, usually NSE_STATUS_SUCCESS (which generally means a + * successful I/O call or NSE_STATUS_TIMEOUT or NSE_STATUS_CANCELLED + * + * Some of the event type handlers have other parameters, specific to their + * needs. All the handlers can assume that the calling function has checked + * that select or poll said their descriptors were readable/writeable (as + * appropriate). + * + * The idea is that each handler will take care of the stuff that is specific + * to it and the calling function will handle the stuff that can be generalized + * to dispatching/deleting/etc. all events. But the calling function may use + * type-specific info to determine whether the handler should be called at all + * (to save CPU time). */ + +/* handle_connect_results assumes that select or poll have already shown the + * descriptor to be active */ +void handle_connect_result(struct npool *ms, struct nevent *nse, enum nse_status status) { + int optval; + socklen_t optlen = sizeof(int); + struct niod *iod = nse->iod; + assert(iod != NULL); +#if HAVE_OPENSSL + int sslerr; + int rc = 0; + int sslconnect_inprogress = nse->type == NSE_TYPE_CONNECT_SSL && nse->iod && + (nse->sslinfo.ssl_desire == SSL_ERROR_WANT_READ || + nse->sslinfo.ssl_desire == SSL_ERROR_WANT_WRITE); + SSL_CTX *sslctx = NULL; +#else + int sslconnect_inprogress = 0; +#endif + + if (status == NSE_STATUS_TIMEOUT || status == NSE_STATUS_CANCELLED) { + nse->status = status; + nse->event_done = 1; + } else if (sslconnect_inprogress) { + /* Do nothing */ + } else if (status == NSE_STATUS_SUCCESS) { + /* First we want to determine whether the socket really is connected */ + if (getsockopt(iod->sd, SOL_SOCKET, SO_ERROR, (char *)&optval, &optlen) != 0) + optval = socket_errno(); /* Stupid Solaris */ + + if (optval == 0) { + nse->status = NSE_STATUS_SUCCESS; + } + else { + nse->status = NSE_STATUS_ERROR; + nse->errnum = optval; + } + + /* Now special code for the SSL case where the TCP connection was successful. */ + if (nse->type == NSE_TYPE_CONNECT_SSL && + nse->status == NSE_STATUS_SUCCESS) { +#if HAVE_OPENSSL + sslctx = iod->lastproto == IPPROTO_UDP ? ms->dtlsctx : ms->sslctx; + assert(sslctx != NULL); + /* Reuse iod->ssl if present. If set, this is the second try at connection + without the SSL_OP_NO_SSLv2 option set. */ + if (iod->ssl == NULL) { + iod->ssl = SSL_new(sslctx); + if (!iod->ssl) + fatal("SSL_new failed: %s", ERR_error_string(ERR_get_error(), NULL)); + } + +#if HAVE_SSL_SET_TLSEXT_HOST_NAME + /* Avoid sending SNI extension with DTLS because many servers don't allow + * fragmented ClientHello messages. */ + if (iod->hostname != NULL && iod->lastproto != IPPROTO_UDP) { + if (SSL_set_tlsext_host_name(iod->ssl, iod->hostname) != 1) + fatal("SSL_set_tlsext_host_name failed: %s", ERR_error_string(ERR_get_error(), NULL)); + } +#endif + + /* Associate our new SSL with the connected socket. It will inherit the + * non-blocking nature of the sd */ + if (SSL_set_fd(iod->ssl, iod->sd) != 1) + fatal("SSL_set_fd failed: %s", ERR_error_string(ERR_get_error(), NULL)); + + /* Event not done -- need to do SSL connect below */ + nse->sslinfo.ssl_desire = SSL_ERROR_WANT_CONNECT; +#endif + } else { + /* This is not an SSL connect (in which case we are always done), or the + * TCP connect() underlying the SSL failed (in which case we are also done */ + nse->event_done = 1; + } + } else { + fatal("Unknown status (%d)", status); + } + + /* At this point the TCP connection is done, whether successful or not. + * Therefore decrease the read/write listen counts that were incremented in + * nsock_pool_add_event. In the SSL case, we may increase one of the counts depending + * on whether SSL_connect returns an error of SSL_ERROR_WANT_READ or + * SSL_ERROR_WANT_WRITE. In that case we will re-enter this function, but we + * don't want to execute this block again. */ + if (iod->sd != -1 && !sslconnect_inprogress) { + int ev = EV_NONE; + + ev |= socket_count_read_dec(iod); + ev |= socket_count_write_dec(iod); + update_events(iod, ms, nse, EV_NONE, ev); + } + +#if HAVE_OPENSSL + if (nse->type == NSE_TYPE_CONNECT_SSL && !nse->event_done) { + /* Lets now start/continue/finish the connect! */ + if (iod->ssl_session) { + rc = SSL_set_session(iod->ssl, iod->ssl_session); + if (rc == 0) + nsock_log_error("Uh-oh: SSL_set_session() failed - please tell dev@nmap.org"); + iod->ssl_session = NULL; /* No need for this any more */ + } + + /* If this is a reinvocation of handle_connect_result, clear out the listen + * bits that caused it, based on the previous SSL desire. */ + if (sslconnect_inprogress) { + int ev; + + ev = socket_count_dec_ssl_desire(nse); + update_events(iod, ms, nse, EV_NONE, ev); + } + + rc = SSL_connect(iod->ssl); + if (rc == 1) { + /* Woop! Connect is done! */ + nse->event_done = 1; + /* Check that certificate verification was okay, if requested. */ + if (nsi_ssl_post_connect_verify(iod)) { + nse->status = NSE_STATUS_SUCCESS; + } else { + nsock_log_error("certificate verification error for EID %li: %s", + nse->id, ERR_error_string(ERR_get_error(), NULL)); + nse->status = NSE_STATUS_ERROR; + } + } else { +#if SSL_OP_NO_SSLv2 != 0 + long options = SSL_get_options(iod->ssl); +#endif + + sslerr = SSL_get_error(iod->ssl, rc); + if (sslerr == SSL_ERROR_WANT_READ) { + nse->sslinfo.ssl_desire = sslerr; + socket_count_read_inc(iod); + update_events(iod, ms, nse, EV_READ, EV_NONE); + } else if (sslerr == SSL_ERROR_WANT_WRITE) { + nse->sslinfo.ssl_desire = sslerr; + socket_count_write_inc(iod); + update_events(iod, ms, nse, EV_WRITE, EV_NONE); +#if SSL_OP_NO_SSLv2 != 0 + } else if (iod->lastproto != IPPROTO_UDP && !(options & SSL_OP_NO_SSLv2)) { + /* SSLv2 does not apply to DTLS, so ensure lastproto was not UDP. */ + int saved_ev; + + /* SSLv3-only and TLSv1-only servers can't be connected to when the + * SSL_OP_NO_SSLv2 option is not set, which is the case when the pool + * was initialized with nsock_pool_ssl_init_max_speed. Try reconnecting + * with SSL_OP_NO_SSLv2. Never downgrade a NO_SSLv2 connection to one + * that might use SSLv2. */ + nsock_log_info("EID %li reconnecting with SSL_OP_NO_SSLv2", nse->id); + + saved_ev = iod->watched_events; + nsock_engine_iod_unregister(ms, iod); + close(iod->sd); + nsock_connect_internal(ms, nse, SOCK_STREAM, iod->lastproto, &iod->peer, + iod->peerlen, nsock_iod_get_peerport(iod)); + nsock_engine_iod_register(ms, iod, nse, saved_ev); + + /* Use SSL_free here because SSL_clear keeps session info, which + * doesn't work when changing SSL versions (as we're clearly trying to + * do by adding SSL_OP_NO_SSLv2). */ + SSL_free(iod->ssl); + iod->ssl = SSL_new(ms->sslctx); + if (!iod->ssl) + fatal("SSL_new failed: %s", ERR_error_string(ERR_get_error(), NULL)); + + SSL_set_options(iod->ssl, options | SSL_OP_NO_SSLv2); + socket_count_read_inc(nse->iod); + socket_count_write_inc(nse->iod); + update_events(iod, ms, nse, EV_READ|EV_WRITE, EV_NONE); + nse->sslinfo.ssl_desire = SSL_ERROR_WANT_CONNECT; +#endif + } else { + nsock_log_info("EID %li %s", + nse->id, ERR_error_string(ERR_get_error(), NULL)); + nse->event_done = 1; + nse->status = NSE_STATUS_ERROR; + nse->errnum = EIO; + } + } + } +#endif +} + +static int errcode_is_failure(int err) { +#ifndef WIN32 + return err != EINTR && err != EAGAIN && err != EBUSY; +#else + return err != EINTR && err != EAGAIN; +#endif +} + +void handle_write_result(struct npool *ms, struct nevent *nse, enum nse_status status) { + int bytesleft; + char *str; + int res; + int err; + struct niod *iod = nse->iod; + + if (status == NSE_STATUS_TIMEOUT || status == NSE_STATUS_CANCELLED) { + nse->event_done = 1; + nse->status = status; + } else if (status == NSE_STATUS_SUCCESS) { + str = fs_str(&nse->iobuf) + nse->writeinfo.written_so_far; + bytesleft = fs_length(&nse->iobuf) - nse->writeinfo.written_so_far; + if (nse->writeinfo.written_so_far > 0) + assert(bytesleft > 0); +#if HAVE_OPENSSL + if (iod->ssl) + res = SSL_write(iod->ssl, str, bytesleft); + else +#endif + res = ms->engine->io_operations->iod_write(ms, nse->iod->sd, str, bytesleft, 0, (struct sockaddr *)&nse->writeinfo.dest, (int)nse->writeinfo.destlen); + if (res == bytesleft) { + nse->event_done = 1; + nse->status = NSE_STATUS_SUCCESS; + } else if (res >= 0) { + nse->writeinfo.written_so_far += res; + } else { + assert(res == -1); + if (iod->ssl) { +#if HAVE_OPENSSL + err = SSL_get_error(iod->ssl, res); + if (err == SSL_ERROR_WANT_READ) { + int evclr; + + evclr = socket_count_dec_ssl_desire(nse); + socket_count_read_inc(iod); + update_events(iod, ms, nse, EV_READ, evclr); + nse->sslinfo.ssl_desire = err; + } else if (err == SSL_ERROR_WANT_WRITE) { + int evclr; + + evclr = socket_count_dec_ssl_desire(nse); + socket_count_write_inc(iod); + update_events(iod, ms, nse, EV_WRITE, evclr); + nse->sslinfo.ssl_desire = err; + } else { + /* Unexpected error */ + nse->event_done = 1; + nse->status = NSE_STATUS_ERROR; + nse->errnum = EIO; + } +#endif + } else { + err = socket_errno(); + if (errcode_is_failure(err)) { + nse->event_done = 1; + nse->status = NSE_STATUS_ERROR; + nse->errnum = err; + } + } + } + + if (res >= 0) + nse->iod->write_count += res; + } + + if (nse->event_done && nse->iod->sd != -1) { + int ev = EV_NONE; + +#if HAVE_OPENSSL + if (nse->iod->ssl != NULL) + ev |= socket_count_dec_ssl_desire(nse); + else +#endif + ev |= socket_count_write_dec(nse->iod); + update_events(nse->iod, ms, nse, EV_NONE, ev); + } +} + +void handle_timer_result(struct npool *ms, struct nevent *nse, enum nse_status status) { + /* Ooh this is a hard job :) */ + nse->event_done = 1; + nse->status = status; +} + +/* Returns -1 if an error, otherwise the number of newly written bytes */ +static int do_actual_read(struct npool *ms, struct nevent *nse) { + char buf[READ_BUFFER_SZ]; + int buflen = 0; + struct niod *iod = nse->iod; + int err = 0; + int max_chunk = NSOCK_READ_CHUNK_SIZE; + int startlen = fs_length(&nse->iobuf); + int enotsock = 0; /* Did we get ENOTSOCK once? */ + + if (nse->readinfo.read_type == NSOCK_READBYTES) + max_chunk = nse->readinfo.num; + + if (!iod->ssl) { + do { + struct sockaddr_storage peer; + socklen_t peerlen; + peerlen = sizeof(peer); + + if (enotsock) { + peer.ss_family = AF_UNSPEC; + peerlen = 0; + buflen = read(iod->sd, buf, sizeof(buf)); + } + else { + buflen = ms->engine->io_operations->iod_read(ms, iod->sd, buf, sizeof(buf), 0, (struct sockaddr *)&peer, &peerlen); + + /* Using recv() was failing, at least on UNIX, for non-network sockets + * (i.e. stdin) in this case, a read() is done - as on ENOTSOCK we may + * have a non-network socket */ + if (buflen == -1) { + if (socket_errno() == ENOTSOCK) { + enotsock = 1; + peer.ss_family = AF_UNSPEC; + peerlen = 0; + buflen = read(iod->sd, buf, sizeof(buf)); + } + } + } + if (buflen == -1) { + err = socket_errno(); + } + else { + /* Windows will ignore src_addr and addrlen arguments to recvfrom on TCP + * sockets, so peerlen is still sizeof(peer) and peer is junk. Instead, + * only set this if it's not already set. + */ + if (peerlen > 0 && iod->peerlen == 0) { + assert(peerlen <= sizeof(iod->peer)); + memcpy(&iod->peer, &peer, peerlen); + iod->peerlen = peerlen; + } + if (buflen > 0) { + if (fs_cat(&nse->iobuf, buf, buflen) == -1) { + nse->event_done = 1; + nse->status = NSE_STATUS_ERROR; + nse->errnum = ENOMEM; + return -1; + } + + /* Sometimes a service just spews and spews data. So we return after a + * somewhat large amount to avoid monopolizing resources and avoid DOS + * attacks. */ + if (fs_length(&nse->iobuf) > max_chunk) + return fs_length(&nse->iobuf) - startlen; + + /* No good reason to read again if we we were successful in the read but + * didn't fill up the buffer. Especially for UDP, where we want to + * return only one datagram at a time. The consistency of the above + * assignment of iod->peer depends on not consolidating more than one + * UDP read buffer. */ + if (buflen < sizeof(buf)) + return fs_length(&nse->iobuf) - startlen; + } + } + } while (buflen > 0 || (buflen == -1 && err == EINTR)); + + if (buflen == -1) { + if (err != EINTR && err != EAGAIN) { + nse->event_done = 1; + nse->status = NSE_STATUS_ERROR; + nse->errnum = err; + return -1; + } + } + } else { +#if HAVE_OPENSSL + /* OpenSSL read */ + while ((buflen = SSL_read(iod->ssl, buf, sizeof(buf))) > 0) { + + if (fs_cat(&nse->iobuf, buf, buflen) == -1) { + nse->event_done = 1; + nse->status = NSE_STATUS_ERROR; + nse->errnum = ENOMEM; + return -1; + } + + /* Sometimes a service just spews and spews data. So we return + * after a somewhat large amount to avoid monopolizing resources + * and avoid DOS attacks. */ + if (fs_length(&nse->iobuf) > max_chunk) + return fs_length(&nse->iobuf) - startlen; + } + + if (buflen == -1) { + err = SSL_get_error(iod->ssl, buflen); + if (err == SSL_ERROR_WANT_READ) { + int evclr; + + evclr = socket_count_dec_ssl_desire(nse); + socket_count_read_inc(iod); + update_events(iod, ms, nse, EV_READ, evclr); + nse->sslinfo.ssl_desire = err; + } else if (err == SSL_ERROR_WANT_WRITE) { + int evclr; + + evclr = socket_count_dec_ssl_desire(nse); + socket_count_write_inc(iod); + update_events(iod, ms, nse, EV_WRITE, evclr); + nse->sslinfo.ssl_desire = err; + } else { + /* Unexpected error */ + nse->event_done = 1; + nse->status = NSE_STATUS_ERROR; + nse->errnum = EIO; + nsock_log_info("SSL_read() failed for reason %s on NSI %li", + ERR_error_string(err, NULL), iod->id); + return -1; + } + } +#endif /* HAVE_OPENSSL */ + } + + if (buflen == 0) { + nse->event_done = 1; + nse->eof = 1; + if (fs_length(&nse->iobuf) > 0) { + nse->status = NSE_STATUS_SUCCESS; + return fs_length(&nse->iobuf) - startlen; + } else { + nse->status = NSE_STATUS_EOF; + return 0; + } + } + + return fs_length(&nse->iobuf) - startlen; +} + + +void handle_read_result(struct npool *ms, struct nevent *nse, enum nse_status status) { + unsigned int count; + char *str; + int rc, len; + struct niod *iod = nse->iod; + + if (status == NSE_STATUS_TIMEOUT) { + nse->event_done = 1; + if (fs_length(&nse->iobuf) > 0) + nse->status = NSE_STATUS_SUCCESS; + else + nse->status = NSE_STATUS_TIMEOUT; + } else if (status == NSE_STATUS_CANCELLED) { + nse->status = status; + nse->event_done = 1; + } else if (status == NSE_STATUS_SUCCESS) { + rc = do_actual_read(ms, nse); + /* printf("DBG: Just read %d new bytes%s.\n", rc, iod->ssl? "( SSL!)" : ""); */ + if (rc > 0) { + nse->iod->read_count += rc; + /* We decide whether we have read enough to return */ + switch (nse->readinfo.read_type) { + case NSOCK_READ: + nse->status = NSE_STATUS_SUCCESS; + nse->event_done = 1; + break; + case NSOCK_READBYTES: + if (fs_length(&nse->iobuf) >= nse->readinfo.num) { + nse->status = NSE_STATUS_SUCCESS; + nse->event_done = 1; + } + /* else we are not done */ + break; + case NSOCK_READLINES: + /* Lets count the number of lines we have ... */ + count = 0; + len = fs_length(&nse->iobuf) -1; + str = fs_str(&nse->iobuf); + for (count=0; len >= 0; len--) { + if (str[len] == '\n') { + count++; + if ((int)count >= nse->readinfo.num) + break; + } + } + if ((int) count >= nse->readinfo.num) { + nse->event_done = 1; + nse->status = NSE_STATUS_SUCCESS; + } + /* Else we are not done */ + break; + default: + fatal("Unknown operation type (%d)", (int)nse->readinfo.read_type); + } + } + } else { + fatal("Unknown status (%d)", status); + } + + /* If there are no more reads for this IOD, we are done reading on the socket + * so we can take it off the descriptor list ... */ + if (nse->event_done && iod->sd >= 0) { + int ev = EV_NONE; + +#if HAVE_OPENSSL + if (nse->iod->ssl != NULL) + ev |= socket_count_dec_ssl_desire(nse); + else +#endif + ev |= socket_count_read_dec(nse->iod); + update_events(nse->iod, ms, nse, EV_NONE, ev); + } +} + +#if HAVE_PCAP +void handle_pcap_read_result(struct npool *ms, struct nevent *nse, enum nse_status status) { + struct niod *iod = nse->iod; + mspcap *mp = (mspcap *)iod->pcap; + + switch (status) { + case NSE_STATUS_TIMEOUT: + nse->status = NSE_STATUS_TIMEOUT; + nse->event_done = 1; + break; + + case NSE_STATUS_CANCELLED: + nse->status = NSE_STATUS_CANCELLED; + nse->event_done = 1; + break; + + case NSE_STATUS_SUCCESS: + /* check if we already have something read */ + if (fs_length(&(nse->iobuf)) == 0) { + nse->status = NSE_STATUS_TIMEOUT; + nse->event_done = 0; + } else { + nse->status = NSE_STATUS_SUCCESS; /* we have full buffer */ + nse->event_done = 1; + } + break; + + default: + fatal("Unknown status (%d) for nsock event #%lu", status, nse->id); + } + + /* If there are no more read events, we are done reading on the socket so we + * can take it off the descriptor list... */ + if (nse->event_done && mp->pcap_desc >= 0) { + int ev; + + ev = socket_count_readpcap_dec(iod); + update_events(iod, ms, nse, EV_NONE, ev); + } +} + +/* Returns whether something was read */ +int pcap_read_on_nonselect(struct npool *nsp) { + gh_lnode_t *current, *next; + struct nevent *nse; + int ret = 0; + + for (current = gh_list_first_elem(&nsp->pcap_read_events); + current != NULL; + current = next) { + nse = lnode_nevent2(current); + if (do_actual_pcap_read(nse) == 1) { + /* something received */ + ret++; + break; + } + next = gh_lnode_next(current); + } + return ret; +} +#endif /* HAVE_PCAP */ + +/* Here is the all important looping function that tells the event engine to + * start up and begin processing events. It will continue until all events have + * been delivered (including new ones started from event handlers), or the + * msec_timeout is reached, or a major error has occurred. Use -1 if you don't + * want to set a maximum time for it to run. A timeout of 0 will return after 1 + * non-blocking loop. The nsock loop can be restarted again after it returns. + * For example you could do a series of 15 second runs, allowing you to do other + * stuff between them */ +enum nsock_loopstatus nsock_loop(nsock_pool nsp, int msec_timeout) { + struct npool *ms = (struct npool *)nsp; + struct timeval loop_timeout; + int msecs_left; + unsigned long loopnum = 0; + enum nsock_loopstatus quitstatus = NSOCK_LOOP_ERROR; + + gettimeofday(&nsock_tod, NULL); + + if (msec_timeout < -1) { + ms->errnum = EINVAL; + return NSOCK_LOOP_ERROR; + } + TIMEVAL_MSEC_ADD(loop_timeout, nsock_tod, msec_timeout); + msecs_left = msec_timeout; + + if (msec_timeout >= 0) + nsock_log_debug("nsock_loop() started (timeout=%dms). %d events pending", + msec_timeout, ms->events_pending); + else + nsock_log_debug("nsock_loop() started (no timeout). %d events pending", + ms->events_pending); + + while (1) { + if (ms->quit) { + /* We've been asked to quit the loop through nsock_loop_quit. */ + ms->quit = 0; + quitstatus = NSOCK_LOOP_QUIT; + break; + } + + if (ms->events_pending == 0) { + /* if no events at all are pending, then none can be created until + * we quit nsock_loop() -- so we do that now. */ + quitstatus = NSOCK_LOOP_NOEVENTS; + break; + } + + if (msec_timeout >= 0) { + msecs_left = MAX(0, TIMEVAL_MSEC_SUBTRACT(loop_timeout, nsock_tod)); + if (msecs_left == 0 && loopnum > 0) { + quitstatus = NSOCK_LOOP_TIMEOUT; + break; + } + } + + if (nsock_engine_loop(ms, msecs_left) == -1) { + quitstatus = NSOCK_LOOP_ERROR; + break; + } + + gettimeofday(&nsock_tod, NULL); /* we do this at end because there is one + * at beginning of function */ + loopnum++; + } + + return quitstatus; +} + +void process_event(struct npool *nsp, gh_list_t *evlist, struct nevent *nse, int ev) { + int match_r = ev & EV_READ; + int match_w = ev & EV_WRITE; + int match_x = ev & EV_EXCEPT; +#if HAVE_OPENSSL + int desire_r = 0, desire_w = 0; +#endif + + nsock_log_debug_all("Processing event %lu (timeout in %ldms, done=%d)", + nse->id, + (long)TIMEVAL_MSEC_SUBTRACT(nse->timeout, nsock_tod), + nse->event_done); + + if (!nse->event_done) { + switch (nse->type) { + case NSE_TYPE_CONNECT: + case NSE_TYPE_CONNECT_SSL: + if (ev != EV_NONE) + handle_connect_result(nsp, nse, NSE_STATUS_SUCCESS); + if (event_timedout(nse)) + handle_connect_result(nsp, nse, NSE_STATUS_TIMEOUT); + break; + + case NSE_TYPE_READ: +#if HAVE_OPENSSL + desire_r = nse->sslinfo.ssl_desire == SSL_ERROR_WANT_READ; + desire_w = nse->sslinfo.ssl_desire == SSL_ERROR_WANT_WRITE; + if (nse->iod->ssl && ((desire_r && match_r) || (desire_w && match_w))) + handle_read_result(nsp, nse, NSE_STATUS_SUCCESS); + else +#endif + if ((!nse->iod->ssl && match_r) || match_x) + handle_read_result(nsp, nse, NSE_STATUS_SUCCESS); + + if (event_timedout(nse)) + handle_read_result(nsp, nse, NSE_STATUS_TIMEOUT); + + break; + + case NSE_TYPE_WRITE: +#if HAVE_OPENSSL + desire_r = nse->sslinfo.ssl_desire == SSL_ERROR_WANT_READ; + desire_w = nse->sslinfo.ssl_desire == SSL_ERROR_WANT_WRITE; + if (nse->iod->ssl && ((desire_r && match_r) || (desire_w && match_w))) + handle_write_result(nsp, nse, NSE_STATUS_SUCCESS); + else +#endif + if ((!nse->iod->ssl && match_w) || match_x) + handle_write_result(nsp, nse, NSE_STATUS_SUCCESS); + + if (event_timedout(nse)) + handle_write_result(nsp, nse, NSE_STATUS_TIMEOUT); + break; + + case NSE_TYPE_TIMER: + if (event_timedout(nse)) + handle_timer_result(nsp, nse, NSE_STATUS_SUCCESS); + break; + +#if HAVE_PCAP + case NSE_TYPE_PCAP_READ:{ + nsock_log_debug_all("PCAP iterating %lu", nse->id); + + if (ev & EV_READ) { + /* buffer empty? check it! */ + if (fs_length(&(nse->iobuf)) == 0) + do_actual_pcap_read(nse); + } + + /* if already received something */ + if (fs_length(&(nse->iobuf)) > 0) + handle_pcap_read_result(nsp, nse, NSE_STATUS_SUCCESS); + + if (event_timedout(nse)) + handle_pcap_read_result(nsp, nse, NSE_STATUS_TIMEOUT); + + #if PCAP_BSD_SELECT_HACK + /* If event occurred, and we're in BSD_HACK mode, then this event was added + * to two queues. read_event and pcap_read_event + * Of course we should destroy it only once. + * I assume we're now in read_event, so just unlink this event from + * pcap_read_event */ + if (((mspcap *)nse->iod->pcap)->pcap_desc >= 0 + && nse->event_done + && evlist == &nsp->read_events) { + /* event is done, list is read_events and we're in BSD_HACK mode. + * So unlink event from pcap_read_events */ + update_first_events(nse); + gh_list_remove(&nsp->pcap_read_events, &nse->nodeq_pcap); + + nsock_log_debug_all("PCAP NSE #%lu: Removing event from PCAP_READ_EVENTS", + nse->id); + } + if (((mspcap *)nse->iod->pcap)->pcap_desc >= 0 + && nse->event_done + && evlist == &nsp->pcap_read_events) { + update_first_events(nse); + gh_list_remove(&nsp->read_events, &nse->nodeq_io); + nsock_log_debug_all("PCAP NSE #%lu: Removing event from READ_EVENTS", + nse->id); + } + #endif + break; + } +#endif + default: + fatal("Event has unknown type (%d)", nse->type); + } + } + + if (nse->event_done) { + /* Security sanity check: don't return a functional SSL iod without + * setting an SSL data structure. */ + if (nse->type == NSE_TYPE_CONNECT_SSL && nse->status == NSE_STATUS_SUCCESS) + assert(nse->iod->ssl != NULL); + + nsock_log_debug_all("NSE #%lu: Sending event", nse->id); + + /* WooHoo! The event is ready to be sent */ + event_dispatch_and_delete(nsp, nse, 1); + } +} + +void process_iod_events(struct npool *nsp, struct niod *nsi, int ev) { + int i = 0; + /* store addresses of the pointers to the first elements of each kind instead + * of storing the values, as a connect can add a read for instance */ + gh_lnode_t **start_elems[] = { + &nsi->first_connect, + &nsi->first_read, + &nsi->first_write, +#if HAVE_PCAP + &nsi->first_pcap_read, +#endif + NULL + }; + gh_list_t *evlists[] = { + &nsp->connect_events, + &nsp->read_events, + &nsp->write_events, +#if HAVE_PCAP + &nsp->pcap_read_events, +#endif + NULL + }; + + assert(nsp == nsi->nsp); + nsock_log_debug_all("Processing events on IOD %lu (ev=%d)", nsi->id, ev); + + /* We keep the events separate because we want to handle them in the + * order: connect => read => write => timer for several reasons: + * + * 1) Makes sure we have gone through all the net i/o events before + * a timer expires (would be a shame to timeout after the data was + * available but before we delivered the events + * + * 2) The connect() results often lead to a read or write that can be + * processed in the same cycle. In the same way, read() often + * leads to write(). + */ + for (i = 0; evlists[i] != NULL; i++) { + gh_lnode_t *current, *next, *last; + + /* for each list, get the last event and don't look past it as an event + * could add another event in the same list and so on... */ + last = gh_list_last_elem(evlists[i]); + + for (current = *start_elems[i]; + current != NULL && gh_lnode_prev(current) != last; + current = next) { + struct nevent *nse; + +#if HAVE_PCAP + if (evlists[i] == &nsi->nsp->pcap_read_events) + nse = lnode_nevent2(current); + else +#endif + nse = lnode_nevent(current); + + /* events are grouped by IOD. Break if we're done with the events for the + * current IOD */ + if (nse->iod != nsi) + break; + + process_event(nsp, evlists[i], nse, ev); + next = gh_lnode_next(current); + + if (nse->event_done) { + /* event is done, remove it from the event list and update IOD pointers + * to the first events of each kind */ + update_first_events(nse); + gh_list_remove(evlists[i], current); + gh_list_append(&nsp->free_events, &nse->nodeq_io); + + if (nse->timeout.tv_sec) + gh_heap_remove(&nsp->expirables, &nse->expire); + } + } + } +} + +static int nevent_unref(struct npool *nsp, struct nevent *nse) { + switch (nse->type) { + case NSE_TYPE_CONNECT: + case NSE_TYPE_CONNECT_SSL: + gh_list_remove(&nsp->connect_events, &nse->nodeq_io); + break; + + case NSE_TYPE_READ: + gh_list_remove(&nsp->read_events, &nse->nodeq_io); + break; + + case NSE_TYPE_WRITE: + gh_list_remove(&nsp->write_events, &nse->nodeq_io); + break; + +#if HAVE_PCAP + case NSE_TYPE_PCAP_READ: { + char read = 0; + char pcap = 0; + +#if PCAP_BSD_SELECT_HACK + read = pcap = 1; +#else + if (((mspcap *)nse->iod->pcap)->pcap_desc >= 0) + read = 1; + else + pcap = 1; +#endif /* PCAP_BSD_SELECT_HACK */ + + if (read) + gh_list_remove(&nsp->read_events, &nse->nodeq_io); + if (pcap) + gh_list_remove(&nsp->pcap_read_events, &nse->nodeq_pcap); + + break; + } +#endif /* HAVE_PCAP */ + + case NSE_TYPE_TIMER: + /* Nothing to do */ + break; + + default: + fatal("Unknown event type %d", nse->type); + } + gh_list_append(&nsp->free_events, &nse->nodeq_io); + return 0; +} + +void process_expired_events(struct npool *nsp) { + for (;;) { + gh_hnode_t *hnode; + struct nevent *nse; + + hnode = gh_heap_min(&nsp->expirables); + if (!hnode) + break; + + nse = container_of(hnode, struct nevent, expire); + if (!event_timedout(nse)) + break; + + gh_heap_remove(&nsp->expirables, hnode); + process_event(nsp, NULL, nse, EV_NONE); + assert(nse->event_done); + update_first_events(nse); + nevent_unref(nsp, nse); + } +} + +/* Calling this function will cause nsock_loop to quit on its next iteration + * with a return value of NSOCK_LOOP_QUIT. */ +void nsock_loop_quit(nsock_pool nsp) { + struct npool *ms = (struct npool *)nsp; + ms->quit = 1; +} + +/* Grab the latest time as recorded by the nsock library, which does so at least + * once per event loop (in main_loop). Not only does this function (generally) + * avoid a system call, but in many circumstances it is better to use nsock's + * time rather than the system time. If nsock has never obtained the time when + * you call it, it will do so before returning */ +const struct timeval *nsock_gettimeofday() { + if (nsock_tod.tv_sec == 0) + gettimeofday(&nsock_tod, NULL); + return &nsock_tod; +} + +/* Adds an event to the appropriate nsp event list, handles housekeeping such as + * adjusting the descriptor select/poll lists, registering the timeout value, + * etc. */ +void nsock_pool_add_event(struct npool *nsp, struct nevent *nse) { + nsock_log_debug("NSE #%lu: Adding event (timeout in %ldms)", + nse->id, + (long)TIMEVAL_MSEC_SUBTRACT(nse->timeout, nsock_tod)); + + nsp->events_pending++; + + if (!nse->event_done && nse->timeout.tv_sec) { + /* This event is expirable, add it to the queue */ + gh_heap_push(&nsp->expirables, &nse->expire); + } + + /* Now we do the event type specific actions */ + switch (nse->type) { + case NSE_TYPE_CONNECT: + case NSE_TYPE_CONNECT_SSL: + if (!nse->event_done) { + assert(nse->iod->sd >= 0); + socket_count_read_inc(nse->iod); + socket_count_write_inc(nse->iod); + update_events(nse->iod, nsp, nse, EV_READ|EV_WRITE, EV_NONE); + } + iod_add_event(nse->iod, nse); + break; + + case NSE_TYPE_READ: + if (!nse->event_done) { + assert(nse->iod->sd >= 0); + socket_count_read_inc(nse->iod); + update_events(nse->iod, nsp, nse, EV_READ, EV_NONE); +#if HAVE_OPENSSL + if (nse->iod->ssl) + nse->sslinfo.ssl_desire = SSL_ERROR_WANT_READ; +#endif + } + iod_add_event(nse->iod, nse); + break; + + case NSE_TYPE_WRITE: + if (!nse->event_done) { + assert(nse->iod->sd >= 0); + socket_count_write_inc(nse->iod); + update_events(nse->iod, nsp, nse, EV_WRITE, EV_NONE); +#if HAVE_OPENSSL + if (nse->iod->ssl) + nse->sslinfo.ssl_desire = SSL_ERROR_WANT_WRITE; +#endif + } + iod_add_event(nse->iod, nse); + break; + + case NSE_TYPE_TIMER: + /* nothing to do */ + break; + +#if HAVE_PCAP + case NSE_TYPE_PCAP_READ: { + mspcap *mp = (mspcap *)nse->iod->pcap; + + assert(mp); + if (mp->pcap_desc >= 0) { /* pcap descriptor present */ + if (!nse->event_done) { + socket_count_readpcap_inc(nse->iod); + update_events(nse->iod, nsp, nse, EV_READ, EV_NONE); + } + nsock_log_debug_all("PCAP NSE #%lu: Adding event to READ_EVENTS", nse->id); + + #if PCAP_BSD_SELECT_HACK + /* when using BSD hack we must do pcap_next() after select(). + * Let's insert this pcap to bot queues, to selectable and nonselectable. + * This will result in doing pcap_next_ex() just before select() */ + nsock_log_debug_all("PCAP NSE #%lu: Adding event to PCAP_READ_EVENTS", nse->id); + #endif + } else { + /* pcap isn't selectable. Add it to pcap-specific queue. */ + nsock_log_debug_all("PCAP NSE #%lu: Adding event to PCAP_READ_EVENTS", nse->id); + } + iod_add_event(nse->iod, nse); + break; + } +#endif + + default: + fatal("Unknown nsock event type (%d)", nse->type); + } + + /* It can happen that the event already completed. In which case we can + * already deliver it, even though we're probably not inside nsock_loop(). */ + if (nse->event_done) { + event_dispatch_and_delete(nsp, nse, 1); + update_first_events(nse); + nevent_unref(nsp, nse); + } +} + +/* An event has been completed and the handler is about to be called. This + * function writes out tracing data about the event if necessary */ +void nsock_trace_handler_callback(struct npool *ms, struct nevent *nse) { + struct niod *nsi; + char *str; + int strlength = 0; + char displaystr[256]; + char errstr[256]; + + if (NsockLogLevel > NSOCK_LOG_INFO) + return; + + nsi = nse->iod; + + if (nse->status == NSE_STATUS_ERROR) + Snprintf(errstr, sizeof(errstr), "[%s (%d)] ", socket_strerror(nse->errnum), + nse->errnum); + else + errstr[0] = '\0'; + + /* Some types have special tracing treatment */ + switch (nse->type) { + case NSE_TYPE_CONNECT: + case NSE_TYPE_CONNECT_SSL: + nsock_log_info("Callback: %s %s %sfor EID %li [%s]", + nse_type2str(nse->type), nse_status2str(nse->status), + errstr, nse->id, get_peeraddr_string(nsi)); + break; + + case NSE_TYPE_READ: + if (nse->status != NSE_STATUS_SUCCESS) { + nsock_log_info("Callback: %s %s %sfor EID %li [%s]", + nse_type2str(nse->type), nse_status2str(nse->status), + errstr, nse->id, get_peeraddr_string(nsi)); + } else { + str = nse_readbuf(nse, &strlength); + if (strlength < 80) { + memcpy(displaystr, ": ", 2); + memcpy(displaystr + 2, str, strlength); + displaystr[2 + strlength] = '\0'; + replacenonprintable(displaystr + 2, strlength, '.'); + } else { + displaystr[0] = '\0'; + } + nsock_log_info("Callback: %s %s for EID %li [%s] %s(%d bytes)%s", + nse_type2str(nse->type), nse_status2str(nse->status), + nse->id, + get_peeraddr_string(nsi), + nse_eof(nse) ? "[EOF]" : "", strlength, displaystr); + } + break; + + case NSE_TYPE_WRITE: + nsock_log_info("Callback: %s %s %sfor EID %li [%s]", + nse_type2str(nse->type), nse_status2str(nse->status), + errstr, nse->id, get_peeraddr_string(nsi)); + break; + + case NSE_TYPE_TIMER: + nsock_log_info("Callback: %s %s %sfor EID %li", + nse_type2str(nse->type), nse_status2str(nse->status), + errstr, nse->id); + break; + +#if HAVE_PCAP + case NSE_TYPE_PCAP_READ: + nsock_log_info("Callback: %s %s %sfor EID %li ", + nse_type2str(nse->type), nse_status2str(nse->status), + errstr, nse->id); + break; +#endif + + default: + fatal("Invalid nsock event type (%d)", nse->type); + } +} + diff --git a/nsock/src/nsock_engines.c b/nsock/src/nsock_engines.c new file mode 100644 index 0000000..de9d44e --- /dev/null +++ b/nsock/src/nsock_engines.c @@ -0,0 +1,187 @@ +/*************************************************************************** + * nsock_engines.c -- This contains the functions and definitions to * + * manage the list of available IO engines. Each IO engine leverages a * + * specific IO notification function to wait for events. Nsock will try * + * to use the most efficient engine for your system. * + * * + ***********************IMPORTANT NSOCK LICENSE TERMS*********************** + * + * The nsock parallel socket event library is (C) 1999-2023 Nmap Software LLC + * This library is free software; you may redistribute and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation; Version 2. This guarantees your right to use, modify, and + * redistribute this software under certain conditions. If this license is + * unacceptable to you, Nmap Software LLC may be willing to sell alternative + * licenses (contact sales@nmap.com ). + * + * As a special exception to the GPL terms, Nmap Software LLC grants permission + * to link the code of this program with any version of the OpenSSL library + * which is distributed under a license identical to that listed in the included + * docs/licenses/OpenSSL.txt file, and distribute linked combinations including + * the two. You must obey the GNU GPL in all respects for all of the code used + * other than OpenSSL. If you modify this file, you may extend this exception to + * your version of the file, but you are not obligated to do so. + * + * If you received these files with a written license agreement stating terms + * other than the (GPL) terms above, then that alternative license agreement + * takes precedence over this comment. + * + * Source is provided to this software because we believe users have a right to + * know exactly what a program is going to do before they run it. This also + * allows you to audit the software for security holes. + * + * Source code also allows you to port Nmap to new platforms, fix bugs, and add + * new features. You are highly encouraged to send your changes to the + * dev@nmap.org mailing list for possible incorporation into the main + * distribution. By sending these changes to Fyodor or one of the Insecure.Org + * development mailing lists, or checking them into the Nmap source code + * repository, it is understood (unless you specify otherwise) that you are + * offering the Nmap Project (Nmap Software LLC) the unlimited, non-exclusive + * right to reuse, modify, and relicense the code. Nmap will always be available + * Open Source, but this is important because the inability to relicense code + * has caused devastating problems for other Free Software projects (such as KDE + * and NASM). We also occasionally relicense the code to third parties as + * discussed above. If you wish to specify special license conditions of your + * contributions, just say so when you send them. + * + * 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 v2.0 for more + * details (http://www.gnu.org/licenses/gpl-2.0.html). + * + ***************************************************************************/ + +/* $Id$ */ + +#ifdef HAVE_CONFIG_H +#include "nsock_config.h" +#endif + +#include "nsock_internal.h" + +#if HAVE_IOCP + extern struct io_engine engine_iocp; + #define ENGINE_IOCP &engine_iocp, +#else + #define ENGINE_IOCP +#endif /* HAVE_IOCP */ + +#if HAVE_EPOLL + extern struct io_engine engine_epoll; + #define ENGINE_EPOLL &engine_epoll, +#else + #define ENGINE_EPOLL +#endif /* HAVE_EPOLL */ + +#if HAVE_KQUEUE + extern struct io_engine engine_kqueue; + #define ENGINE_KQUEUE &engine_kqueue, +#else + #define ENGINE_KQUEUE +#endif /* HAVE_KQUEUE */ + +#if HAVE_POLL + extern struct io_engine engine_poll; + #define ENGINE_POLL &engine_poll, +#else + #define ENGINE_POLL +#endif /* HAVE_POLL */ + +/* select() based engine is the fallback engine, we assume it's always available */ +extern struct io_engine engine_select; +#define ENGINE_SELECT &engine_select, + +/* Available IO engines. This depends on which IO management interfaces are + * available on your system. Engines must be sorted by order of preference */ +static struct io_engine *available_engines[] = { + ENGINE_EPOLL + ENGINE_KQUEUE + ENGINE_POLL + ENGINE_IOCP + ENGINE_SELECT + NULL +}; + +static char *engine_hint; + +int posix_iod_connect(struct npool *nsp, int sockfd, const struct sockaddr *addr, socklen_t addrlen) { + return connect(sockfd, addr, addrlen); +} + +int posix_iod_read(struct npool *nsp, int sockfd, void *buf, size_t len, int flags, struct sockaddr *src_addr, socklen_t *addrlen) { + return recvfrom(sockfd, (char *)buf, len, flags, src_addr, addrlen); +} + +int posix_iod_write(struct npool *nsp, int sockfd, const void *buf, size_t len, int flags, const struct sockaddr *dest_addr, socklen_t addrlen) { + struct sockaddr_storage *dest = (struct sockaddr_storage *)dest_addr; + if (dest->ss_family == AF_UNSPEC) + return send(sockfd, (char *)buf, len, flags); + else + return sendto(sockfd, (char *)buf, len, flags, dest_addr, addrlen); +} + +struct io_operations posix_io_operations = { + posix_iod_connect, + posix_iod_read, + posix_iod_write +}; + +struct io_engine *get_io_engine(void) { + struct io_engine *engine = NULL; + int i; + + if (!engine_hint) { + engine = available_engines[0]; + } else { + for (i = 0; available_engines[i] != NULL; i++) + if (strcmp(engine_hint, available_engines[i]->name) == 0) { + engine = available_engines[i]; + break; + } + } + + if (!engine) + fatal("No suitable IO engine found! (%s)\n", + engine_hint ? engine_hint : "no hint"); + + return engine; +} + +int nsock_set_default_engine(char *engine) { + if (engine_hint) + free(engine_hint); + + if (engine) { + int i; + + for (i = 0; available_engines[i] != NULL; i++) { + if (strcmp(engine, available_engines[i]->name) == 0) { + engine_hint = strdup(engine); + return 0; + } + } + return -1; + } + /* having engine = NULL is fine. This is actually the + * way to tell nsock to use the default engine again. */ + engine_hint = NULL; + return 0; +} + +const char *nsock_list_engines(void) { + return +#if HAVE_IOCP + "iocp " +#endif +#if HAVE_EPOLL + "epoll " +#endif +#if HAVE_KQUEUE + "kqueue " +#endif +#if HAVE_POLL + "poll " +#endif + "select"; +} + diff --git a/nsock/src/nsock_event.c b/nsock/src/nsock_event.c new file mode 100644 index 0000000..bfc489b --- /dev/null +++ b/nsock/src/nsock_event.c @@ -0,0 +1,538 @@ +/*************************************************************************** + * nsock_event.c -- Functions dealing with nsock_events (and their * + * struct nevent internal representation. An event is created when you do * + * various calls (for reading, writing, connecting, timers, etc) and is * + * provided back to you in the callback when the call completes or * + * fails. It is automatically destroyed after the callback returns * + * * + ***********************IMPORTANT NSOCK LICENSE TERMS*********************** + * + * The nsock parallel socket event library is (C) 1999-2023 Nmap Software LLC + * This library is free software; you may redistribute and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation; Version 2. This guarantees your right to use, modify, and + * redistribute this software under certain conditions. If this license is + * unacceptable to you, Nmap Software LLC may be willing to sell alternative + * licenses (contact sales@nmap.com ). + * + * As a special exception to the GPL terms, Nmap Software LLC grants permission + * to link the code of this program with any version of the OpenSSL library + * which is distributed under a license identical to that listed in the included + * docs/licenses/OpenSSL.txt file, and distribute linked combinations including + * the two. You must obey the GNU GPL in all respects for all of the code used + * other than OpenSSL. If you modify this file, you may extend this exception to + * your version of the file, but you are not obligated to do so. + * + * If you received these files with a written license agreement stating terms + * other than the (GPL) terms above, then that alternative license agreement + * takes precedence over this comment. + * + * Source is provided to this software because we believe users have a right to + * know exactly what a program is going to do before they run it. This also + * allows you to audit the software for security holes. + * + * Source code also allows you to port Nmap to new platforms, fix bugs, and add + * new features. You are highly encouraged to send your changes to the + * dev@nmap.org mailing list for possible incorporation into the main + * distribution. By sending these changes to Fyodor or one of the Insecure.Org + * development mailing lists, or checking them into the Nmap source code + * repository, it is understood (unless you specify otherwise) that you are + * offering the Nmap Project (Nmap Software LLC) the unlimited, non-exclusive + * right to reuse, modify, and relicense the code. Nmap will always be available + * Open Source, but this is important because the inability to relicense code + * has caused devastating problems for other Free Software projects (such as KDE + * and NASM). We also occasionally relicense the code to third parties as + * discussed above. If you wish to specify special license conditions of your + * contributions, just say so when you send them. + * + * 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 v2.0 for more + * details (http://www.gnu.org/licenses/gpl-2.0.html). + * + ***************************************************************************/ + +/* $Id$ */ + +#include "nsock_internal.h" +#include "nsock_log.h" +#include "gh_list.h" + +#if HAVE_PCAP +#include "nsock_pcap.h" +#endif + +#include <string.h> + +extern struct timeval nsock_tod; + +/* Find the type of an event that spawned a callback */ +enum nse_type nse_type(nsock_event nse) { + struct nevent *me = (struct nevent *)nse; + return me->type; +} + +enum nse_status nse_status(nsock_event nse) { + struct nevent *me = (struct nevent *)nse; + return me->status; +} + +int nse_eof(nsock_event nse) { + struct nevent *me = (struct nevent *)nse; + return me->eof; +} + +/* Obtains the nsock_iod (see below) associated with the event. Note that + * some events (such as timers) don't have an nsock_iod associated with them */ +nsock_iod nse_iod(nsock_event ms_event) { + struct nevent *nse = (struct nevent *)ms_event; + return (nsock_iod) nse->iod; +} + +/* This next function returns the errno style error code -- which is only valid + * if the status is NSE_STATUS_ERROR */ +int nse_errorcode(nsock_event nse) { + struct nevent *me = (struct nevent *)nse; + return me->errnum; +} + +/* Every event has an ID which will be unique throughout the program's execution + * unless you use (literally) billions of them */ +nsock_event_id nse_id(nsock_event nse) { + struct nevent *me = (struct nevent *)nse; + return me->id; +} + +/* If you did a read request, and the result was STATUS_SUCCESS, this function + * provides the buffer that was read in as well as the number of chars read. + * The buffer should not be modified or free'd */ +char *nse_readbuf(nsock_event nse, int *nbytes) { + struct nevent *me = (struct nevent *)nse; + + if (nbytes) + *nbytes = fs_length(&(me->iobuf)); + return fs_str(&(me->iobuf)); +} + +static void first_ev_next(struct nevent *nse, gh_lnode_t **first, int nodeq2) { + if (!first || !*first) + return; + + if (&nse->nodeq_io == *first || &nse->nodeq_pcap == *first) { + gh_lnode_t *next; + + next = gh_lnode_next(*first); + if (next) { + struct nevent *newevent; + + if (nodeq2) + newevent = lnode_nevent2(next); + else + newevent = lnode_nevent(next); + + if (newevent->iod == nse->iod) + *first = next; + else + *first = NULL; + } else { + *first = NULL; + } + } +} + +void update_first_events(struct nevent *nse) { + switch (get_event_id_type(nse->id)) { + case NSE_TYPE_CONNECT: + case NSE_TYPE_CONNECT_SSL: + first_ev_next(nse, &nse->iod->first_connect, 0); + break; + + case NSE_TYPE_READ: + first_ev_next(nse, &nse->iod->first_read, 0); + break; + + case NSE_TYPE_WRITE: + first_ev_next(nse, &nse->iod->first_write, 0); + break; + +#if HAVE_PCAP + case NSE_TYPE_PCAP_READ: + first_ev_next(nse, &nse->iod->first_read, 0); + first_ev_next(nse, &nse->iod->first_pcap_read, 1); + break; +#endif + + case NSE_TYPE_TIMER: + /* nothing to do */ + break; + + default: + fatal("Bogus event type in update_first_events"); + break; + } +} + +/* Cancel an event (such as a timer or read request). If notify is nonzero, the + * requester will be sent an event CANCELLED status back to the given handler. + * But in some cases there is no need to do this (like if the function deleting + * it is the one which created it), in which case 0 can be passed to skip the + * step. This function returns zero if the event is not found, nonzero + * otherwise. */ +int nsock_event_cancel(nsock_pool ms_pool, nsock_event_id id, int notify) { + struct npool *nsp = (struct npool *)ms_pool; + enum nse_type type; + unsigned int i; + gh_list_t *event_list = NULL, *event_list2 = NULL; + gh_lnode_t *current, *next; + struct nevent *nse = NULL; + + assert(nsp); + + type = get_event_id_type(id); + nsock_log_info("Event #%li (type %s) cancelled", id, nse_type2str(type)); + + /* First we figure out what list it is in */ + switch (type) { + case NSE_TYPE_CONNECT: + case NSE_TYPE_CONNECT_SSL: + event_list = &nsp->connect_events; + break; + + case NSE_TYPE_READ: + event_list = &nsp->read_events; + break; + + case NSE_TYPE_WRITE: + event_list = &nsp->write_events; + break; + + case NSE_TYPE_TIMER: + for (i = 0; i < gh_heap_count(&nsp->expirables); i++) { + gh_hnode_t *hnode; + + hnode = gh_heap_find(&nsp->expirables, i); + nse = container_of(hnode, struct nevent, expire); + if (nse->id == id) + return nevent_delete(nsp, nse, NULL, NULL, notify); + } + return 0; + +#if HAVE_PCAP + case NSE_TYPE_PCAP_READ: + event_list = &nsp->read_events; + event_list2 = &nsp->pcap_read_events; + break; +#endif + + default: + fatal("Bogus event type in nsock_event_cancel"); break; + } + + /* Now we try to find the event in the list */ + for (current = gh_list_first_elem(event_list); current != NULL; current = next) { + next = gh_lnode_next(current); + nse = lnode_nevent(current); + if (nse->id == id) + break; + } + + if (current == NULL && event_list2) { + event_list = event_list2; + for (current = gh_list_first_elem(event_list); current != NULL; current = next) { + next = gh_lnode_next(current); + nse = lnode_nevent2(current); + if (nse->id == id) + break; + } + } + if (current == NULL) + return 0; + + return nevent_delete(nsp, nse, event_list, current, notify); +} + +/* An internal function for cancelling an event when you already have a pointer + * to the struct nevent (use nsock_event_cancel if you just have an ID). The + * event_list passed in should correspond to the type of the event. For example, + * with NSE_TYPE_READ, you would pass in &nsp->read_events;. elem is the list + * element in event_list which holds the event. Pass a nonzero for notify if + * you want the program owning the event to be notified that it has been + * cancelled */ +int nevent_delete(struct npool *nsp, struct nevent *nse, gh_list_t *event_list, + gh_lnode_t *elem, int notify) { + if (nse->event_done) { + /* This event has already been marked for death somewhere else -- it will be + * gone soon (and if we try to kill it now all hell will break loose due to + * reentrancy. */ + return 0; + } + + nsock_log_info("%s on event #%li (type %s)", __func__, nse->id, + nse_type2str(nse->type)); + + /* Now that we found the event... we go through the motions of cleanly + * cancelling it */ + switch (nse->type) { + case NSE_TYPE_CONNECT: + case NSE_TYPE_CONNECT_SSL: + handle_connect_result(nsp, nse, NSE_STATUS_CANCELLED); + break; + + case NSE_TYPE_READ: + handle_read_result(nsp, nse, NSE_STATUS_CANCELLED); + break; + + case NSE_TYPE_WRITE: + handle_write_result(nsp, nse, NSE_STATUS_CANCELLED); + break; + + case NSE_TYPE_TIMER: + handle_timer_result(nsp, nse, NSE_STATUS_CANCELLED); + break; + +#if HAVE_PCAP + case NSE_TYPE_PCAP_READ: + handle_pcap_read_result(nsp, nse, NSE_STATUS_CANCELLED); + break; +#endif + + default: + fatal("Invalid nsock event type (%d)", nse->type); + } + + assert(nse->event_done); + + if (nse->timeout.tv_sec) + gh_heap_remove(&nsp->expirables, &nse->expire); + + if (event_list) { + update_first_events(nse); + gh_list_remove(event_list, elem); + } + + gh_list_append(&nsp->free_events, &nse->nodeq_io); + + nsock_log_debug_all("NSE #%lu: Removing event from list", nse->id); + +#if HAVE_PCAP +#if PCAP_BSD_SELECT_HACK + if (nse->type == NSE_TYPE_PCAP_READ) { + nsock_log_debug_all("PCAP NSE #%lu: CANCEL TEST pcap=%p read=%p curr=%p sd=%i", + nse->id, &nsp->pcap_read_events, &nsp->read_events, + event_list,((mspcap *)nse->iod->pcap)->pcap_desc); + + /* If event occurred, and we're in BSD_HACK mode, then this event was added to + * two queues. read_event and pcap_read_event Of course we should + * destroy it only once. I assume we're now in read_event, so just unlink + * this event from pcap_read_event */ + if (((mspcap *)nse->iod->pcap)->pcap_desc >= 0 && event_list == &nsp->read_events) { + /* event is done, list is read_events and we're in BSD_HACK mode. So unlink + * event from pcap_read_events */ + gh_list_remove(&nsp->pcap_read_events, &nse->nodeq_pcap); + nsock_log_debug_all("PCAP NSE #%lu: Removing event from PCAP_READ_EVENTS", nse->id); + } + + if (((mspcap *)nse->iod->pcap)->pcap_desc >= 0 && event_list == &nsp->pcap_read_events) { + /* event is done, list is read_events and we're in BSD_HACK mode. + * So unlink event from read_events */ + gh_list_remove(&nsp->read_events, &nse->nodeq_io); + + nsock_log_debug_all("PCAP NSE #%lu: Removing event from READ_EVENTS", nse->id); + } + } +#endif +#endif + event_dispatch_and_delete(nsp, nse, notify); + return 1; +} + +/* Adjust various statistics, dispatches the event handler (if notify is + * nonzero) and then deletes the event. This function does NOT delete the event + * from any lists it might be on (eg nsp->read_list etc.) nse->event_done + * MUST be true when you call this */ +void event_dispatch_and_delete(struct npool *nsp, struct nevent *nse, int notify) { + assert(nsp); + assert(nse); + + assert(nse->event_done); + + nsp->events_pending--; + assert(nsp->events_pending >= 0); + + if (nse->iod) { + nse->iod->events_pending--; + assert(nse->iod->events_pending >= 0); + } + + if (notify) { + nsock_trace_handler_callback(nsp, nse); + nse->handler(nsp, nse, nse->userdata); + } + + /* FIXME: We should be updating stats here ... */ + + /* Now we clobber the event ... */ + event_delete(nsp, nse); +} + +/* OK -- the idea is that we want the type included in the rightmost two bits + * and the serial number in the leftmost 30 or 62. But we also want to insure a + * correct wrap-around in the case of an obscene number of event. One + * definition of a "correct" wraparound is that it goes from the highest number + * back to one (not zero) because we don't want event numbers to ever be zero. + * */ +nsock_event_id get_new_event_id(struct npool *ms, enum nse_type type) { + int type_code = (int)type; + unsigned long serial = ms->next_event_serial++; + unsigned long max_serial_allowed; + int shiftbits; + + assert(type < NSE_TYPE_MAX); + + shiftbits = sizeof(nsock_event_id) * 8 - TYPE_CODE_NUM_BITS; + max_serial_allowed = ((unsigned long)1 << shiftbits) - 1; + if (serial == max_serial_allowed) { + /* then the next serial will be one because 0 is forbidden */ + ms->next_event_serial = 1; + } + + return (serial << TYPE_CODE_NUM_BITS) | type_code; +} + +/* Take an event ID and return the type (NSE_TYPE_CONNECT, etc */ +enum nse_type get_event_id_type(nsock_event_id event_id) { + return (enum nse_type)((event_id & ((1 << TYPE_CODE_NUM_BITS) - 1))); +} + +/* Create a new event structure -- must be deleted later with event_delete, + * unless it returns NULL (failure). NULL can be passed in for the struct niod + * and the userdata if not available */ +struct nevent *event_new(struct npool *nsp, enum nse_type type, + struct niod *iod, int timeout_msecs, + nsock_ev_handler handler, void *userdata) { + struct nevent *nse; + gh_lnode_t *lnode; + + /* Bring us up to date for the timeout calculation. */ + gettimeofday(&nsock_tod, NULL); + + if (iod) { + iod->events_pending++; + assert(iod->state != NSIOD_STATE_DELETED); + } + + /* First we check if one is available from the free list ... */ + lnode = gh_list_pop(&nsp->free_events); + if (!lnode) + nse = (struct nevent *)safe_malloc(sizeof(*nse)); + else + nse = lnode_nevent(lnode); + + memset(nse, 0, sizeof(*nse)); + + nse->id = get_new_event_id(nsp, type); + nse->type = type; + nse->status = NSE_STATUS_NONE; + gh_hnode_invalidate(&nse->expire); +#if HAVE_OPENSSL + nse->sslinfo.ssl_desire = SSL_ERROR_NONE; +#endif + + if (type == NSE_TYPE_READ || type == NSE_TYPE_WRITE) + filespace_init(&(nse->iobuf), 1024); + +#if HAVE_PCAP + if (type == NSE_TYPE_PCAP_READ) { + mspcap *mp; + int sz; + + assert(iod != NULL); + mp = (mspcap *)iod->pcap; + assert(mp); + + sz = mp->snaplen+1 + sizeof(nsock_pcap); + filespace_init(&(nse->iobuf), sz); + } +#endif + + if (timeout_msecs != -1) { + assert(timeout_msecs >= 0); + TIMEVAL_MSEC_ADD(nse->timeout, nsock_tod, timeout_msecs); + } + + nse->iod = iod; + nse->handler = handler; + nse->userdata = userdata; + + if (nse->iod == NULL) + nsock_log_debug("%s (IOD #NULL) (EID #%li)", __func__, nse->id); + else + nsock_log_debug("%s (IOD #%li) (EID #%li)", __func__, nse->iod->id, + nse->id); + return nse; +} + +/* Free an struct nevent which was allocated with event_new, including all internal + * resources. Note -- we assume that nse->iod->events_pending (if it exists) + * has ALREADY been decremented (done during event_dispatch_and_delete) -- so + * remember to do this if you call event_delete() directly */ +void event_delete(struct npool *nsp, struct nevent *nse) { + if (nse->iod == NULL) + nsock_log_debug("%s (IOD #NULL) (EID #%li)", __func__, nse->id); + else + nsock_log_debug("%s (IOD #%li) (EID #%li)", __func__, nse->iod->id, nse->id); + + /* First free the IOBuf inside it if necessary */ + if (nse->type == NSE_TYPE_READ || nse->type == NSE_TYPE_WRITE) { + fs_free(&nse->iobuf); + } + #if HAVE_PCAP + if (nse->type == NSE_TYPE_PCAP_READ) { + fs_free(&nse->iobuf); + nsock_log_debug_all("PCAP removed %lu", nse->id); + } + #endif + + /* Now we add the event back into the free pool */ + nse->event_done = 1; +} + + +/* Takes an nse_type (as returned by nse_type() and returns a static string name + * that you can use for printing, etc. */ +const char *nse_type2str(enum nse_type type) { + switch (type) { + case NSE_TYPE_CONNECT: return "CONNECT"; + case NSE_TYPE_CONNECT_SSL: return "SSL-CONNECT"; + case NSE_TYPE_READ: return "READ"; + case NSE_TYPE_WRITE: return "WRITE"; + case NSE_TYPE_TIMER: return "TIMER"; + case NSE_TYPE_PCAP_READ: return "READ-PCAP"; + default: + return "UNKNOWN!"; + } +} + +/* Takes an nse_status (as returned by nse_status() and returns a static string + * name that you can use for printing, etc. */ +const char *nse_status2str(enum nse_status status) { + switch (status) { + case NSE_STATUS_NONE: return "NONE"; + case NSE_STATUS_SUCCESS: return "SUCCESS"; + case NSE_STATUS_ERROR: return "ERROR"; + case NSE_STATUS_TIMEOUT: return "TIMEOUT"; + case NSE_STATUS_CANCELLED: return "CANCELLED"; + case NSE_STATUS_KILL: return "KILL"; + case NSE_STATUS_EOF: return "EOF"; + case NSE_STATUS_PROXYERROR: return "PROXY ERROR"; + default: + return "UNKNOWN!"; + } +} + +int event_timedout(struct nevent *nse) { + if (nse->event_done) + return 0; + + return (nse->timeout.tv_sec && !TIMEVAL_AFTER(nse->timeout, nsock_tod)); +} diff --git a/nsock/src/nsock_internal.h b/nsock/src/nsock_internal.h new file mode 100644 index 0000000..dc47c3f --- /dev/null +++ b/nsock/src/nsock_internal.h @@ -0,0 +1,522 @@ +/*************************************************************************** + * nsock_internal.h -- PRIVATE interface definitions for the guts of the * + * nsock parallel socket event library. Applications calling this library * + * should NOT include this. even LOOK at these :). * + * * + ***********************IMPORTANT NSOCK LICENSE TERMS*********************** + * + * The nsock parallel socket event library is (C) 1999-2023 Nmap Software LLC + * This library is free software; you may redistribute and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation; Version 2. This guarantees your right to use, modify, and + * redistribute this software under certain conditions. If this license is + * unacceptable to you, Nmap Software LLC may be willing to sell alternative + * licenses (contact sales@nmap.com ). + * + * As a special exception to the GPL terms, Nmap Software LLC grants permission + * to link the code of this program with any version of the OpenSSL library + * which is distributed under a license identical to that listed in the included + * docs/licenses/OpenSSL.txt file, and distribute linked combinations including + * the two. You must obey the GNU GPL in all respects for all of the code used + * other than OpenSSL. If you modify this file, you may extend this exception to + * your version of the file, but you are not obligated to do so. + * + * If you received these files with a written license agreement stating terms + * other than the (GPL) terms above, then that alternative license agreement + * takes precedence over this comment. + * + * Source is provided to this software because we believe users have a right to + * know exactly what a program is going to do before they run it. This also + * allows you to audit the software for security holes. + * + * Source code also allows you to port Nmap to new platforms, fix bugs, and add + * new features. You are highly encouraged to send your changes to the + * dev@nmap.org mailing list for possible incorporation into the main + * distribution. By sending these changes to Fyodor or one of the Insecure.Org + * development mailing lists, or checking them into the Nmap source code + * repository, it is understood (unless you specify otherwise) that you are + * offering the Nmap Project (Nmap Software LLC) the unlimited, non-exclusive + * right to reuse, modify, and relicense the code. Nmap will always be available + * Open Source, but this is important because the inability to relicense code + * has caused devastating problems for other Free Software projects (such as KDE + * and NASM). We also occasionally relicense the code to third parties as + * discussed above. If you wish to specify special license conditions of your + * contributions, just say so when you send them. + * + * 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 v2.0 for more + * details (http://www.gnu.org/licenses/gpl-2.0.html). + * + ***************************************************************************/ + +/* $Id$ */ + +#ifndef NSOCK_INTERNAL_H +#define NSOCK_INTERNAL_H + +#include <nbase.h> + +#ifdef HAVE_CONFIG_H +#include "nsock_config.h" +#include "nbase_config.h" +#endif + +#ifdef WIN32 +#include "nbase_winconfig.h" +#include <Winsock2.h> +#endif + +#include "gh_list.h" +#include "gh_heap.h" +#include "filespace.h" +#include "nsock.h" /* The public interface -- I need it for some enum defs */ +#include "nsock_ssl.h" +#include "nsock_proxy.h" + +#if HAVE_SYS_TIME_H +#include <sys/time.h> +#endif +#if HAVE_UNISTD_H +#include <unistd.h> +#endif +#if HAVE_SYS_SOCKET_H +#include <sys/socket.h> +#endif +#if HAVE_NETINET_IN_H +#include <netinet/in.h> +#endif +#if HAVE_ARPA_INET_H +#include <arpa/inet.h> +#endif +#if HAVE_STRING_H +#include <string.h> +#endif +#if HAVE_STRINGS_H +#include <strings.h> +#endif +#if HAVE_SYS_UN_H +#include <sys/un.h> +#endif + +#ifndef IPPROTO_SCTP +#define IPPROTO_SCTP 132 +#endif + + +/* ------------------- CONSTANTS ------------------- */ +#define READ_BUFFER_SZ 8192 + +enum nsock_read_types { + NSOCK_READLINES, + NSOCK_READBYTES, + NSOCK_READ +}; + +enum iod_state { + NSIOD_STATE_DELETED, + NSIOD_STATE_INITIAL, + + /* sd was provided to us in nsock_iod_new2 (see nsock_iod.c) */ + NSIOD_STATE_UNKNOWN, + + NSIOD_STATE_CONNECTED_TCP, + NSIOD_STATE_CONNECTED_UDP +}; + +/* XXX: ensure that these values can be OR'ed when adding new ones */ +#define EV_NONE 0x00 +#define EV_READ 0x01 +#define EV_WRITE 0x02 +#define EV_EXCEPT 0x04 + + +/* ------------------- STRUCTURES ------------------- */ + +struct readinfo { + enum nsock_read_types read_type; + /* num lines; num bytes; whatever (depends on read_type) */ + int num; +}; + +struct writeinfo { + struct sockaddr_storage dest; + size_t destlen; + /* Number of bytes successfully written */ + int written_so_far; +}; + +/* Remember that callers of this library should NOT be accessing these + * fields directly */ +struct npool { + /* User data, NULL if unset */ + void *userdata; + + /* IO Engine vtable */ + struct io_engine *engine; + /* IO Engine internal data */ + void *engine_data; + + /* Active network events */ + gh_list_t connect_events; + gh_list_t read_events; + gh_list_t write_events; +#if HAVE_PCAP + gh_list_t pcap_read_events; +#endif + gh_heap_t expirables; + + /* Active iods and related lists of events */ + gh_list_t active_iods; + + /* struct niod structures that have been freed for reuse */ + gh_list_t free_iods; + /* When an event is deleted, we stick it here for later reuse */ + gh_list_t free_events; + + /* Number of events pending (total) on all lists */ + int events_pending; + + /* Serial # of next event (used to create next nsock_event_id */ + unsigned long next_event_serial; + /* Serial # of next iod to be created */ + unsigned long next_iod_serial; + + /* If nsock_loop() returns NSOCK_LOOP_ERROR, this is where we describe the + * error (errnum fashion) */ + int errnum; + + /* If true, new sockets will have SO_BROADCAST set */ + int broadcast; + + /* Interface to bind to; only supported on Linux with SO_BINDTODEVICE sockopt. */ + const char *device; + + /* If true, exit the next iteration of nsock_loop with a status of + * NSOCK_LOOP_QUIT. */ + int quit; + +#if HAVE_OPENSSL + /* The SSL Context (options and such) */ + SSL_CTX *sslctx; +#ifdef HAVE_DTLS_CLIENT_METHOD + SSL_CTX *dtlsctx; +#endif +#endif + + /* Optional proxy chain (NULL is not set). Can only be set once per NSP (using + * nsock_proxychain_new() or nsock_pool_set_proxychain(). */ + struct proxy_chain *px_chain; + +}; + + +/* nsock_iod is like a "file descriptor" for the nsock library. You use it to + * request events. */ +struct niod { + /* The socket descriptor related to the event */ + int sd; + + /* Number of pending events on this iod */ + int events_pending; + + /* Pending events */ + gh_lnode_t *first_connect; + gh_lnode_t *first_read; + gh_lnode_t *first_write; +#if HAVE_PCAP + gh_lnode_t *first_pcap_read; +#endif + + int readsd_count; + int writesd_count; +#if HAVE_PCAP + int readpcapsd_count; +#endif + + int watched_events; + + /* The struct npool used to create the iod (used for deletion) */ + struct npool *nsp; + + enum iod_state state; + + /* The host and port we are connected to using sd (saves a call to getpeername) */ + struct sockaddr_storage peer; + /* The host and port to bind to with sd */ + struct sockaddr_storage local; + + /* The length of peer/local actually used (sizeof(sockaddr_in) or + * sizeof(sockaddr_in6), SUN_LEN(sockaddr_un), or 0 if peer/local + * has not been filled in */ + size_t locallen; + size_t peerlen; + + /* -1 if none yet, otherwise IPPROTO_TCP, etc. */ + int lastproto; + + /* The struct npool keeps track of NIODs that have been allocated so that it + * can destroy them if the msp is deleted. This pointer makes it easy to + * remove this struct niod from the allocated list when necessary */ + gh_lnode_t nodeq; + +#define IOD_REGISTERED 0x01 +#define IOD_PROCESSED 0x02 /* internally used by engine_kqueue.c */ + +#define IOD_PROPSET(iod, flag) ((iod)->_flags |= (flag)) +#define IOD_PROPCLR(iod, flag) ((iod)->_flags &= ~(flag)) +#define IOD_PROPGET(iod, flag) (((iod)->_flags & (flag)) != 0) + char _flags; + + /* Used for SSL Server Name Indication. */ + char *hostname; + +#if HAVE_OPENSSL + /* An SSL connection (or NULL if none) */ + SSL *ssl; + /* SSL SESSION ID (or NULL if none) */ + SSL_SESSION *ssl_session; +#else + /* Because there are many if (nsi->ssl) cases in the code */ + char *ssl; +#endif + /* Every iod has an id which is always unique for the same nspool (unless you + * create billions of them) */ + unsigned long id; + + /* No. of bytes read from the sd*/ + unsigned long read_count; + /* No. of bytes written to the sd */ + unsigned long write_count; + + void *userdata; + + /* IP options to set on socket before connect() */ + void *ipopts; + int ipoptslen; + + /* Pointer to mspcap struct (used only if pcap support is included) */ + void *pcap; + + struct proxy_chain_context *px_ctx; + +}; + + +/* nsock_event_t handles a single event. Its ID is generally returned when the + * event is created, and the event is included in callbacks */ +struct nevent { + /* Every event has an ID which is unique for a given nsock unless you blow + * through more than 500,000,000 events */ + nsock_event_id id; + + enum nse_type type; + enum nse_status status; + + /* For write events, this is the data to be written, for read events, this is + * what we will read into */ + struct filespace iobuf; + + /* The timeout of the event -- absolute time + * except that tv_sec == 0 means no timeout */ + struct timeval timeout; + + /* Info pertaining to READ requests */ + struct readinfo readinfo; + /* Info pertaining to WRITE requests */ + struct writeinfo writeinfo; + +#if HAVE_OPENSSL + struct sslinfo sslinfo; +#endif + + /* If we return a status of NSE_STATUS_ERROR, this must be set */ + int errnum; + + /* The nsock I/O descriptor related to event (if applicable) */ + struct niod *iod; + + /* The handler to call when event is complete */ + nsock_ev_handler handler; + + /* slot in the expirable binheap */ + gh_hnode_t expire; + + /* For some reasons (see nsock_pcap.c) we register pcap events as both read + * and pcap_read events when in PCAP_BSD_SELECT_HACK mode. We then need two + * gh_lnode_t handles. To make code simpler, we _always_ use _nodeq_pcap for + * pcap_read events and _nodeq_io for the other ones. + * When not in PCAP_BSD_SELECT_HACK mode we define both handles as members + * of an union to optimize memory footprint. */ + gh_lnode_t nodeq_io; + gh_lnode_t nodeq_pcap; + + /* Optional (NULL if unset) pointer to pass to the handler */ + void *userdata; + + /* If this event is all filled out and ready for immediate delivery, + * event_done is nonzero. Used when event is finished at unexpected time and + * we want to dispatch it later to avoid duplicating stat update code and all + * that other crap */ + unsigned int event_done: 1; + unsigned int eof: 1; + +#if HAVE_IOCP + struct extended_overlapped *eov; +#endif +}; + +struct io_operations { + int(*iod_connect)(struct npool *nsp, int sockfd, const struct sockaddr *addr, socklen_t addrlen); + + int(*iod_read)(struct npool *nsp, int sockfd, void *buf, size_t len, int flags, + struct sockaddr *src_addr, socklen_t *addrlen); + + int(*iod_write)(struct npool *nsp, int sockfd, const void *buf, size_t len, int flags, + const struct sockaddr *dest_addr, socklen_t addrlen); +}; + +struct io_engine { + /* Human readable identifier for this engine. */ + const char *name; + + /* Engine constructor */ + int (*init)(struct npool *nsp); + + /* Engine destructor */ + void (*destroy)(struct npool *nsp); + + /* Register a new IOD to the engine */ + int(*iod_register)(struct npool *nsp, struct niod *iod, struct nevent *nse, int ev); + + /* Remove a registered IOD */ + int(*iod_unregister)(struct npool *nsp, struct niod *iod); + + /* Modify events for a registered IOD. + * - ev_set represent the events to add + * - ev_clr represent the events to delete (if set) */ + int (*iod_modify)(struct npool *nsp, struct niod *iod, struct nevent *nse, int ev_set, int ev_clr); + + /* Main engine loop */ + int (*loop)(struct npool *nsp, int msec_timeout); + + /* I/O operations */ + struct io_operations *io_operations; +}; + +/* ----------- NSOCK I/O ENGINE CONVENIENCE WRAPPERS ------------ */ +static inline int nsock_engine_init(struct npool *nsp) { + return nsp->engine->init(nsp); +} + +static inline void nsock_engine_destroy(struct npool *nsp) { + nsp->engine->destroy(nsp); + return; +} + +static inline int nsock_engine_iod_register(struct npool *nsp, struct niod *iod, struct nevent *nse, int ev) { + return nsp->engine->iod_register(nsp, iod, nse, ev); +} + +static inline int nsock_engine_iod_unregister(struct npool *nsp, struct niod *iod) { + return nsp->engine->iod_unregister(nsp, iod); +} + +static inline int nsock_engine_iod_modify(struct npool *nsp, struct niod *iod, struct nevent *nse, int ev_set, int ev_clr) { + return nsp->engine->iod_modify(nsp, iod, nse, ev_set, ev_clr); +} + +static inline int nsock_engine_loop(struct npool *nsp, int msec_timeout) { + return nsp->engine->loop(nsp, msec_timeout); +} + +/* ------------------- PROTOTYPES ------------------- */ + +int event_timedout(struct nevent *nse); + +/* Get a new nsock_event_id, given a type */ +nsock_event_id get_new_event_id(struct npool *nsp, enum nse_type type); + +/* Take an event ID and return the type (NSE_TYPE_CONNECT, etc */ +enum nse_type get_event_id_type(nsock_event_id event_id); + +/* Create a new event structure -- must be deleted later with event_delete, + * unless it returns NULL (failure). NULL can be passed in for the struct niod and + * the userdata if not available. */ +struct nevent *event_new(struct npool *nsp, enum nse_type type, struct niod *iod, + int timeout_msecs, nsock_ev_handler handler, void *userdata); + +/* An internal function for cancelling an event when you already have a pointer + * to the struct nevent (use nsock_event_cancel if you just have an ID). The + * event_list passed in should correspond to the type of the event. For + * example, with NSE_TYPE_READ, you would pass in &iod->read_events;. elem + * is the list element in event_list which holds the event. Pass a nonzero for + * notify if you want the program owning the event to be notified that it has + * been cancelled */ +int nevent_delete(struct npool *nsp, struct nevent *nse, gh_list_t *event_list, gh_lnode_t *elem, int notify); + +/* Adjust various statistics, dispatches the event handler (if notify is + * nonzero) and then deletes the event. This function does NOT delete the event + * from any lists it might be on (eg nsp->read_list etc.) nse->event_done + * MUST be true when you call this */ +void event_dispatch_and_delete(struct npool *nsp, struct nevent *nse, int notify); + +/* Free an struct nevent which was allocated with event_new, including all internal + * resources. Note -- we assume that nse->iod->events_pending (if it exists) + * has ALREADY been decremented (done during event_dispatch_and_delete) -- so + * remember to do this if you call event_delete() directly */ +void event_delete(struct npool *nsp, struct nevent *nse); + +/* Add an event to the appropriate nsp event list, handles housekeeping such as + * adjusting the descriptor select/poll lists, registering the timeout value, + * etc. */ +void nsock_pool_add_event(struct npool *nsp, struct nevent *nse); + +void nsock_connect_internal(struct npool *ms, struct nevent *nse, int type, int proto, struct sockaddr_storage *ss, size_t sslen, unsigned int port); + +/* Comments on using the following handle_*_result functions are available in nsock_core.c */ + +/* handle_connect_results assumes that select or poll have already shown the + * descriptor to be active */ +void handle_connect_result(struct npool *ms, struct nevent *nse, enum nse_status status); + +void handle_read_result(struct npool *ms, struct nevent *nse, enum nse_status status); + +void handle_write_result(struct npool *ms, struct nevent *nse, enum nse_status status); + +void handle_timer_result(struct npool *ms, struct nevent *nse, enum nse_status status); + +#if HAVE_PCAP +void handle_pcap_read_result(struct npool *ms, struct nevent *nse, enum nse_status status); +#endif + +/* An event has been completed and the handler is about to be called. This + * function writes out tracing data about the event if necessary */ +void nsock_trace_handler_callback(struct npool *ms, struct nevent *nse); + +#if HAVE_OPENSSL +/* Sets the ssl session of an nsock_iod, increments usage count. The session + * should not have been set yet (as no freeing is done) */ +void nsi_set_ssl_session(struct niod *iod, SSL_SESSION *sessid); +#endif + +static inline struct nevent *next_expirable_event(struct npool *nsp) { + gh_hnode_t *hnode; + + hnode = gh_heap_min(&nsp->expirables); + if (!hnode) + return NULL; + + return container_of(hnode, struct nevent, expire); +} + +static inline struct nevent *lnode_nevent(gh_lnode_t *lnode) { + return container_of(lnode, struct nevent, nodeq_io); +} + +static inline struct nevent *lnode_nevent2(gh_lnode_t *lnode) { + return container_of(lnode, struct nevent, nodeq_pcap); +} + +#endif /* NSOCK_INTERNAL_H */ + diff --git a/nsock/src/nsock_iod.c b/nsock/src/nsock_iod.c new file mode 100644 index 0000000..d74ab5e --- /dev/null +++ b/nsock/src/nsock_iod.c @@ -0,0 +1,455 @@ +/*************************************************************************** + * nsock_iod.c -- This contains the functions relating to nsock_iod (and * + * its nsock internal manifestation -- nsockiod. This is is similar to a * + * file descriptor in that you create it and then use it to initiate * + * connections, read/write data, etc. * + * * + ***********************IMPORTANT NSOCK LICENSE TERMS*********************** + * + * The nsock parallel socket event library is (C) 1999-2023 Nmap Software LLC + * This library is free software; you may redistribute and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation; Version 2. This guarantees your right to use, modify, and + * redistribute this software under certain conditions. If this license is + * unacceptable to you, Nmap Software LLC may be willing to sell alternative + * licenses (contact sales@nmap.com ). + * + * As a special exception to the GPL terms, Nmap Software LLC grants permission + * to link the code of this program with any version of the OpenSSL library + * which is distributed under a license identical to that listed in the included + * docs/licenses/OpenSSL.txt file, and distribute linked combinations including + * the two. You must obey the GNU GPL in all respects for all of the code used + * other than OpenSSL. If you modify this file, you may extend this exception to + * your version of the file, but you are not obligated to do so. + * + * If you received these files with a written license agreement stating terms + * other than the (GPL) terms above, then that alternative license agreement + * takes precedence over this comment. + * + * Source is provided to this software because we believe users have a right to + * know exactly what a program is going to do before they run it. This also + * allows you to audit the software for security holes. + * + * Source code also allows you to port Nmap to new platforms, fix bugs, and add + * new features. You are highly encouraged to send your changes to the + * dev@nmap.org mailing list for possible incorporation into the main + * distribution. By sending these changes to Fyodor or one of the Insecure.Org + * development mailing lists, or checking them into the Nmap source code + * repository, it is understood (unless you specify otherwise) that you are + * offering the Nmap Project (Nmap Software LLC) the unlimited, non-exclusive + * right to reuse, modify, and relicense the code. Nmap will always be available + * Open Source, but this is important because the inability to relicense code + * has caused devastating problems for other Free Software projects (such as KDE + * and NASM). We also occasionally relicense the code to third parties as + * discussed above. If you wish to specify special license conditions of your + * contributions, just say so when you send them. + * + * 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 v2.0 for more + * details (http://www.gnu.org/licenses/gpl-2.0.html). + * + ***************************************************************************/ + +/* $Id$ */ + +#include "nsock.h" +#include "nsock_internal.h" +#include "nsock_log.h" +#include "gh_list.h" +#include "netutils.h" + +#if HAVE_PCAP +#include "nsock_pcap.h" +#endif + +#include <string.h> + + +/* nsock_iod is like a "file descriptor" for the nsock library. You use it to + * request events. And here is how you create an nsock_iod. nsock_iod_new returns + * NULL if the iod cannot be allocated. Pass NULL as userdata if you don't want + * to immediately associate any user data with the iod. */ +nsock_iod nsock_iod_new(nsock_pool nsockp, void *userdata) { + return nsock_iod_new2(nsockp, -1, userdata); +} + +/* This version allows you to associate an existing sd with the msi so that you + * can read/write it using the nsock infrastructure. For example, you may want + * to watch for data from STDIN_FILENO at the same time as you read/write + * various sockets. STDIN_FILENO is a special case, however. Any other sd is + * dup()ed, so you may close or otherwise manipulate your copy. The duped copy + * will be destroyed when the nsi is destroyed. */ +nsock_iod nsock_iod_new2(nsock_pool nsockp, int sd, void *userdata) { + struct npool *nsp = (struct npool *)nsockp; + gh_lnode_t *lnode; + struct niod *nsi; + + lnode = gh_list_pop(&nsp->free_iods); + if (!lnode) { + nsi = (struct niod *)safe_malloc(sizeof(*nsi)); + memset(nsi, 0, sizeof(*nsi)); + } else { + nsi = container_of(lnode, struct niod, nodeq); + } + + if (sd == -1) { + nsi->sd = -1; + nsi->state = NSIOD_STATE_INITIAL; + } else if (sd == STDIN_FILENO) { + nsi->sd = STDIN_FILENO; + nsi->state = NSIOD_STATE_UNKNOWN; + } else { + nsi->sd = dup_socket(sd); + if (nsi->sd == -1) { + free(nsi); + return NULL; + } + unblock_socket(nsi->sd); + nsi->state = NSIOD_STATE_UNKNOWN; + } + + nsi->first_connect = NULL; + nsi->first_read = NULL; + nsi->first_write = NULL; +#if HAVE_PCAP + nsi->first_pcap_read = NULL; + nsi->readpcapsd_count = 0; +#endif + nsi->readsd_count = 0; + nsi->write_count = 0; + + nsi->userdata = userdata; + nsi->nsp = (struct npool *)nsockp; + + nsi->_flags = 0; + + nsi->read_count = 0; + nsi->write_count = 0; + + nsi->hostname = NULL; + + nsi->ipopts = NULL; + nsi->ipoptslen = 0; + +#if HAVE_OPENSSL + nsi->ssl_session = NULL; +#endif + + if (nsp->px_chain) { + nsi->px_ctx = proxy_chain_context_new(nsp); + } else { + nsi->px_ctx = NULL; + } + + nsi->id = nsp->next_iod_serial++; + if (nsi->id == 0) + nsi->id = nsp->next_iod_serial++; + + /* The nsp keeps track of active iods so it can delete them if it is deleted */ + gh_list_append(&nsp->active_iods, &nsi->nodeq); + + nsock_log_info("nsock_iod_new (IOD #%lu)", nsi->id); + + return (nsock_iod)nsi; +} + +/* Defined in nsock_core.c. */ +int socket_count_zero(struct niod *iod, struct npool *ms); + +/* If nsock_iod_new returned success, you must free the iod when you are done with + * it to conserve memory (and in some cases, sockets). After this call, + * nsockiod may no longer be used -- you need to create a new one with + * nsock_iod_new(). pending_response tells what to do with any events that are + * pending on this nsock_iod. This can be NSOCK_PENDING_NOTIFY (send a KILL + * notification to each event), NSOCK_PENDING_SILENT (do not send notification + * to the killed events), or NSOCK_PENDING_ERROR (print an error message and + * quit the program) */ +void nsock_iod_delete(nsock_iod nsockiod, enum nsock_del_mode pending_response) { +#if HAVE_PCAP +#define NUM_EVT_TYPES 4 +#else +#define NUM_EVT_TYPES 3 +#endif + struct niod *nsi = (struct niod *)nsockiod; + gh_lnode_t *evlist_ar[NUM_EVT_TYPES]; + gh_list_t *corresp_list[NUM_EVT_TYPES]; + int i; + gh_lnode_t *current, *next; + + assert(nsi); + + if (nsi->state == NSIOD_STATE_DELETED) { + /* This nsi is already marked as deleted, will probably be removed from the + * list very soon. Just return to avoid breaking reentrancy. */ + return; + } + + nsock_log_info("nsock_iod_delete (IOD #%lu)", nsi->id); + + if (nsi->events_pending > 0) { + /* shit -- they killed the struct niod while an event was still pending on it. + * Maybe I should store the pending events in the iod. On the other hand, + * this should be a pretty rare occurrence and so I'll save space and hassle + * by just locating the events here by searching through the active events + * list */ + if (pending_response == NSOCK_PENDING_ERROR) + fatal("nsock_iod_delete called with argument NSOCK_PENDING_ERROR on a nsock_iod that has %d pending event(s) associated with it", nsi->events_pending); + + assert(pending_response == NSOCK_PENDING_NOTIFY || pending_response == NSOCK_PENDING_SILENT); + + evlist_ar[0] = nsi->first_connect; + evlist_ar[1] = nsi->first_read; + evlist_ar[2] = nsi->first_write; +#if HAVE_PCAP + evlist_ar[3] = nsi->first_pcap_read; +#endif + + corresp_list[0] = &nsi->nsp->connect_events; + corresp_list[1] = &nsi->nsp->read_events; + corresp_list[2] = &nsi->nsp->write_events; +#if HAVE_PCAP + corresp_list[3] = &nsi->nsp->pcap_read_events; +#endif + + for (i = 0; i < NUM_EVT_TYPES && nsi->events_pending > 0; i++) { + for (current = evlist_ar[i]; current != NULL; current = next) { + struct nevent *nse; + + next = gh_lnode_next(current); + nse = lnode_nevent(current); + + /* we're done with this list of events for the current IOD */ + if (nse->iod != nsi) + break; + + nevent_delete(nsi->nsp, nse, corresp_list[i], current, pending_response == NSOCK_PENDING_NOTIFY); + } + } + } + + if (nsi->events_pending != 0) + fatal("Trying to delete NSI, but could not find %d of the purportedly pending events on that IOD.\n", nsi->events_pending); + + /* Make sure we no longer select on this socket, in case the socket counts + * weren't already decremented to zero. */ + if (nsi->sd >= 0) + socket_count_zero(nsi, nsi->nsp); + + free(nsi->hostname); + +#if HAVE_OPENSSL + /* Close any SSL resources */ + if (nsi->ssl) { + /* No longer free session because copy nsi stores is not reference counted */ +#if 0 + if (nsi->ssl_session) + SSL_SESSION_free(nsi->ssl_session); + nsi->ssl_session = NULL; +#endif + + if (SSL_shutdown(nsi->ssl) == -1) { + nsock_log_info("nsock_iod_delete: SSL shutdown failed (%s) on NSI %li", + ERR_reason_error_string(SSL_get_error(nsi->ssl, -1)), nsi->id); + } + + /* I don't really care if the SSL_shutdown() succeeded politely. I could + * make the SD blocking temporarily for this, but I'm hoping it will succeed + * 95% of the time because we can usually write to a socket. */ + SSL_free(nsi->ssl); + nsi->ssl = NULL; + } +#endif + + if (nsi->sd >= 0 && nsi->sd != STDIN_FILENO) { + close(nsi->sd); + nsi->sd = -1; + } + + nsi->state = NSIOD_STATE_DELETED; + nsi->userdata = NULL; + + if (nsi->ipoptslen) + free(nsi->ipopts); + +#if HAVE_PCAP + if (nsi->pcap){ + mspcap *mp = (mspcap *)nsi->pcap; + + if (mp->pt){ + pcap_close(mp->pt); + mp->pt = NULL; + } + if (mp->pcap_desc) { + /* pcap_close() will close the associated pcap descriptor */ + mp->pcap_desc = -1; + } + if (mp->pcap_device) { + free(mp->pcap_device); + mp->pcap_device = NULL; + } + free(mp); + nsi->pcap = NULL; + } +#endif + + if (nsi->px_ctx) + proxy_chain_context_delete(nsi->px_ctx); +} + +/* Returns the ID of an nsock_iod . This ID is always unique amongst ids for a + * given nspool (unless you blow through billions of them). */ +unsigned long nsock_iod_id(nsock_iod nsockiod) { + assert(nsockiod); + return ((struct niod *)nsockiod)->id; +} + +/* Returns the SSL object inside an nsock_iod, or NULL if unset. */ +nsock_ssl nsock_iod_get_ssl(nsock_iod iod) { +#if HAVE_OPENSSL + return ((struct niod *)iod)->ssl; +#else + return NULL; +#endif +} + +/* Returns the SSL_SESSION of an nsock_iod. + * Increments its usage count if inc_ref is not zero. */ +nsock_ssl_session nsock_iod_get_ssl_session(nsock_iod iod, int inc_ref) { +#if HAVE_OPENSSL + if (inc_ref) + return SSL_get1_session(((struct niod *)iod)->ssl); + else + return SSL_get0_session(((struct niod *)iod)->ssl); +#else + return NULL; +#endif +} + +/* sets the ssl session of an nsock_iod, increments usage count. The session + * should not have been set yet (as no freeing is done) */ +#if HAVE_OPENSSL +void nsi_set_ssl_session(struct niod *iod, SSL_SESSION *sessid) { + if (sessid) { + iod->ssl_session = sessid; + /* No reference counting for the copy stored briefly in nsiod */ + } +} +#endif + +/* Sometimes it is useful to store a pointer to information inside the struct niod so + * you can retrieve it during a callback. */ +void nsock_iod_set_udata(nsock_iod iod, void *udata) { + assert(iod); + ((struct niod *)iod)->userdata = udata; +} + +/* And the function above wouldn't make much sense if we didn't have a way to + * retrieve that data... */ +void *nsock_iod_get_udata(nsock_iod iod) { + assert(iod); + return ((struct niod *)iod)->userdata; +} + +/* Returns 1 if an NSI is communicating via SSL, 0 otherwise. */ +int nsock_iod_check_ssl(nsock_iod iod) { + return (((struct niod *)iod)->ssl) ? 1 : 0; +} + +/* Returns the remote peer port (or -1 if unavailable). Note the return value + * is a whole int so that -1 can be distinguished from 65535. Port is returned + * in host byte order. */ +int nsock_iod_get_peerport(nsock_iod iod) { + struct niod *nsi = (struct niod *)iod; + int fam; + + if (nsi->peerlen <= 0) + return -1; + + fam = ((struct sockaddr_in *)&nsi->peer)->sin_family; + + if (fam == AF_INET) + return ntohs(((struct sockaddr_in *)&nsi->peer)->sin_port); +#if HAVE_IPV6 + else if (fam == AF_INET6) + return ntohs(((struct sockaddr_in6 *)&nsi->peer)->sin6_port); +#endif + + return -1; +} + +/* Sets the local address to bind to before connect() */ +int nsock_iod_set_localaddr(nsock_iod iod, struct sockaddr_storage *ss, + size_t sslen) { + struct niod *nsi = (struct niod *)iod; + + assert(nsi); + + if (sslen > sizeof(nsi->local)) + return -1; + + memcpy(&nsi->local, ss, sslen); + nsi->locallen = sslen; + return 0; +} + +/* Sets IPv4 options to apply before connect(). It makes a copy of the options, + * so you can free() yours if necessary. This copy is freed when the iod is + * destroyed. */ +int nsock_iod_set_ipoptions(nsock_iod iod, void *opts, size_t optslen) { + struct niod *nsi = (struct niod *)iod; + + assert(nsi); + + if (optslen > 44) + return -1; + + nsi->ipopts = safe_malloc(optslen); + memcpy(nsi->ipopts, opts, optslen); + nsi->ipoptslen = optslen; + return 0; +} + +/* I didn't want to do this. Its an ugly hack, but I suspect it will be + * necessary. I certainly can't reproduce in nsock EVERYTHING you might want + * to do with a socket. So I'm offering you this function to obtain the socket + * descriptor which is (usually) wrapped in a nsock_iod). You can do + * "reasonable" things with it, like setting socket receive buffers. But don't + * create havok by closing the descriptor! If the descriptor you get back is + * -1, the iod does not currently possess a valid descriptor */ +int nsock_iod_get_sd(nsock_iod iod) { + struct niod *nsi = (struct niod *)iod; + + assert(nsi); + +#if HAVE_PCAP + if (nsi->pcap) + return ((mspcap *)nsi->pcap)->pcap_desc; + else +#endif + return nsi->sd; +} + +unsigned long nsock_iod_get_read_count(nsock_iod iod){ + assert(iod); + return ((struct niod *)iod)->read_count; +} + +unsigned long nsock_iod_get_write_count(nsock_iod iod){ + assert(iod); + return ((struct niod *)iod)->write_count; +} + +int nsock_iod_set_hostname(nsock_iod iod, const char *hostname) { + struct niod *nsi = (struct niod *)iod; + + if (nsi->hostname != NULL) + free(nsi->hostname); + + nsi->hostname = strdup(hostname); + if (nsi->hostname == NULL) + return -1; + + return 0; +} + diff --git a/nsock/src/nsock_log.c b/nsock/src/nsock_log.c new file mode 100644 index 0000000..5ef033c --- /dev/null +++ b/nsock/src/nsock_log.c @@ -0,0 +1,116 @@ +/*************************************************************************** + * nsock_log.c -- nsock logging infrastructure. * + * * + ***********************IMPORTANT NSOCK LICENSE TERMS*********************** + * + * The nsock parallel socket event library is (C) 1999-2023 Nmap Software LLC + * This library is free software; you may redistribute and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation; Version 2. This guarantees your right to use, modify, and + * redistribute this software under certain conditions. If this license is + * unacceptable to you, Nmap Software LLC may be willing to sell alternative + * licenses (contact sales@nmap.com ). + * + * As a special exception to the GPL terms, Nmap Software LLC grants permission + * to link the code of this program with any version of the OpenSSL library + * which is distributed under a license identical to that listed in the included + * docs/licenses/OpenSSL.txt file, and distribute linked combinations including + * the two. You must obey the GNU GPL in all respects for all of the code used + * other than OpenSSL. If you modify this file, you may extend this exception to + * your version of the file, but you are not obligated to do so. + * + * If you received these files with a written license agreement stating terms + * other than the (GPL) terms above, then that alternative license agreement + * takes precedence over this comment. + * + * Source is provided to this software because we believe users have a right to + * know exactly what a program is going to do before they run it. This also + * allows you to audit the software for security holes. + * + * Source code also allows you to port Nmap to new platforms, fix bugs, and add + * new features. You are highly encouraged to send your changes to the + * dev@nmap.org mailing list for possible incorporation into the main + * distribution. By sending these changes to Fyodor or one of the Insecure.Org + * development mailing lists, or checking them into the Nmap source code + * repository, it is understood (unless you specify otherwise) that you are + * offering the Nmap Project (Nmap Software LLC) the unlimited, non-exclusive + * right to reuse, modify, and relicense the code. Nmap will always be available + * Open Source, but this is important because the inability to relicense code + * has caused devastating problems for other Free Software projects (such as KDE + * and NASM). We also occasionally relicense the code to third parties as + * discussed above. If you wish to specify special license conditions of your + * contributions, just say so when you send them. + * + * 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 v2.0 for more + * details (http://www.gnu.org/licenses/gpl-2.0.html). + * + ***************************************************************************/ + +/* $Id$ */ + + +#define _GNU_SOURCE +#include <stdio.h> + +#include <stdlib.h> +#include <string.h> +#include <errno.h> +#include <assert.h> + +#include "nsock_internal.h" +#include "nsock_log.h" + +static void nsock_stderr_logger(const struct nsock_log_rec *rec); + +extern struct timeval nsock_tod; + +nsock_loglevel_t NsockLogLevel = NSOCK_LOG_ERROR; +nsock_logger_t NsockLogger = nsock_stderr_logger; + + +void nsock_set_log_function(nsock_logger_t logger) { + if (logger != NULL) + NsockLogger = logger; + else + NsockLogger = nsock_stderr_logger; + + nsock_log_debug("Registered external logging function: %p", NsockLogger); +} + +nsock_loglevel_t nsock_get_loglevel(void) { + return NsockLogLevel; +} + +void nsock_set_loglevel(nsock_loglevel_t loglevel) { + NsockLogLevel = loglevel; + nsock_log_debug("Set log level to %s", nsock_loglevel2str(loglevel)); +} + +void nsock_stderr_logger(const struct nsock_log_rec *rec) { + fprintf(stderr, "libnsock %s(): %s\n", rec->func, rec->msg); +} + +void __nsock_log_internal(nsock_loglevel_t loglevel, const char *file, int line, + const char *func, const char *format, ...) { + struct nsock_log_rec rec; + va_list args; + int rc; + + va_start(args, format); + + rec.level = loglevel; + rec.time = nsock_tod; + rec.file = file; + rec.line = line; + rec.func = func; + + rc = vasprintf(&rec.msg, format, args); + if (rc >= 0) { + NsockLogger(&rec); + free(rec.msg); + } + va_end(args); +} + diff --git a/nsock/src/nsock_log.h b/nsock/src/nsock_log.h new file mode 100644 index 0000000..49b0dea --- /dev/null +++ b/nsock/src/nsock_log.h @@ -0,0 +1,115 @@ +/*************************************************************************** + * nsock_log.c -- nsock logging infrastructure. * + * * + ***********************IMPORTANT NSOCK LICENSE TERMS*********************** + * + * The nsock parallel socket event library is (C) 1999-2023 Nmap Software LLC + * This library is free software; you may redistribute and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation; Version 2. This guarantees your right to use, modify, and + * redistribute this software under certain conditions. If this license is + * unacceptable to you, Nmap Software LLC may be willing to sell alternative + * licenses (contact sales@nmap.com ). + * + * As a special exception to the GPL terms, Nmap Software LLC grants permission + * to link the code of this program with any version of the OpenSSL library + * which is distributed under a license identical to that listed in the included + * docs/licenses/OpenSSL.txt file, and distribute linked combinations including + * the two. You must obey the GNU GPL in all respects for all of the code used + * other than OpenSSL. If you modify this file, you may extend this exception to + * your version of the file, but you are not obligated to do so. + * + * If you received these files with a written license agreement stating terms + * other than the (GPL) terms above, then that alternative license agreement + * takes precedence over this comment. + * + * Source is provided to this software because we believe users have a right to + * know exactly what a program is going to do before they run it. This also + * allows you to audit the software for security holes. + * + * Source code also allows you to port Nmap to new platforms, fix bugs, and add + * new features. You are highly encouraged to send your changes to the + * dev@nmap.org mailing list for possible incorporation into the main + * distribution. By sending these changes to Fyodor or one of the Insecure.Org + * development mailing lists, or checking them into the Nmap source code + * repository, it is understood (unless you specify otherwise) that you are + * offering the Nmap Project (Nmap Software LLC) the unlimited, non-exclusive + * right to reuse, modify, and relicense the code. Nmap will always be available + * Open Source, but this is important because the inability to relicense code + * has caused devastating problems for other Free Software projects (such as KDE + * and NASM). We also occasionally relicense the code to third parties as + * discussed above. If you wish to specify special license conditions of your + * contributions, just say so when you send them. + * + * 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 v2.0 for more + * details (http://www.gnu.org/licenses/gpl-2.0.html). + * + ***************************************************************************/ + +/* $Id$ */ + + +#ifndef NSOCK_LOG_H +#define NSOCK_LOG_H + +#include "nsock.h" + +extern nsock_loglevel_t NsockLogLevel; +extern nsock_logger_t NsockLogger; + + +#define NSOCK_LOG_WRAP(lvl, ...) \ + do { \ + if (NsockLogger && (lvl) >= NsockLogLevel) { \ + __nsock_log_internal((lvl), __FILE__, __LINE__, __func__, __VA_ARGS__); \ + } \ + } while (0) + + +static inline const char *nsock_loglevel2str(nsock_loglevel_t level) +{ + switch (level) { + case NSOCK_LOG_DBG_ALL: + return "FULL DEBUG"; + case NSOCK_LOG_DBG: + return "DEBUG"; + case NSOCK_LOG_INFO: + return "INFO"; + case NSOCK_LOG_ERROR: + return "ERROR"; + default: + return "???"; + } +} + +/* -- Internal logging macros -- */ +/** + * Most detailed debug messages, like allocating or moving objects. + */ +#define nsock_log_debug_all(...) NSOCK_LOG_WRAP(NSOCK_LOG_DBG_ALL, __VA_ARGS__) + +/** + * Detailed debug messages, describing internal operations. + */ +#define nsock_log_debug(...) NSOCK_LOG_WRAP(NSOCK_LOG_DBG, __VA_ARGS__) + +/** + * High level debug messages, describing top level operations and external + * requests. + */ +#define nsock_log_info(...) NSOCK_LOG_WRAP(NSOCK_LOG_INFO, __VA_ARGS__) + +/** + * Error messages. + */ +#define nsock_log_error(...) NSOCK_LOG_WRAP(NSOCK_LOG_ERROR, __VA_ARGS__) + + +void __nsock_log_internal(nsock_loglevel_t loglevel, const char *file, int line, + const char *func, const char *format, ...) + __attribute__((format (printf, 5, 6))); + +#endif /* NSOCK_LOG_H */ + diff --git a/nsock/src/nsock_pcap.c b/nsock/src/nsock_pcap.c new file mode 100644 index 0000000..c9e43d4 --- /dev/null +++ b/nsock/src/nsock_pcap.c @@ -0,0 +1,516 @@ +/*************************************************************************** + * nsock_pcap.c -- This contains pcap operations functions from * + * the nsock parallel socket event library * + * * + ***********************IMPORTANT NSOCK LICENSE TERMS*********************** + * + * The nsock parallel socket event library is (C) 1999-2023 Nmap Software LLC + * This library is free software; you may redistribute and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation; Version 2. This guarantees your right to use, modify, and + * redistribute this software under certain conditions. If this license is + * unacceptable to you, Nmap Software LLC may be willing to sell alternative + * licenses (contact sales@nmap.com ). + * + * As a special exception to the GPL terms, Nmap Software LLC grants permission + * to link the code of this program with any version of the OpenSSL library + * which is distributed under a license identical to that listed in the included + * docs/licenses/OpenSSL.txt file, and distribute linked combinations including + * the two. You must obey the GNU GPL in all respects for all of the code used + * other than OpenSSL. If you modify this file, you may extend this exception to + * your version of the file, but you are not obligated to do so. + * + * If you received these files with a written license agreement stating terms + * other than the (GPL) terms above, then that alternative license agreement + * takes precedence over this comment. + * + * Source is provided to this software because we believe users have a right to + * know exactly what a program is going to do before they run it. This also + * allows you to audit the software for security holes. + * + * Source code also allows you to port Nmap to new platforms, fix bugs, and add + * new features. You are highly encouraged to send your changes to the + * dev@nmap.org mailing list for possible incorporation into the main + * distribution. By sending these changes to Fyodor or one of the Insecure.Org + * development mailing lists, or checking them into the Nmap source code + * repository, it is understood (unless you specify otherwise) that you are + * offering the Nmap Project (Nmap Software LLC) the unlimited, non-exclusive + * right to reuse, modify, and relicense the code. Nmap will always be available + * Open Source, but this is important because the inability to relicense code + * has caused devastating problems for other Free Software projects (such as KDE + * and NASM). We also occasionally relicense the code to third parties as + * discussed above. If you wish to specify special license conditions of your + * contributions, just say so when you send them. + * + * 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 v2.0 for more + * details (http://www.gnu.org/licenses/gpl-2.0.html). + * + ***************************************************************************/ + +/* $Id$ */ + +#include "nsock.h" +#include "nsock_internal.h" +#include "nsock_log.h" + +#include <limits.h> +#if HAVE_SYS_IOCTL_H +#include <sys/ioctl.h> +#endif +#if HAVE_NET_BPF_H +#ifdef _AIX +/* Prevent bpf.h from redefining the DLT_ values to their IFT_ values. (See + * similar comment in libpcap/pcap-bpf.c.) */ +#undef _AIX +#include <net/bpf.h> +#define _AIX +#else +#include <net/bpf.h> +#endif +#endif + +#include "nsock_pcap.h" + +extern struct timeval nsock_tod; + +#if HAVE_PCAP + +#ifndef PCAP_NETMASK_UNKNOWN +/* libpcap before 1.1.1 (e.g. WinPcap) doesn't handle this specially, so just use 0 netmask */ +#define PCAP_NETMASK_UNKNOWN 0 +#endif + +#define PCAP_OPEN_MAX_RETRIES 3 + +#define PCAP_FAILURE_EXPL_MESSAGE \ + "There are several possible reasons for this, " \ + "depending on your operating system:\n" \ + "LINUX: If you are getting Socket type not supported, " \ + "try modprobe af_packet or recompile your kernel with PACKET enabled.\n" \ + "*BSD: If you are getting device not configured, you need to recompile " \ + "your kernel with Berkeley Packet Filter support." \ + "If you are getting No such file or directory, try creating the device " \ + "(eg cd /dev; MAKEDEV <device>; or use mknod).\n" \ + "*WINDOWS: Nmap only supports ethernet interfaces on Windows for most " \ + "operations because Microsoft disabled raw sockets as of Windows XP SP2. " \ + "Depending on the reason for this error, it is possible that the " \ + "--unprivileged command-line argument will help.\n" \ + "SOLARIS: If you are trying to scan localhost and getting "\ + "'/dev/lo0: No such file or directory', complain to Sun. "\ + "I don't think Solaris can support advanced localhost scans. "\ + "You can probably use \"-PN -sT localhost\" though.\n\n" + + +static int nsock_pcap_set_filter(struct npool *nsp, pcap_t *pt, const char *device, + const char *bpf) { + struct bpf_program fcode; + int rc; + + rc = pcap_compile(pt, &fcode, (char *)bpf, 1, PCAP_NETMASK_UNKNOWN); + if (rc) { + nsock_log_error("Error compiling pcap filter: %s", pcap_geterr(pt)); + return rc; + } + + rc = pcap_setfilter(pt, &fcode); + if (rc) { + nsock_log_error("Failed to set the pcap filter: %s", pcap_geterr(pt)); + return rc; + } + + pcap_freecode(&fcode); + return 0; +} + +static int nsock_pcap_get_l3_offset(pcap_t *pt, int *dl) { + int datalink; + unsigned int offset = 0; + + /* New packet capture device, need to recompute offset */ + if ((datalink = pcap_datalink(pt)) < 0) + fatal("Cannot obtain datalink information: %s", pcap_geterr(pt)); + + /* XXX NOTE: + * if a new offset ever exceeds the current max (24), + * adjust MAX_LINK_HEADERSZ in libnetutil/netutil.h + */ + switch (datalink) { + case DLT_EN10MB: offset = 14; break; + case DLT_IEEE802: offset = 22; break; + #ifdef __amigaos__ + case DLT_MIAMI: offset = 16; break; + #endif + #ifdef DLT_LOOP + case DLT_LOOP: + #endif + case DLT_NULL: offset = 4; break; + + case DLT_SLIP: + #ifdef DLT_SLIP_BSDOS + case DLT_SLIP_BSDOS: + #endif + #if (FREEBSD || OPENBSD || NETBSD || BSDI || MACOSX) + offset = 16;break; + #else + offset = 24;break; /* Anyone use this??? */ + #endif + + case DLT_PPP: + #ifdef DLT_PPP_BSDOS + case DLT_PPP_BSDOS: + #endif + #ifdef DLT_PPP_SERIAL + case DLT_PPP_SERIAL: + #endif + #ifdef DLT_PPP_ETHER + case DLT_PPP_ETHER: + #endif + #if (FREEBSD || OPENBSD || NETBSD || BSDI || MACOSX) + offset = 4;break; + #else + #ifdef SOLARIS + offset = 8;break; + #else + offset = 24;break; /* Anyone use this? */ + #endif /* ifdef solaris */ + #endif /* if freebsd || openbsd || netbsd || bsdi */ + #ifdef DLT_RAW + case DLT_RAW: offset = 0; break; + #endif /* DLT_RAW */ + case DLT_FDDI: offset = 21; break; + #ifdef DLT_ENC + case DLT_ENC: offset = 12; break; + #endif /* DLT_ENC */ + #ifdef DLT_LINUX_SLL + case DLT_LINUX_SLL: offset = 16; break; + #endif + #ifdef DLT_IPNET + case DLT_IPNET: offset = 24; break; + #endif /* DLT_IPNET */ + + default: /* Sorry, link type is unknown. */ + fatal("Unknown datalink type %d.\n", datalink); + } + if (dl) + *dl = datalink; + return (offset); +} + +/* Convert new nsiod to pcap descriptor. Other parameters have + * the same meaning as for pcap_open_live in pcap(3). + * device : pcap-style device name + * snaplen : size of packet to be copied to handler + * promisc : whether to open device in promiscuous mode + * bpf_fmt : berkeley filter + * return value: NULL if everything was okay, or error string + * if error occurred. */ +int nsock_pcap_open(nsock_pool nsp, nsock_iod nsiod, const char *pcap_device, + int snaplen, int promisc, const char *bpf_fmt, ...) { + struct niod *nsi = (struct niod *)nsiod; + struct npool *ms = (struct npool *)nsp; + mspcap *mp = (mspcap *)nsi->pcap; + char errbuf[PCAP_ERRBUF_SIZE]; + char bpf[4096]; + va_list ap; + int failed, datalink; + int rc; + +#ifdef PCAP_CAN_DO_SELECT +#if PCAP_BSD_SELECT_HACK + /* MacOsX reports error if to_ms is too big (like INT_MAX) with error + * FAILED. Reported error: BIOCSRTIMEOUT: Invalid argument + * INT_MAX/6 (=357913941) seems to be working... */ + int to_ms = 357913941; +#else + int to_ms = 200; +#endif /* PCAP_BSD_SELECT_HACK */ + +#else + int to_ms = 1; +#endif + + gettimeofday(&nsock_tod, NULL); + + if (mp) { + nsock_log_error("This nsi already has pcap device opened"); + return -1; + } + + mp = (mspcap *)safe_zalloc(sizeof(mspcap)); + nsi->pcap = (void *)mp; + + va_start(ap, bpf_fmt); + rc = Vsnprintf(bpf, sizeof(bpf), bpf_fmt, ap); + va_end(ap); + + if (rc >= (int)sizeof(bpf)) { + nsock_log_error("Too-large bpf filter argument"); + return -1; + } + + nsock_log_info("PCAP requested on device '%s' with berkeley filter '%s' " + "(promisc=%i snaplen=%i to_ms=%i) (IOD #%li)", + pcap_device,bpf, promisc, snaplen, to_ms, nsi->id); + +#ifdef __amigaos__ + // Amiga doesn't have pcap_create + // TODO: Does Nmap still work on Amiga? + mp->pt = pcap_open_live(pcap_device, snaplen, promisc, to_ms, errbuf); + if (!mp->pt) { + nsock_log_error("pcap_open_live(%s, %d, %d, %d) failed with error: %s", + pcap_device, snaplen, promisc, to_ms, errbuf); + nsock_log_error(PCAP_FAILURE_EXPL_MESSAGE); + nsock_log_error("Can't open pcap! Are you root?"); + return -1; + } +#else + mp->pt = pcap_create(pcap_device, errbuf); + if (!mp->pt) { + nsock_log_error("pcap_create(%s) failed with error: %s", pcap_device, errbuf); + nsock_log_error(PCAP_FAILURE_EXPL_MESSAGE); + nsock_log_error("Can't open pcap! Are you root?"); + return -1; + } + +#define MY_PCAP_SET(func, p_t, val) do {\ + failed = func(p_t, val);\ + if (failed) {\ + nsock_log_error(#func "(%d) FAILED: %d.", val, failed);\ + pcap_close(p_t);\ + return -1;\ + }\ +} while(0); + + MY_PCAP_SET(pcap_set_snaplen, mp->pt, snaplen); + MY_PCAP_SET(pcap_set_promisc, mp->pt, promisc); + MY_PCAP_SET(pcap_set_timeout, mp->pt, to_ms); +#ifdef HAVE_PCAP_SET_IMMEDIATE_MODE + MY_PCAP_SET(pcap_set_immediate_mode, mp->pt, 1); +#endif + + failed = pcap_activate(mp->pt); + if (failed < 0) { + // PCAP error + nsock_log_error("pcap_activate(%s) FAILED: %s.", pcap_device, pcap_geterr(mp->pt)); + pcap_close(mp->pt); + mp->pt = NULL; + return -1; + } + else if (failed > 0) { + // PCAP warning, report but assume it'll still work + nsock_log_error("pcap_activate(%s) WARNING: %s.", pcap_device, pcap_geterr(mp->pt)); + } +#endif /* not __amigaos__ */ + + rc = nsock_pcap_set_filter(ms, mp->pt, pcap_device, bpf); + if (rc) + return rc; + + mp->l3_offset = nsock_pcap_get_l3_offset(mp->pt, &datalink); + mp->snaplen = snaplen; + mp->datalink = datalink; + mp->pcap_device = strdup(pcap_device); +#ifdef PCAP_CAN_DO_SELECT + mp->pcap_desc = pcap_get_selectable_fd(mp->pt); +#else + mp->pcap_desc = -1; +#endif + mp->readsd_count = 0; + +#ifndef HAVE_PCAP_SET_IMMEDIATE_MODE + /* This is already handled by pcap_set_immediate_mode if available */ +#ifdef BIOCIMMEDIATE + /* Without setting this ioctl, some systems (BSDs, though it depends on the + * release) will buffer packets in non-blocking mode and only return them in a + * bunch when the buffer is full. Setting the ioctl makes each one be + * delivered immediately. This is how Linux works by default. See the comments + * surrounding the setting of BIOCIMMEDIATE in libpcap/pcap-bpf.c. */ + if (mp->pcap_desc != -1) { + int immediate = 1; + + if (ioctl(mp->pcap_desc, BIOCIMMEDIATE, &immediate) < 0) + fatal("Cannot set BIOCIMMEDIATE on pcap descriptor"); + } +#elif defined WIN32 + /* We want any responses back ASAP */ + pcap_setmintocopy(mp->pt, 0); +#endif +#endif + + /* Set device non-blocking */ + rc = pcap_setnonblock(mp->pt, 1, errbuf); + if (rc) { + + /* I can't do select() on pcap! + * blocking + no_select is fatal */ +#ifndef PCAP_BSD_SELECT_HACK + if (mp->pcap_desc < 0) +#endif + { + nsock_log_error("Failed to set pcap descriptor on device %s " + "to nonblocking mode: %s", pcap_device, errbuf); + return -1; + } + /* in other case, we can accept blocking pcap */ + nsock_log_info("Failed to set pcap descriptor on device %s " + "to nonblocking state: %s", pcap_device, errbuf); + } + + if (NsockLogLevel <= NSOCK_LOG_INFO) { + #if PCAP_BSD_SELECT_HACK + int bsd_select_hack = 1; + #else + int bsd_select_hack = 0; + #endif + + #if PCAP_RECV_TIMEVAL_VALID + int recv_timeval_valid = 1; + #else + int recv_timeval_valid = 0; + #endif + + nsock_log_info("PCAP created successfully on device '%s' " + "(pcap_desc=%i bsd_hack=%i to_valid=%i l3_offset=%i) (IOD #%li)", + pcap_device, mp->pcap_desc, bsd_select_hack, + recv_timeval_valid, mp->l3_offset, nsi->id); + } + return 0; +} + +/* Requests exactly one packet to be captured. */ +nsock_event_id nsock_pcap_read_packet(nsock_pool nsp, nsock_iod nsiod, + nsock_ev_handler handler, + int timeout_msecs, void *userdata) { + struct niod *nsi = (struct niod *)nsiod; + struct npool *ms = (struct npool *)nsp; + struct nevent *nse; + + nse = event_new(ms, NSE_TYPE_PCAP_READ, nsi, timeout_msecs, handler, userdata); + assert(nse); + + nsock_log_info("Pcap read request from IOD #%li EID %li", nsi->id, nse->id); + + nsock_pool_add_event(ms, nse); + + return nse->id; +} + +/* Remember that pcap descriptor is in nonblocking state. */ +int do_actual_pcap_read(struct nevent *nse) { + mspcap *mp = (mspcap *)nse->iod->pcap; + nsock_pcap npp; + nsock_pcap *n; + struct pcap_pkthdr *pkt_header; + const unsigned char *pkt_data = NULL; + int rc; + + memset(&npp, 0, sizeof(nsock_pcap)); + + nsock_log_debug_all("PCAP %s TEST (IOD #%li) (EID #%li)", + __func__, nse->iod->id, nse->id); + + assert(fs_length(&(nse->iobuf)) == 0); + + rc = pcap_next_ex(mp->pt, &pkt_header, &pkt_data); + switch (rc) { + case 1: /* read good packet */ +#ifdef PCAP_RECV_TIMEVAL_VALID + npp.ts = pkt_header->ts; +#else + /* On these platforms time received from pcap is invalid. + * It's better to set current time */ + memcpy(&npp.ts, nsock_gettimeofday(), sizeof(struct timeval)); +#endif + npp.len = pkt_header->len; + npp.caplen = pkt_header->caplen; + npp.packet = pkt_data; + + fs_cat(&(nse->iobuf), (char *)&npp, sizeof(npp)); + fs_cat(&(nse->iobuf), (char *)pkt_data, npp.caplen); + n = (nsock_pcap *)fs_str(&(nse->iobuf)); + n->packet = (unsigned char *)fs_str(&(nse->iobuf)) + sizeof(npp); + + nsock_log_debug_all("PCAP %s READ (IOD #%li) (EID #%li) size=%i", + __func__, nse->iod->id, nse->id, pkt_header->caplen); + rc = 1; + break; + + case 0: /* timeout */ + rc = 0; + break; + + case -1: /* error */ + fatal("pcap_next_ex() fatal error while reading from pcap: %s\n", + pcap_geterr(mp->pt)); + break; + + case -2: /* no more packets in savefile (if reading from one) */ + default: + fatal("Unexpected return code from pcap_next_ex! (%d)\n", rc); + } + + return rc; +} + +void nse_readpcap(nsock_event nsev, const unsigned char **l2_data, size_t *l2_len, + const unsigned char **l3_data, size_t *l3_len, + size_t *packet_len, struct timeval *ts) { + struct nevent *nse = (struct nevent *)nsev; + struct niod *iod = nse->iod; + mspcap *mp = (mspcap *)iod->pcap; + nsock_pcap *n; + size_t l2l; + size_t l3l; + + n = (nsock_pcap *)fs_str(&(nse->iobuf)); + if (fs_length(&(nse->iobuf)) < sizeof(nsock_pcap)) { + if (l2_data) + *l2_data = NULL; + if (l2_len) + *l2_len = 0; + if (l3_data) + *l3_data = NULL; + if (l3_len) + *l3_len = 0; + if (packet_len) + *packet_len = 0; + return; + } + + l2l = MIN(mp->l3_offset, n->caplen); + l3l = MAX(0, n->caplen-mp->l3_offset); + + if (l2_data) + *l2_data = n->packet; + if (l2_len) + *l2_len = l2l; + if (l3_data) + *l3_data = (l3l > 0) ? n->packet+l2l : NULL; + if (l3_len) + *l3_len = l3l; + if (packet_len) + *packet_len = n->len; + if (ts) + *ts = n->ts; + return; +} + +int nsock_iod_linktype(nsock_iod iod) { + struct niod *nsi = (struct niod *)iod; + mspcap *mp = (mspcap *)nsi->pcap; + + assert(mp); + return (mp->datalink); +} + +int nsock_iod_is_pcap(nsock_iod iod) { + struct niod *nsi = (struct niod *)iod; + mspcap *mp = (mspcap *)nsi->pcap; + + return (mp != NULL); +} + +#endif /* HAVE_PCAP */ + diff --git a/nsock/src/nsock_pcap.h b/nsock/src/nsock_pcap.h new file mode 100644 index 0000000..ca667db --- /dev/null +++ b/nsock/src/nsock_pcap.h @@ -0,0 +1,152 @@ +/*************************************************************************** + * nsock_pcap.h -- Header for pcap operations functions from * + * the nsock parallel socket event library * + * * + ***********************IMPORTANT NSOCK LICENSE TERMS*********************** + * + * The nsock parallel socket event library is (C) 1999-2023 Nmap Software LLC + * This library is free software; you may redistribute and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation; Version 2. This guarantees your right to use, modify, and + * redistribute this software under certain conditions. If this license is + * unacceptable to you, Nmap Software LLC may be willing to sell alternative + * licenses (contact sales@nmap.com ). + * + * As a special exception to the GPL terms, Nmap Software LLC grants permission + * to link the code of this program with any version of the OpenSSL library + * which is distributed under a license identical to that listed in the included + * docs/licenses/OpenSSL.txt file, and distribute linked combinations including + * the two. You must obey the GNU GPL in all respects for all of the code used + * other than OpenSSL. If you modify this file, you may extend this exception to + * your version of the file, but you are not obligated to do so. + * + * If you received these files with a written license agreement stating terms + * other than the (GPL) terms above, then that alternative license agreement + * takes precedence over this comment. + * + * Source is provided to this software because we believe users have a right to + * know exactly what a program is going to do before they run it. This also + * allows you to audit the software for security holes. + * + * Source code also allows you to port Nmap to new platforms, fix bugs, and add + * new features. You are highly encouraged to send your changes to the + * dev@nmap.org mailing list for possible incorporation into the main + * distribution. By sending these changes to Fyodor or one of the Insecure.Org + * development mailing lists, or checking them into the Nmap source code + * repository, it is understood (unless you specify otherwise) that you are + * offering the Nmap Project (Nmap Software LLC) the unlimited, non-exclusive + * right to reuse, modify, and relicense the code. Nmap will always be available + * Open Source, but this is important because the inability to relicense code + * has caused devastating problems for other Free Software projects (such as KDE + * and NASM). We also occasionally relicense the code to third parties as + * discussed above. If you wish to specify special license conditions of your + * contributions, just say so when you send them. + * + * 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 v2.0 for more + * details (http://www.gnu.org/licenses/gpl-2.0.html). + * + ***************************************************************************/ + +/* $Id$ */ + +#ifndef NSOCK_PCAP_H +#define NSOCK_PCAP_H + +#include "nsock_internal.h" +#ifdef HAVE_PCAP + +#include "pcap.h" + +#include <string.h> +#include <stdarg.h> + +/* + * There are three possible ways to read packets from pcap descriptor: + * - select() on descriptor: + * this one is of course the best, but there are systems that + * don't support this like WIN32. This works perfectly for Linux. + * + * - select() + some hacks: + * this one is hack for older bsd systems, + * Descriptor *must* be set in nonblocking mode. + * + * - never do select(): + * this one is for WIN32 and other systems that return descriptor -1 + * from pcap_get_selectable_fd(). + * In this case descriptor *must* be set in nonblocking mode. + * If that fails than we can't do any sniffing from that box. + * + * In any case we try to set descriptor to non-blocking mode. + */ + +/* Returns whether the system supports pcap_get_selectable_fd() properly */ +#if !defined(WIN32) && !defined(SOLARIS_BPF_PCAP_CAPTURE) +#define PCAP_CAN_DO_SELECT 1 +#endif + +/* In some systems (like Windows), the pcap descriptor is not selectable. + * Therefore, we cannot just select() on it and expect it to wake us up and + * deliver a packet, but we need to poll it continuously. This define sets the + * frequency, in milliseconds, at which the pcap handle is polled to determine + * if there are any captured packets. Note that this is only used when + * PCAP_CAN_DO_SELECT is not defined and therefore it has no effect on systems + * like Linux. + */ +#define PCAP_POLL_INTERVAL 2 + +/* Note that on most versions of most BSDs (including Mac OS X) select() and + * poll() do not work correctly on BPF devices; pcap_get_selectable_fd() will + * return a file descriptor on most of those versions (the exceptions being + * FreeBSD 4.3 and 4.4), a simple select() or poll() will not return even after + * a timeout specified in pcap_open_live() expires. To work around this, an + * application that uses select() or poll() to wait for packets to arrive must + * put the pcap_t in non-blocking mode, and must arrange that the select() or + * poll() have a timeout less than or equal to the timeout specified in + * pcap_open_live(), and must try to read packets after that timeout expires, + * regardless of whether select() or poll() indicated that the file descriptor + * for the pcap_t is ready to be read or not. (That workaround will not work in + * FreeBSD 4.3 and later; however, in FreeBSD 4.6 and later, select() and poll() + * work correctly on BPF devices, so the workaround isn't necessary, although it + * does no harm.) + */ +#if defined(MACOSX) || defined(FREEBSD) || defined(OPENBSD) +/* Well, now select() is not receiving any pcap events on MACOSX, but maybe it + * will someday :) in both cases. It never hurts to enable this feature. It just + * has performance penalty. */ +#define PCAP_BSD_SELECT_HACK 1 +#endif + +/* Returns whether the packet receive time value obtained from libpcap + * (and thus by readip_pcap()) should be considered valid. When + * invalid (Windows and Amiga), readip_pcap returns the time you called it. */ +#if !defined(WIN32) && !defined(__amigaos__) +#define PCAP_RECV_TIMEVAL_VALID 1 +#endif + + +typedef struct{ + pcap_t *pt; + int pcap_desc; + /* Like the corresponding member in iod, when this reaches 0 we stop + * watching the socket for readability. */ + int readsd_count; + int datalink; + int l3_offset; + int snaplen; + char *pcap_device; +} mspcap; + +typedef struct{ + struct timeval ts; + int caplen; + int len; + const unsigned char *packet; /* caplen bytes */ +} nsock_pcap; + +int do_actual_pcap_read(struct nevent *nse); + +#endif /* HAVE_PCAP */ +#endif /* NSOCK_PCAP_H */ + diff --git a/nsock/src/nsock_pool.c b/nsock/src/nsock_pool.c new file mode 100644 index 0000000..485a68b --- /dev/null +++ b/nsock/src/nsock_pool.c @@ -0,0 +1,308 @@ +/*************************************************************************** + * nsock_pool.c -- This contains the functions that deal with creating, * + * destroying, and otherwise manipulating nsock_pools (and their internal * + * struct npool representation). An nsock_pool aggregates and manages events * + * and i/o descriptors * + * * + ***********************IMPORTANT NSOCK LICENSE TERMS*********************** + * + * The nsock parallel socket event library is (C) 1999-2023 Nmap Software LLC + * This library is free software; you may redistribute and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation; Version 2. This guarantees your right to use, modify, and + * redistribute this software under certain conditions. If this license is + * unacceptable to you, Nmap Software LLC may be willing to sell alternative + * licenses (contact sales@nmap.com ). + * + * As a special exception to the GPL terms, Nmap Software LLC grants permission + * to link the code of this program with any version of the OpenSSL library + * which is distributed under a license identical to that listed in the included + * docs/licenses/OpenSSL.txt file, and distribute linked combinations including + * the two. You must obey the GNU GPL in all respects for all of the code used + * other than OpenSSL. If you modify this file, you may extend this exception to + * your version of the file, but you are not obligated to do so. + * + * If you received these files with a written license agreement stating terms + * other than the (GPL) terms above, then that alternative license agreement + * takes precedence over this comment. + * + * Source is provided to this software because we believe users have a right to + * know exactly what a program is going to do before they run it. This also + * allows you to audit the software for security holes. + * + * Source code also allows you to port Nmap to new platforms, fix bugs, and add + * new features. You are highly encouraged to send your changes to the + * dev@nmap.org mailing list for possible incorporation into the main + * distribution. By sending these changes to Fyodor or one of the Insecure.Org + * development mailing lists, or checking them into the Nmap source code + * repository, it is understood (unless you specify otherwise) that you are + * offering the Nmap Project (Nmap Software LLC) the unlimited, non-exclusive + * right to reuse, modify, and relicense the code. Nmap will always be available + * Open Source, but this is important because the inability to relicense code + * has caused devastating problems for other Free Software projects (such as KDE + * and NASM). We also occasionally relicense the code to third parties as + * discussed above. If you wish to specify special license conditions of your + * contributions, just say so when you send them. + * + * 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 v2.0 for more + * details (http://www.gnu.org/licenses/gpl-2.0.html). + * + ***************************************************************************/ + +/* $Id$ */ + +#include "nsock_internal.h" +#include "nsock_log.h" +#include "gh_list.h" +#include "netutils.h" + +#include <string.h> +#ifdef HAVE_SYS_TIME_H +#include <sys/time.h> +#endif +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif +#include <signal.h> + +#if HAVE_SYS_RESOURCE_H +#include <sys/resource.h> +#endif + +extern struct timeval nsock_tod; + +/* To use this library, the first thing they must do is create a pool + * so we do the initialization during the first pool creation */ +static int nsocklib_initialized = 0; + + +/* defined in nsock_engines.h */ +struct io_engine *get_io_engine(void); + +/* ---- INTERNAL FUNCTIONS PROTOTYPES ---- */ +static void nsock_library_initialize(void); +/* --------------------------------------- */ + + +/* This next function returns the errno style error code -- which is only + * valid if the status NSOCK_LOOP_ERROR was returned by nsock_loop() */ +int nsock_pool_get_error(nsock_pool nsp) { + struct npool *mt = (struct npool *)nsp; + return mt->errnum; +} + +/* Sometimes it is useful to store a pointer to information inside + * the NSP so you can retrieve it during a callback. */ +void nsock_pool_set_udata(nsock_pool nsp, void *data) { + struct npool *mt = (struct npool *)nsp; + mt->userdata = data; +} + +/* And the define above wouldn't make much sense if we didn't have a way + * to retrieve that data ... */ +void *nsock_pool_get_udata(nsock_pool nsp) { + struct npool *mt = (struct npool *)nsp; + return mt->userdata; +} + +/* Turns on or off broadcast support on new sockets. Default is off (0, false) + * set in nsock_pool_new(). Any non-zero (true) value sets SO_BROADCAST on all new + * sockets (value of optval will be used directly in the setsockopt() call */ +void nsock_pool_set_broadcast(nsock_pool nsp, int optval) { + struct npool *mt = (struct npool *)nsp; + mt->broadcast = optval; +} + +/* Sets the name of the interface for new sockets to bind to. */ +void nsock_pool_set_device(nsock_pool nsp, const char *device) { + struct npool *mt = (struct npool *)nsp; + mt->device = device; +} + +static int expirable_cmp(gh_hnode_t *n1, gh_hnode_t *n2) { + struct nevent *nse1; + struct nevent *nse2; + + nse1 = container_of(n1, struct nevent, expire); + nse2 = container_of(n2, struct nevent, expire); + + return (TIMEVAL_BEFORE(nse1->timeout, nse2->timeout)) ? 1 : 0; +} + +/* And here is how you create an nsock_pool. This allocates, initializes, and + * returns an nsock_pool event aggregator. In the case of error, NULL will be + * returned. If you do not wish to immediately associate any userdata, pass in + * NULL. */ +nsock_pool nsock_pool_new(void *userdata) { + struct npool *nsp; + + /* initialize the library in not already done */ + if (!nsocklib_initialized) { + nsock_library_initialize(); + nsocklib_initialized = 1; + } + + nsp = (struct npool *)safe_malloc(sizeof(*nsp)); + memset(nsp, 0, sizeof(*nsp)); + + gettimeofday(&nsock_tod, NULL); + + nsp->userdata = userdata; + + nsp->engine = get_io_engine(); + nsock_engine_init(nsp); + + /* initialize IO events lists */ + gh_list_init(&nsp->connect_events); + gh_list_init(&nsp->read_events); + gh_list_init(&nsp->write_events); +#if HAVE_PCAP + gh_list_init(&nsp->pcap_read_events); +#endif + + /* initialize timer heap */ + gh_heap_init(&nsp->expirables, expirable_cmp); + + /* initialize the list of IODs */ + gh_list_init(&nsp->active_iods); + + /* initialize caches */ + gh_list_init(&nsp->free_iods); + gh_list_init(&nsp->free_events); + + nsp->next_event_serial = 1; + + nsp->device = NULL; + +#if HAVE_OPENSSL + nsp->sslctx = NULL; + nsp->dtlsctx = NULL; +#endif + + nsp->px_chain = NULL; + + return (nsock_pool)nsp; +} + +/* If nsock_pool_new returned success, you must free the nsp when you are done with it + * to conserve memory (and in some cases, sockets). After this call, nsp may no + * longer be used. Any pending events are sent an NSE_STATUS_KILL callback and + * all outstanding iods are deleted. */ +void nsock_pool_delete(nsock_pool ms_pool) { + struct npool *nsp = (struct npool *)ms_pool; + struct nevent *nse; + struct niod *nsi; + int i; + gh_lnode_t *current, *next; + gh_list_t *event_lists[] = { + &nsp->connect_events, + &nsp->read_events, + &nsp->write_events, +#if HAVE_PCAP + &nsp->pcap_read_events, +#endif + NULL + }; + + assert(nsp); + + /* First I go through all the events sending NSE_STATUS_KILL */ + for (i = 0; event_lists[i] != NULL; i++) { + while (gh_list_count(event_lists[i]) > 0) { + gh_lnode_t *lnode = gh_list_pop(event_lists[i]); + + assert(lnode); + +#if HAVE_PCAP + if (event_lists[i] == &nsp->pcap_read_events) + nse = lnode_nevent2(lnode); + else +#endif + nse = lnode_nevent(lnode); + + assert(nse); + + nse->status = NSE_STATUS_KILL; + nsock_trace_handler_callback(nsp, nse); + nse->handler(nsp, nse, nse->userdata); + + if (nse->iod) { + nse->iod->events_pending--; + assert(nse->iod->events_pending >= 0); + } + event_delete(nsp, nse); + } + gh_list_free(event_lists[i]); + } + + /* Kill timers too, they're not in event lists */ + while (gh_heap_count(&nsp->expirables) > 0) { + gh_hnode_t *hnode; + + hnode = gh_heap_pop(&nsp->expirables); + nse = container_of(hnode, struct nevent, expire); + + if (nse->type == NSE_TYPE_TIMER) { + nse->status = NSE_STATUS_KILL; + nsock_trace_handler_callback(nsp, nse); + nse->handler(nsp, nse, nse->userdata); + event_delete(nsp, nse); + gh_list_append(&nsp->free_events, &nse->nodeq_io); + } + } + + gh_heap_free(&nsp->expirables); + + /* foreach struct niod */ + for (current = gh_list_first_elem(&nsp->active_iods); + current != NULL; + current = next) { + next = gh_lnode_next(current); + nsi = container_of(current, struct niod, nodeq); + + nsock_iod_delete(nsi, NSOCK_PENDING_ERROR); + + gh_list_remove(&nsp->active_iods, current); + gh_list_prepend(&nsp->free_iods, &nsi->nodeq); + } + + /* Now we free all the memory in the free iod list */ + while ((current = gh_list_pop(&nsp->free_iods))) { + nsi = container_of(current, struct niod, nodeq); + free(nsi); + } + + while ((current = gh_list_pop(&nsp->free_events))) { + nse = lnode_nevent(current); + free(nse); + } + + gh_list_free(&nsp->active_iods); + gh_list_free(&nsp->free_iods); + gh_list_free(&nsp->free_events); + + nsock_engine_destroy(nsp); + +#if HAVE_OPENSSL + nsp_ssl_cleanup(nsp); +#endif + + free(nsp); +} + +void nsock_library_initialize(void) { +#ifndef WIN32 + rlim_t res; + + /* We want to make darn sure the evil SIGPIPE is ignored */ + signal(SIGPIPE, SIG_IGN); + + /* And we're gonna need sockets -- LOTS of sockets ... */ + res = maximize_fdlimit(); + assert(res > 7); +#endif + return; +} + diff --git a/nsock/src/nsock_proxy.c b/nsock/src/nsock_proxy.c new file mode 100644 index 0000000..29a1f3d --- /dev/null +++ b/nsock/src/nsock_proxy.c @@ -0,0 +1,439 @@ +/*************************************************************************** + * nsock_proxy.c -- This contains the functions relating to proxies. * + * * + ***********************IMPORTANT NSOCK LICENSE TERMS*********************** + * + * The nsock parallel socket event library is (C) 1999-2023 Nmap Software LLC + * This library is free software; you may redistribute and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation; Version 2. This guarantees your right to use, modify, and + * redistribute this software under certain conditions. If this license is + * unacceptable to you, Nmap Software LLC may be willing to sell alternative + * licenses (contact sales@nmap.com ). + * + * As a special exception to the GPL terms, Nmap Software LLC grants permission + * to link the code of this program with any version of the OpenSSL library + * which is distributed under a license identical to that listed in the included + * docs/licenses/OpenSSL.txt file, and distribute linked combinations including + * the two. You must obey the GNU GPL in all respects for all of the code used + * other than OpenSSL. If you modify this file, you may extend this exception to + * your version of the file, but you are not obligated to do so. + * + * If you received these files with a written license agreement stating terms + * other than the (GPL) terms above, then that alternative license agreement + * takes precedence over this comment. + * + * Source is provided to this software because we believe users have a right to + * know exactly what a program is going to do before they run it. This also + * allows you to audit the software for security holes. + * + * Source code also allows you to port Nmap to new platforms, fix bugs, and add + * new features. You are highly encouraged to send your changes to the + * dev@nmap.org mailing list for possible incorporation into the main + * distribution. By sending these changes to Fyodor or one of the Insecure.Org + * development mailing lists, or checking them into the Nmap source code + * repository, it is understood (unless you specify otherwise) that you are + * offering the Nmap Project (Nmap Software LLC) the unlimited, non-exclusive + * right to reuse, modify, and relicense the code. Nmap will always be available + * Open Source, but this is important because the inability to relicense code + * has caused devastating problems for other Free Software projects (such as KDE + * and NASM). We also occasionally relicense the code to third parties as + * discussed above. If you wish to specify special license conditions of your + * contributions, just say so when you send them. + * + * 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 v2.0 for more + * details (http://www.gnu.org/licenses/gpl-2.0.html). + * + ***************************************************************************/ + +/* $Id$ */ + +#include "nsock.h" +#include "nsock_internal.h" +#include "nsock_log.h" +#include <string.h> + +#define IN_RANGE(x, min, max) ((x) >= (min) && (x) <= (max)) + +static struct proxy_node *proxy_node_new(const char *proxystr, const char *end); + +/* --- Implemented proxy backends --- */ +extern const struct proxy_spec ProxySpecHttp; +extern const struct proxy_spec ProxySpecSocks4; + + +static const struct proxy_spec *ProxyBackends[] = { + &ProxySpecHttp, + &ProxySpecSocks4, + NULL +}; + + +/* A proxy chain is a comma-separated list of proxy specification strings: + * proto://[user:pass@]host[:port] */ +int nsock_proxychain_new(const char *proxystr, nsock_proxychain *chain, nsock_pool nspool) { + struct npool *nsp = (struct npool *)nspool; + struct proxy_chain *pxc, **pchain = (struct proxy_chain **)chain; + + *pchain = NULL; + + pxc = (struct proxy_chain *)safe_malloc(sizeof(struct proxy_chain)); + gh_list_init(&pxc->nodes); + + if (proxystr) { + const char *next = proxystr; + const char *end = strchr(proxystr, ','); + struct proxy_node *proxy; + + while (end != NULL) { + proxy = proxy_node_new(next, end); + if (!proxy) + return -1; + gh_list_append(&pxc->nodes, &proxy->nodeq); + next = end + 1; + end = strchr(next, ','); + } + proxy = proxy_node_new(next, strchr(next, '\0')); + if (!proxy) + return -1; + gh_list_append(&pxc->nodes, &proxy->nodeq); + } + + if (nsp) { + if (nsock_pool_set_proxychain(nspool, pxc) < 0) { + nsock_proxychain_delete(pxc); + return -1; + } + } + + *pchain = pxc; + return 1; +} + +void nsock_proxychain_delete(nsock_proxychain chain) { + struct proxy_chain *pchain = (struct proxy_chain *)chain; + gh_lnode_t *lnode; + + if (!pchain) + return; + + while ((lnode = gh_list_pop(&pchain->nodes)) != NULL) { + struct proxy_node *node; + + node = container_of(lnode, struct proxy_node, nodeq); + node->spec->ops->node_delete(node); + } + + gh_list_free(&pchain->nodes); + free(pchain); +} + +int nsock_pool_set_proxychain(nsock_pool nspool, nsock_proxychain chain) { + struct npool *nsp = (struct npool *)nspool; + assert(nsp != NULL); + + if (nsp && nsp->px_chain) { + nsock_log_error("Invalid call. Existing proxychain on this nsock_pool"); + return -1; + } + + if (gh_list_count(&chain->nodes) < 1) { + nsock_log_error("Invalid call. No proxies in chain"); + return -1; + } + + nsp->px_chain = (struct proxy_chain *)chain; + return 1; +} + +struct proxy_chain_context *proxy_chain_context_new(nsock_pool nspool) { + struct npool *nsp = (struct npool *)nspool; + struct proxy_chain_context *ctx; + + ctx = (struct proxy_chain_context *)safe_malloc(sizeof(struct proxy_chain_context)); + ctx->px_chain = nsp->px_chain; + ctx->px_state = PROXY_STATE_INITIAL; + ctx->px_current = container_of(gh_list_first_elem(&nsp->px_chain->nodes), + struct proxy_node, + nodeq); + return ctx; +} + +void proxy_chain_context_delete(struct proxy_chain_context *ctx) { + free(ctx); +} + +static void uri_free(struct uri *uri) { + free(uri->scheme); + free(uri->user); + free(uri->pass); + free(uri->host); + free(uri->path); +} + +static int lowercase(char *s) { + char *p; + + for (p = s; *p != '\0'; p++) + *p = tolower((int) (unsigned char) *p); + + return p - s; +} + +static int hex_digit_value(char digit) { + static const char DIGITS[] = "0123456789abcdef"; + const char *p; + + if ((unsigned char)digit == '\0') + return -1; + + p = strchr(DIGITS, tolower((int)(unsigned char)digit)); + if (p == NULL) + return -1; + + return p - DIGITS; +} + +static int percent_decode(char *s) { + char *p, *q; + + /* Skip to the first '%'. If there are no percent escapes, this lets us + * return without doing any copying. */ + q = s; + while (*q != '\0' && *q != '%') + q++; + + p = q; + while (*q != '\0') { + if (*q == '%') { + int c, d; + + q++; + c = hex_digit_value(*q); + if (c == -1) + return -1; + q++; + d = hex_digit_value(*q); + if (d == -1) + return -1; + + *p++ = c * 16 + d; + q++; + } else { + *p++ = *q++; + } + } + *p = '\0'; + + return p - s; +} + +static int uri_parse_authority(const char *authority, const char *end, struct uri *uri) { + const char *portsep; + const char *host_start, *host_end; + const char *tail; + + /* We do not support "user:pass@" userinfo. The proxy has no use for it. */ + if (strchr_p(authority, end, '@') != NULL) + return -1; + + /* Find the beginning and end of the host. */ + host_start = authority; + + if (*host_start == '[') { + /* IPv6 address in brackets. */ + host_start++; + if (host_start >= end || + NULL == (host_end = strchr_p(host_start, end, ']')) + ) { + nsock_log_error("Invalid IPv6 address: %s", authority); + return -1; + } + + portsep = host_end + 1; + + } else { + for (portsep = end; portsep > host_start && *portsep != ':'; portsep--); + + if (portsep == host_start) + portsep = end; + host_end = portsep; + } + + /* Get the port number. */ + if (portsep + 1 < end && *portsep == ':') { + long n; + + errno = 0; + n = parse_long(portsep + 1, &tail); + if (errno || tail != end || !IN_RANGE(n, 1, 65535)) { + nsock_log_error("Invalid port number (%ld), errno = %d", n, errno); + return -1; + } + uri->port = n; + } else { + uri->port = -1; + } + + /* Get the host. */ + uri->host = mkstr(host_start, host_end); + if (percent_decode(uri->host) < 0) { + nsock_log_error("Invalid URL encoding in host: %s", uri->host); + free(uri->host); + uri->host = NULL; + return -1; + } + + return 1; +} + +static int parse_uri(const char *proxystr, const char *end, struct uri *uri) { + const char *p, *q; + + /* Scheme, section 3.1. */ + p = proxystr; + if (!isalpha(*p)) + goto fail; + + q = p; + while (isalpha(*q) || isdigit(*q) || *q == '+' || *q == '-' || *q == '.') { + q++; + if (q >= end) + goto fail; + } + + if (*q != ':') + goto fail; + + uri->scheme = mkstr(p, q); + + /* "An implementation should accept uppercase letters as equivalent to + * lowercase in scheme names (e.g., allow "HTTP" as well as "http") for the + * sake of robustness..." */ + lowercase(uri->scheme); + + /* Authority, section 3.2. */ + p = q + 1; + if (p >= end) + goto fail; + if (p + 1 < end && *p == '/' && *(p + 1) == '/') { + + p += 2; + q = p; + while (q < end && !(*q == '/' || *q == '?' || *q == '#' || *q == '\0')) + q++; + + if (uri_parse_authority(p, q, uri) < 0) { + goto fail; + } + + p = q; + } + + /* Path, section 3.3. We include the query and fragment in the path. The + * path is also not percent-decoded because we just pass it on to the origin + * server. */ + + uri->path = mkstr(p, end); + + return 1; + +fail: + uri_free(uri); + return -1; +} + +static struct proxy_node *proxy_node_new(const char *proxystr, const char *end) { + int i; + + for (i = 0; ProxyBackends[i] != NULL; i++) { + const struct proxy_spec *pspec; + size_t prefix_len; + + pspec = ProxyBackends[i]; + prefix_len = strlen(pspec->prefix); + if (end - proxystr > prefix_len && strncasecmp(proxystr, pspec->prefix, prefix_len) == 0) { + struct proxy_node *proxy = NULL; + struct uri uri; + + memset(&uri, 0x00, sizeof(struct uri)); + + if (parse_uri(proxystr, end, &uri) < 0) + break; + + if (pspec->ops->node_new(&proxy, &uri) < 0) { + nsock_log_error("Cannot initialize proxy node %s", proxystr); + uri_free(&uri); + break; + } + + uri_free(&uri); + + return proxy; + } + } + nsock_log_error("Invalid protocol in proxy specification string: %s", proxystr); + return NULL; +} + +void forward_event(nsock_pool nspool, nsock_event nsevent, void *udata) { + struct npool *nsp = (struct npool *)nspool; + struct nevent *nse = (struct nevent *)nsevent; + enum nse_type cached_type; + enum nse_status cached_status; + + cached_type = nse->type; + cached_status = nse->status; + + nse->type = nse->iod->px_ctx->target_ev_type; + + if (nse->status != NSE_STATUS_SUCCESS) + nse->status = NSE_STATUS_PROXYERROR; + + nsock_log_info("Forwarding event upstream: TCP connect %s (IOD #%li) EID %li", + nse_status2str(nse->status), nse->iod->id, nse->id); + + nse->iod->px_ctx->target_handler(nsp, nse, udata); + + nse->type = cached_type; + nse->status = cached_status; +} + +void nsock_proxy_ev_dispatch(nsock_pool nspool, nsock_event nsevent, void *udata) { + struct nevent *nse = (struct nevent *)nsevent; + + if (nse->status == NSE_STATUS_SUCCESS) { + struct proxy_node *current; + + current = nse->iod->px_ctx->px_current; + assert(current); + current->spec->ops->handler(nspool, nsevent, udata); + } else { + forward_event(nspool, nsevent, udata); + } +} + +int proxy_resolve(const char *host, struct sockaddr *addr, size_t *addrlen, int ai_family) { + struct addrinfo hints; + struct addrinfo *res; + int rc; + + memset(&hints, 0, sizeof(hints)); + hints.ai_family = ai_family; + /* All proxy types are TCP-only at the moment */ + hints.ai_socktype = SOCK_STREAM; + + rc = getaddrinfo(host, NULL, &hints, &res); + if (rc) { + nsock_log_info("getaddrinfo error: %s", gai_strerror(rc)); + return -abs(rc); + } + + *addr = *res->ai_addr; + *addrlen = res->ai_addrlen; + freeaddrinfo(res); + return 1; +} + diff --git a/nsock/src/nsock_proxy.h b/nsock/src/nsock_proxy.h new file mode 100644 index 0000000..57d8b12 --- /dev/null +++ b/nsock/src/nsock_proxy.h @@ -0,0 +1,176 @@ +/*************************************************************************** + * nsock_proxy.h -- PRIVATE interface definitions for proxy handling. * + * * + ***********************IMPORTANT NSOCK LICENSE TERMS*********************** + * + * The nsock parallel socket event library is (C) 1999-2023 Nmap Software LLC + * This library is free software; you may redistribute and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation; Version 2. This guarantees your right to use, modify, and + * redistribute this software under certain conditions. If this license is + * unacceptable to you, Nmap Software LLC may be willing to sell alternative + * licenses (contact sales@nmap.com ). + * + * As a special exception to the GPL terms, Nmap Software LLC grants permission + * to link the code of this program with any version of the OpenSSL library + * which is distributed under a license identical to that listed in the included + * docs/licenses/OpenSSL.txt file, and distribute linked combinations including + * the two. You must obey the GNU GPL in all respects for all of the code used + * other than OpenSSL. If you modify this file, you may extend this exception to + * your version of the file, but you are not obligated to do so. + * + * If you received these files with a written license agreement stating terms + * other than the (GPL) terms above, then that alternative license agreement + * takes precedence over this comment. + * + * Source is provided to this software because we believe users have a right to + * know exactly what a program is going to do before they run it. This also + * allows you to audit the software for security holes. + * + * Source code also allows you to port Nmap to new platforms, fix bugs, and add + * new features. You are highly encouraged to send your changes to the + * dev@nmap.org mailing list for possible incorporation into the main + * distribution. By sending these changes to Fyodor or one of the Insecure.Org + * development mailing lists, or checking them into the Nmap source code + * repository, it is understood (unless you specify otherwise) that you are + * offering the Nmap Project (Nmap Software LLC) the unlimited, non-exclusive + * right to reuse, modify, and relicense the code. Nmap will always be available + * Open Source, but this is important because the inability to relicense code + * has caused devastating problems for other Free Software projects (such as KDE + * and NASM). We also occasionally relicense the code to third parties as + * discussed above. If you wish to specify special license conditions of your + * contributions, just say so when you send them. + * + * 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 v2.0 for more + * details (http://www.gnu.org/licenses/gpl-2.0.html). + * + ***************************************************************************/ + +/* $Id$ */ + +#ifndef NSOCK_PROXY_H +#define NSOCK_PROXY_H + +#include "gh_list.h" + +#if HAVE_NETDB_H +#include <netdb.h> +#endif + +#include <nsock.h> +#include <errno.h> + + +/* ------------------- CONSTANTS ------------------- */ +enum nsock_proxy_type { + PROXY_TYPE_HTTP = 0, + PROXY_TYPE_SOCKS4, + PROXY_TYPE_COUNT, +}; + +enum nsock_proxy_state { + /* Common initial state for all proxy types. */ + PROXY_STATE_INITIAL, + + /* HTTP proxy states. */ + PROXY_STATE_HTTP_TCP_CONNECTED, + PROXY_STATE_HTTP_TUNNEL_ESTABLISHED, + + /* SOCKS 4 proxy states. */ + PROXY_STATE_SOCKS4_TCP_CONNECTED, + PROXY_STATE_SOCKS4_TUNNEL_ESTABLISHED, +}; + + +/* ------------------- STRUCTURES ------------------- */ + +struct uri { + char *scheme; + char *user; + char *pass; + char *host; + char *path; + int port; +}; + +/* Static information about a proxy node in the chain. This is generated by + * parsing the proxy specification string given by user. Those structures are + * then read-only and stored in the nsock_pool. */ +struct proxy_node { + const struct proxy_spec *spec; + + struct sockaddr_storage ss; + size_t sslen; + unsigned short port; + char *nodestr; /* used for log messages */ + gh_lnode_t nodeq; +}; + +/* Ordered list of proxy nodes, as specified in the proxy specification string. */ +struct proxy_chain { + gh_list_t nodes; +}; + +/* IOD-specific context. For each IOD we establish a tunnel through the chain of + * proxies. This structure stores all the related information. */ +struct proxy_chain_context { + const struct proxy_chain *px_chain; + + /* Nodes iterator in px_chain->nodes */ + struct proxy_node *px_current; + + /* Current node connection state. */ + enum nsock_proxy_state px_state; + + /* Those fields are used to store information about the final target + * to reach. */ + enum nse_type target_ev_type; + struct sockaddr_storage target_ss; + size_t target_sslen; + unsigned short target_port; + nsock_ev_handler target_handler; +}; + +struct proxy_op { + int (*node_new)(struct proxy_node **node, const struct uri *uri); + void (*node_delete)(struct proxy_node *node); + void (*handler)(nsock_pool nspool, nsock_event nsevent, void *udata); +}; + +struct proxy_spec { + const char *prefix; + enum nsock_proxy_type type; + const struct proxy_op *ops; +}; + + +/* ------------------- UTIL FUNCTIONS ------------------- */ +int proxy_resolve(const char *host, struct sockaddr *addr, size_t *addrlen, int ai_family); + +static inline struct proxy_node *proxy_ctx_node_next(struct proxy_chain_context *ctx) { + gh_lnode_t *next; + + assert(ctx); + assert(ctx->px_current); + + next = gh_lnode_next(&ctx->px_current->nodeq); + if (!next) + return NULL; + + return container_of(next, struct proxy_node, nodeq); +} + + +/* ------------------- PROTOTYPES ------------------- */ + +struct proxy_chain_context *proxy_chain_context_new(nsock_pool nspool); +void proxy_chain_context_delete(struct proxy_chain_context *ctx); + +void nsock_proxy_ev_dispatch(nsock_pool nspool, nsock_event nsevent, void *udata); +void forward_event(nsock_pool nspool, nsock_event nse, void *udata); + + +#endif /* NSOCK_PROXY_H */ + diff --git a/nsock/src/nsock_read.c b/nsock/src/nsock_read.c new file mode 100644 index 0000000..27f874f --- /dev/null +++ b/nsock/src/nsock_read.c @@ -0,0 +1,130 @@ +/*************************************************************************** + * nsock_read.c -- This contains the functions for requesting various read * + * events from the nsock parallel socket event library * + * * + ***********************IMPORTANT NSOCK LICENSE TERMS*********************** + * + * The nsock parallel socket event library is (C) 1999-2023 Nmap Software LLC + * This library is free software; you may redistribute and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation; Version 2. This guarantees your right to use, modify, and + * redistribute this software under certain conditions. If this license is + * unacceptable to you, Nmap Software LLC may be willing to sell alternative + * licenses (contact sales@nmap.com ). + * + * As a special exception to the GPL terms, Nmap Software LLC grants permission + * to link the code of this program with any version of the OpenSSL library + * which is distributed under a license identical to that listed in the included + * docs/licenses/OpenSSL.txt file, and distribute linked combinations including + * the two. You must obey the GNU GPL in all respects for all of the code used + * other than OpenSSL. If you modify this file, you may extend this exception to + * your version of the file, but you are not obligated to do so. + * + * If you received these files with a written license agreement stating terms + * other than the (GPL) terms above, then that alternative license agreement + * takes precedence over this comment. + * + * Source is provided to this software because we believe users have a right to + * know exactly what a program is going to do before they run it. This also + * allows you to audit the software for security holes. + * + * Source code also allows you to port Nmap to new platforms, fix bugs, and add + * new features. You are highly encouraged to send your changes to the + * dev@nmap.org mailing list for possible incorporation into the main + * distribution. By sending these changes to Fyodor or one of the Insecure.Org + * development mailing lists, or checking them into the Nmap source code + * repository, it is understood (unless you specify otherwise) that you are + * offering the Nmap Project (Nmap Software LLC) the unlimited, non-exclusive + * right to reuse, modify, and relicense the code. Nmap will always be available + * Open Source, but this is important because the inability to relicense code + * has caused devastating problems for other Free Software projects (such as KDE + * and NASM). We also occasionally relicense the code to third parties as + * discussed above. If you wish to specify special license conditions of your + * contributions, just say so when you send them. + * + * 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 v2.0 for more + * details (http://www.gnu.org/licenses/gpl-2.0.html). + * + ***************************************************************************/ + +/* $Id$ */ + +#include "nsock_internal.h" +#include "nsock_log.h" +#include "netutils.h" + + +/* Read up to nlines lines (terminated with \n, which of course includes \r\n), + * or until EOF, or until the timeout, whichever comes first. Note that + * NSE_STATUS_SUCCESS will be returned in the case of EOF or timeout if at least + * 1 char has been read. Also note that you may get more than 'nlines' back -- + * we just stop once "at least" 'nlines' is read */ +nsock_event_id nsock_readlines(nsock_pool nsp, nsock_iod ms_iod, + nsock_ev_handler handler, int timeout_msecs, + void *userdata, int nlines) { + struct niod *nsi = (struct niod *)ms_iod; + struct npool *ms = (struct npool *)nsp; + struct nevent *nse; + + nse = event_new(ms, NSE_TYPE_READ, nsi, timeout_msecs, handler, userdata); + assert(nse); + + nsock_log_info("Read request for %d lines from IOD #%li [%s] EID %li", + nlines, nsi->id, get_peeraddr_string(nsi), nse->id); + + nse->readinfo.read_type = NSOCK_READLINES; + nse->readinfo.num = nlines; + + nsock_pool_add_event(ms, nse); + + return nse->id; +} + +/* Same as above, except it tries to read at least 'nbytes' instead of 'nlines'. */ +nsock_event_id nsock_readbytes(nsock_pool nsp, nsock_iod ms_iod, + nsock_ev_handler handler, int timeout_msecs, + void *userdata, int nbytes) { + + struct niod *nsi = (struct niod *)ms_iod; + struct npool *ms = (struct npool *)nsp; + struct nevent *nse; + + nse = event_new(ms, NSE_TYPE_READ, nsi, timeout_msecs, handler, userdata); + assert(nse); + + nsock_log_info("Read request for %d bytes from IOD #%li [%s] EID %li", + nbytes, nsi->id, get_peeraddr_string(nsi), nse->id); + + nse->readinfo.read_type = NSOCK_READBYTES; + nse->readinfo.num = nbytes; + + nsock_pool_add_event(ms, nse); + + return nse->id; +} + + +/* The simplest read function -- returns NSE_STATUS_SUCCESS when it + * reads anything, otherwise it returns timeout, eof, or error as appropriate */ +nsock_event_id nsock_read(nsock_pool nsp, nsock_iod ms_iod, + nsock_ev_handler handler, int timeout_msecs, + void *userdata) { + struct niod *nsi = (struct niod *)ms_iod; + struct npool *ms = (struct npool *)nsp; + struct nevent *nse; + + nse = event_new(ms, NSE_TYPE_READ, nsi, timeout_msecs, handler, userdata); + assert(nse); + + nsock_log_info("Read request from IOD #%li [%s] (timeout: %dms) EID %li", + nsi->id, get_peeraddr_string(nsi), timeout_msecs, nse->id); + + nse->readinfo.read_type = NSOCK_READ; + + nsock_pool_add_event(ms, nse); + + return nse->id; +} + diff --git a/nsock/src/nsock_ssl.c b/nsock/src/nsock_ssl.c new file mode 100644 index 0000000..096ce72 --- /dev/null +++ b/nsock/src/nsock_ssl.c @@ -0,0 +1,278 @@ +/*************************************************************************** + * nsock_ssl.c -- This contains functions that relate somewhat exclusively * + * to SSL (over TCP) support in nsock. Where SSL support is incidental, * + * it is often in other files where code can be more easily shared between * + * the SSL and NonSSL paths. * + * * + ***********************IMPORTANT NSOCK LICENSE TERMS*********************** + * + * The nsock parallel socket event library is (C) 1999-2023 Nmap Software LLC + * This library is free software; you may redistribute and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation; Version 2. This guarantees your right to use, modify, and + * redistribute this software under certain conditions. If this license is + * unacceptable to you, Nmap Software LLC may be willing to sell alternative + * licenses (contact sales@nmap.com ). + * + * As a special exception to the GPL terms, Nmap Software LLC grants permission + * to link the code of this program with any version of the OpenSSL library + * which is distributed under a license identical to that listed in the included + * docs/licenses/OpenSSL.txt file, and distribute linked combinations including + * the two. You must obey the GNU GPL in all respects for all of the code used + * other than OpenSSL. If you modify this file, you may extend this exception to + * your version of the file, but you are not obligated to do so. + * + * If you received these files with a written license agreement stating terms + * other than the (GPL) terms above, then that alternative license agreement + * takes precedence over this comment. + * + * Source is provided to this software because we believe users have a right to + * know exactly what a program is going to do before they run it. This also + * allows you to audit the software for security holes. + * + * Source code also allows you to port Nmap to new platforms, fix bugs, and add + * new features. You are highly encouraged to send your changes to the + * dev@nmap.org mailing list for possible incorporation into the main + * distribution. By sending these changes to Fyodor or one of the Insecure.Org + * development mailing lists, or checking them into the Nmap source code + * repository, it is understood (unless you specify otherwise) that you are + * offering the Nmap Project (Nmap Software LLC) the unlimited, non-exclusive + * right to reuse, modify, and relicense the code. Nmap will always be available + * Open Source, but this is important because the inability to relicense code + * has caused devastating problems for other Free Software projects (such as KDE + * and NASM). We also occasionally relicense the code to third parties as + * discussed above. If you wish to specify special license conditions of your + * contributions, just say so when you send them. + * + * 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 v2.0 for more + * details (http://www.gnu.org/licenses/gpl-2.0.html). + * + ***************************************************************************/ + +/* $Id$ */ + + +#include "nsock.h" +#include "nsock_internal.h" +#include "nsock_log.h" +#include "nsock_ssl.h" +#include "netutils.h" + +#if HAVE_OPENSSL +#if OPENSSL_VERSION_NUMBER >= 0x30000000L +#include <openssl/provider.h> +#endif + +/* Disallow anonymous ciphers (Diffie-Hellman key agreement), low bit-strength + * ciphers, export-crippled ciphers, and MD5. Prefer ciphers in decreasing order + * of key size. The cipher list is taken from the book Network Security with + * OpenSSL. To see exactly what ciphers are enabled, use the command + * openssl ciphers -v '...' + * where ... is the string below. */ +#define CIPHERS_SECURE "ALL:!aNULL:!eNULL:!LOW:!EXP:!RC4:!MD5:@STRENGTH" + +/* This list of ciphers is for speed and compatibility, not security. Any cipher + * is accepted, and the list is sorted by speed based on Brian Hatch's + * (bri@ifokr.org) tests on an Pentium 686 against the ciphers listed. */ +#define CIPHERS_FAST "RC4-SHA:RC4-MD5:NULL-SHA:EXP-DES-CBC-SHA:EXP-EDH-RSA-DES-CBC-SHA:EXP-RC4-MD5:NULL-MD5:EDH-RSA-DES-CBC-SHA:EXP-RC2-CBC-MD5:EDH-RSA-DES-CBC3-SHA:EXP-ADH-RC4-MD5:DHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA:EXP-ADH-DES-CBC-SHA:ADH-AES256-SHA:ADH-DES-CBC-SHA:ADH-RC4-MD5:AES256-SHA:DES-CBC-SHA:DES-CBC3-SHA:ADH-DES-CBC3-SHA:AES128-SHA:ADH-AES128-SHA:eNULL:ALL" + +extern struct timeval nsock_tod; +#define NSOCK_SSL_STATE_UNINITIALIZED -1 +#define NSOCK_SSL_STATE_INITIALIZED 1 +#define NSOCK_SSL_STATE_ATEXIT 0 +static int nsock_ssl_state = NSOCK_SSL_STATE_UNINITIALIZED; +#if OPENSSL_VERSION_NUMBER >= 0x10100000L && !defined LIBRESSL_VERSION_NUMBER +static void nsock_ssl_atexit(void) +{ + nsock_ssl_state = NSOCK_SSL_STATE_ATEXIT; +} +#endif +void nsp_ssl_cleanup(struct npool *nsp) +{ + if (nsock_ssl_state != NSOCK_SSL_STATE_ATEXIT) + { + if (nsp->sslctx != NULL) + SSL_CTX_free(nsp->sslctx); +#ifdef HAVE_DTLS_CLIENT_METHOD + if (nsp->dtlsctx != NULL) + SSL_CTX_free(nsp->dtlsctx); +#endif + } + nsp->sslctx = NULL; +#ifdef HAVE_DTLS_CLIENT_METHOD + nsp->dtlsctx = NULL; +#endif +} + +static SSL_CTX *ssl_init_helper(const SSL_METHOD *method) { + SSL_CTX *ctx; + + if (nsock_ssl_state == NSOCK_SSL_STATE_UNINITIALIZED) + { + nsock_ssl_state = NSOCK_SSL_STATE_INITIALIZED; +#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined LIBRESSL_VERSION_NUMBER + SSL_load_error_strings(); + SSL_library_init(); +#else + OPENSSL_atexit(nsock_ssl_atexit); +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + if (NULL == OSSL_PROVIDER_load(NULL, "legacy")) + { + nsock_log_info("OpenSSL legacy provider failed to load: %s", + ERR_error_string(ERR_get_error(), NULL)); + } + if (NULL == OSSL_PROVIDER_load(NULL, "default")) + { + nsock_log_error("OpenSSL default provider failed to load: %s", + ERR_error_string(ERR_get_error(), NULL)); + } +#endif +#endif + } + + ctx = SSL_CTX_new(method); + if (!ctx) { + fatal("OpenSSL failed to create a new SSL_CTX: %s", + ERR_error_string(ERR_get_error(), NULL)); + } + + /* Our SSL* will always have the SSL_SESSION* inside it, so we neither need to + * use nor waste memory for the session cache. (Use '1' because '0' means + * 'infinite'.) */ + SSL_CTX_set_session_cache_mode(ctx, SSL_SESS_CACHE_OFF|SSL_SESS_CACHE_NO_AUTO_CLEAR); + SSL_CTX_sess_set_cache_size(ctx, 1); + SSL_CTX_set_timeout(ctx, 3600); /* pretty unnecessary */ + + return ctx; +} + +/* Create an SSL_CTX and do initialization that is common to all init modes. */ +static SSL_CTX *ssl_init_common() { + return ssl_init_helper(SSLv23_client_method()); +} + +/* Initializes an Nsock pool to create SSL connections. This sets an internal + * SSL_CTX, which is like a template that sets options for all connections that + * are made from it. The connections made from this context will use only secure + * ciphers but no server certificate verification is done. Returns the SSL_CTX + * so you can set your own options. */ +static nsock_ssl_ctx nsock_pool_ssl_init_helper(SSL_CTX *ctx, int flags) { + char rndbuf[128]; + + /* Get_random_bytes may or may not provide high-quality randomness. Add it to + * the entropy pool without increasing the entropy estimate (third argument of + * RAND_add is 0). We rely on OpenSSL's entropy gathering, called implicitly + * by RAND_status, to give us what we need, or else bail out if it fails. */ + get_random_bytes(rndbuf, sizeof(rndbuf)); + RAND_add(rndbuf, sizeof(rndbuf), 0); + + if (!(flags & NSOCK_SSL_MAX_SPEED)) { + if (!RAND_status()) + fatal("%s: Failed to seed OpenSSL PRNG" + " (RAND_status returned false).", __func__); + } + + /* SSL_OP_ALL sets bug-compatibility for pretty much everything. + * SSL_OP_NO_SSLv2 disables the less-secure SSLv2 while allowing us to use the + * SSLv2-compatible SSLv23_client_method. */ + SSL_CTX_set_verify(ctx, SSL_VERIFY_NONE, NULL); + SSL_CTX_clear_options(ctx, SSL_OP_NO_SSLv2); + SSL_CTX_set_options(ctx, flags & NSOCK_SSL_MAX_SPEED ? + SSL_OP_ALL : SSL_OP_ALL|SSL_OP_NO_SSLv2); + + if (!SSL_CTX_set_cipher_list(ctx, flags & NSOCK_SSL_MAX_SPEED ? + CIPHERS_FAST : CIPHERS_SECURE)) + fatal("Unable to set OpenSSL cipher list: %s", + ERR_error_string(ERR_get_error(), NULL)); + + return ctx; +} + +nsock_ssl_ctx nsock_pool_ssl_init(nsock_pool ms_pool, int flags) { + struct npool *ms = (struct npool *)ms_pool; + + if (ms->sslctx == NULL) + ms->sslctx = ssl_init_common(); + return nsock_pool_ssl_init_helper(ms->sslctx, flags); +} + +#ifdef HAVE_DTLS_CLIENT_METHOD + +/* Create an SSL_CTX and do initialisation, creating a DTLS client */ +static SSL_CTX *dtls_init_common() { + return ssl_init_helper(DTLS_client_method()); +} + +/* Initializes an Nsock pool to create DTLS connections. Very much similar to + * nsock_pool_ssl_init, just with DTLS. */ +nsock_ssl_ctx nsock_pool_dtls_init(nsock_pool ms_pool, int flags) { + SSL_CTX *dtls_ctx = NULL; + struct npool *ms = (struct npool *)ms_pool; + + if (ms->dtlsctx == NULL) + ms->dtlsctx = dtls_init_common(); + dtls_ctx = (SSL_CTX *) nsock_pool_ssl_init_helper(ms->dtlsctx, flags); + + /* Don't add padding or the ClientHello will fragment and not connect properly. */ + SSL_CTX_clear_options(dtls_ctx, SSL_OP_TLSEXT_PADDING); + + if (!SSL_CTX_set_cipher_list(dtls_ctx, "DEFAULT")) + fatal("Unable to set OpenSSL cipher list: %s", + ERR_error_string(ERR_get_error(), NULL)); + + return dtls_ctx; +} + +#else /* OpenSSL Version does not support DTLS */ + +nsock_ssl_ctx nsock_pool_dtls_init(nsock_pool ms_pool, int flags) { + fatal("%s called with no OpenSSL DTLS support", __func__); +} + +#endif + +/* Check server certificate verification, after a connection is established. We + * check first that a certificate was even offered, then call + * SSL_get_verify_result to get the overall status of verification. (Just + * calling SSL_get_verify_result is not enough because that function returns + * X509_V_OK when 0 certificates are presented.) If the verification mode of the + * SSL object is SSL_VERIFY_NONE, or if OpenSSL is disabled, this function + * always returns true. */ +int nsi_ssl_post_connect_verify(const nsock_iod nsockiod) { + struct niod *iod = (struct niod *)nsockiod; + + assert(iod->ssl != NULL); + if (SSL_get_verify_mode(iod->ssl) != SSL_VERIFY_NONE) { + X509 *cert; + + cert = SSL_get_peer_certificate(iod->ssl); + if (cert == NULL) + /* No certificate presented. */ + return 0; + + X509_free(cert); + + if (SSL_get_verify_result(iod->ssl) != X509_V_OK) + /* Something wrong with verification. */ + return 0; + } + return 1; +} + +#else /* NOT HAVE_OPENSSL */ + +nsock_ssl_ctx nsock_pool_ssl_init(nsock_pool ms_pool, int flags) { + fatal("%s called with no OpenSSL support", __func__); +} + +nsock_ssl_ctx nsock_pool_dtls_init(nsock_pool ms_pool, int flags) { + fatal("%s called with no OpenSSL support", __func__); +} + +int nsi_ssl_post_connect_verify(const nsock_iod nsockiod) { + return 1; +} + +#endif diff --git a/nsock/src/nsock_ssl.h b/nsock/src/nsock_ssl.h new file mode 100644 index 0000000..f23f615 --- /dev/null +++ b/nsock/src/nsock_ssl.h @@ -0,0 +1,85 @@ +/*************************************************************************** + * nsock_ssl.c -- This contains functions that relate somewhat exclusively * + * to SSL (over TCP) support in nsock. Where SSL support is incidental, * + * it is often in other files where code can be more easily shared between * + * the SSL and NonSSL paths. * + * * + ***********************IMPORTANT NSOCK LICENSE TERMS*********************** + * + * The nsock parallel socket event library is (C) 1999-2023 Nmap Software LLC + * This library is free software; you may redistribute and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation; Version 2. This guarantees your right to use, modify, and + * redistribute this software under certain conditions. If this license is + * unacceptable to you, Nmap Software LLC may be willing to sell alternative + * licenses (contact sales@nmap.com ). + * + * As a special exception to the GPL terms, Nmap Software LLC grants permission + * to link the code of this program with any version of the OpenSSL library + * which is distributed under a license identical to that listed in the included + * docs/licenses/OpenSSL.txt file, and distribute linked combinations including + * the two. You must obey the GNU GPL in all respects for all of the code used + * other than OpenSSL. If you modify this file, you may extend this exception to + * your version of the file, but you are not obligated to do so. + * + * If you received these files with a written license agreement stating terms + * other than the (GPL) terms above, then that alternative license agreement + * takes precedence over this comment. + * + * Source is provided to this software because we believe users have a right to + * know exactly what a program is going to do before they run it. This also + * allows you to audit the software for security holes. + * + * Source code also allows you to port Nmap to new platforms, fix bugs, and add + * new features. You are highly encouraged to send your changes to the + * dev@nmap.org mailing list for possible incorporation into the main + * distribution. By sending these changes to Fyodor or one of the Insecure.Org + * development mailing lists, or checking them into the Nmap source code + * repository, it is understood (unless you specify otherwise) that you are + * offering the Nmap Project (Nmap Software LLC) the unlimited, non-exclusive + * right to reuse, modify, and relicense the code. Nmap will always be available + * Open Source, but this is important because the inability to relicense code + * has caused devastating problems for other Free Software projects (such as KDE + * and NASM). We also occasionally relicense the code to third parties as + * discussed above. If you wish to specify special license conditions of your + * contributions, just say so when you send them. + * + * 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 v2.0 for more + * details (http://www.gnu.org/licenses/gpl-2.0.html). + * + ***************************************************************************/ + +/* $Id$ */ + +#ifndef NSOCK_SSL_H +#define NSOCK_SSL_H + +#ifdef HAVE_CONFIG_H +#include "nsock_config.h" +#endif +#include "nsock_internal.h" + +#if HAVE_OPENSSL +#include <openssl/ssl.h> +#include <openssl/err.h> +#include <openssl/rand.h> + +#if OPENSSL_VERSION_NUMBER >= 0x30000000L +/* Deprecated in OpenSSL 3.0 */ +#define SSL_get_peer_certificate SSL_get1_peer_certificate +#endif + +struct sslinfo { + /* SSL_ERROR_NONE, SSL_ERROR_WANT_CONNECT, SSL_ERROR_WANT_READ, or + * SSL_ERROR_WANT_WRITE */ + int ssl_desire; +}; + +int nsi_ssl_post_connect_verify(const nsock_iod nsockiod); + +void nsp_ssl_cleanup(struct npool *nsp); +#endif /* HAVE_OPENSSL */ +#endif /* NSOCK_SSL_H */ + diff --git a/nsock/src/nsock_timers.c b/nsock/src/nsock_timers.c new file mode 100644 index 0000000..c36fd0b --- /dev/null +++ b/nsock/src/nsock_timers.c @@ -0,0 +1,76 @@ +/*************************************************************************** + * nsock_timers.c -- This contains the functions for requesting timers * + * from the nsock parallel socket event library * + * * + ***********************IMPORTANT NSOCK LICENSE TERMS*********************** + * + * The nsock parallel socket event library is (C) 1999-2023 Nmap Software LLC + * This library is free software; you may redistribute and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation; Version 2. This guarantees your right to use, modify, and + * redistribute this software under certain conditions. If this license is + * unacceptable to you, Nmap Software LLC may be willing to sell alternative + * licenses (contact sales@nmap.com ). + * + * As a special exception to the GPL terms, Nmap Software LLC grants permission + * to link the code of this program with any version of the OpenSSL library + * which is distributed under a license identical to that listed in the included + * docs/licenses/OpenSSL.txt file, and distribute linked combinations including + * the two. You must obey the GNU GPL in all respects for all of the code used + * other than OpenSSL. If you modify this file, you may extend this exception to + * your version of the file, but you are not obligated to do so. + * + * If you received these files with a written license agreement stating terms + * other than the (GPL) terms above, then that alternative license agreement + * takes precedence over this comment. + * + * Source is provided to this software because we believe users have a right to + * know exactly what a program is going to do before they run it. This also + * allows you to audit the software for security holes. + * + * Source code also allows you to port Nmap to new platforms, fix bugs, and add + * new features. You are highly encouraged to send your changes to the + * dev@nmap.org mailing list for possible incorporation into the main + * distribution. By sending these changes to Fyodor or one of the Insecure.Org + * development mailing lists, or checking them into the Nmap source code + * repository, it is understood (unless you specify otherwise) that you are + * offering the Nmap Project (Nmap Software LLC) the unlimited, non-exclusive + * right to reuse, modify, and relicense the code. Nmap will always be available + * Open Source, but this is important because the inability to relicense code + * has caused devastating problems for other Free Software projects (such as KDE + * and NASM). We also occasionally relicense the code to third parties as + * discussed above. If you wish to specify special license conditions of your + * contributions, just say so when you send them. + * + * 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 v2.0 for more + * details (http://www.gnu.org/licenses/gpl-2.0.html). + * + ***************************************************************************/ + +/* $Id$ */ + +#include "nsock_internal.h" +#include "nsock_log.h" + +extern struct timeval nsock_tod; + +/* Send back an NSE_TYPE_TIMER after the number of milliseconds specified. Of + * course it can also return due to error, cancellation, etc. */ +nsock_event_id nsock_timer_create(nsock_pool ms_pool, nsock_ev_handler handler, + int timeout_msecs, void *userdata) { + struct npool *nsp = (struct npool *)ms_pool; + struct nevent *nse; + + nse = event_new(nsp, NSE_TYPE_TIMER, NULL, timeout_msecs, handler, userdata); + assert(nse); + + nsock_log_info("Timer created - %dms from now. EID %li", timeout_msecs, + nse->id); + + nsock_pool_add_event(nsp, nse); + + return nse->id; +} + diff --git a/nsock/src/nsock_write.c b/nsock/src/nsock_write.c new file mode 100644 index 0000000..03b82b8 --- /dev/null +++ b/nsock/src/nsock_write.c @@ -0,0 +1,236 @@ +/*************************************************************************** + * nsock_write.c -- This contains the functions relating to writing to * + * sockets using the nsock parallel socket event library * + * * + ***********************IMPORTANT NSOCK LICENSE TERMS*********************** + * + * The nsock parallel socket event library is (C) 1999-2023 Nmap Software LLC + * This library is free software; you may redistribute and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation; Version 2. This guarantees your right to use, modify, and + * redistribute this software under certain conditions. If this license is + * unacceptable to you, Nmap Software LLC may be willing to sell alternative + * licenses (contact sales@nmap.com ). + * + * As a special exception to the GPL terms, Nmap Software LLC grants permission + * to link the code of this program with any version of the OpenSSL library + * which is distributed under a license identical to that listed in the included + * docs/licenses/OpenSSL.txt file, and distribute linked combinations including + * the two. You must obey the GNU GPL in all respects for all of the code used + * other than OpenSSL. If you modify this file, you may extend this exception to + * your version of the file, but you are not obligated to do so. + * + * If you received these files with a written license agreement stating terms + * other than the (GPL) terms above, then that alternative license agreement + * takes precedence over this comment. + * + * Source is provided to this software because we believe users have a right to + * know exactly what a program is going to do before they run it. This also + * allows you to audit the software for security holes. + * + * Source code also allows you to port Nmap to new platforms, fix bugs, and add + * new features. You are highly encouraged to send your changes to the + * dev@nmap.org mailing list for possible incorporation into the main + * distribution. By sending these changes to Fyodor or one of the Insecure.Org + * development mailing lists, or checking them into the Nmap source code + * repository, it is understood (unless you specify otherwise) that you are + * offering the Nmap Project (Nmap Software LLC) the unlimited, non-exclusive + * right to reuse, modify, and relicense the code. Nmap will always be available + * Open Source, but this is important because the inability to relicense code + * has caused devastating problems for other Free Software projects (such as KDE + * and NASM). We also occasionally relicense the code to third parties as + * discussed above. If you wish to specify special license conditions of your + * contributions, just say so when you send them. + * + * 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 v2.0 for more + * details (http://www.gnu.org/licenses/gpl-2.0.html). + * + ***************************************************************************/ + +/* $Id$ */ + +#include "nsock.h" +#include "nsock_internal.h" +#include "nsock_log.h" +#include "netutils.h" + +#include <nbase.h> +#include <stdarg.h> +#include <errno.h> + +nsock_event_id nsock_sendto(nsock_pool ms_pool, nsock_iod ms_iod, nsock_ev_handler handler, int timeout_msecs, + void *userdata, struct sockaddr *saddr, size_t sslen, unsigned short port, const char *data, int datalen) { + struct npool *nsp = (struct npool *)ms_pool; + struct niod *nsi = (struct niod *)ms_iod; + struct nevent *nse; + char displaystr[256]; + struct sockaddr_in *sin = (struct sockaddr_in *)saddr; +#if HAVE_IPV6 + struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)saddr; +#endif + + nse = event_new(nsp, NSE_TYPE_WRITE, nsi, timeout_msecs, handler, userdata); + assert(nse); + + if (saddr->sa_family == AF_INET) { + sin->sin_port = htons(port); +#if HAVE_SYS_UN_H + } else if (saddr->sa_family == AF_INET6) { +#else + } else { +#endif + assert(saddr->sa_family == AF_INET6); +#if HAVE_IPV6 + sin6->sin6_port = htons(port); +#else + fatal("IPv6 address passed to %s call, but nsock was not compiled w/IPv6 support", __func__); +#endif + } + + assert(sslen <= sizeof(nse->writeinfo.dest)); + memcpy(&nse->writeinfo.dest, saddr, sslen); + nse->writeinfo.destlen = sslen; + + assert(sslen <= sizeof(nse->iod->peer)); + memcpy(&nse->iod->peer, saddr, sslen); + nse->iod->peerlen = sslen; + + if (datalen < 0) + datalen = (int) strlen(data); + + if (NsockLogLevel == NSOCK_LOG_DBG_ALL && datalen < 80) { + memcpy(displaystr, ": ", 2); + memcpy(displaystr + 2, data, datalen); + displaystr[2 + datalen] = '\0'; + replacenonprintable(displaystr + 2, datalen, '.'); + } else { + displaystr[0] = '\0'; + } + nsock_log_info("Sendto request for %d bytes to IOD #%li EID %li [%s]%s", + datalen, nsi->id, nse->id, get_peeraddr_string(nse->iod), + displaystr); + + fs_cat(&nse->iobuf, data, datalen); + + nsock_pool_add_event(nsp, nse); + + return nse->id; +} + +/* Write some data to the socket. If the write is not COMPLETED within + * timeout_msecs , NSE_STATUS_TIMEOUT will be returned. If you are supplying + * NUL-terminated data, you can optionally pass -1 for datalen and nsock_write + * will figure out the length itself */ +nsock_event_id nsock_write(nsock_pool ms_pool, nsock_iod ms_iod, + nsock_ev_handler handler, int timeout_msecs, void *userdata, const char *data, int datalen) { + struct npool *nsp = (struct npool *)ms_pool; + struct niod *nsi = (struct niod *)ms_iod; + struct nevent *nse; + char displaystr[256]; + + nse = event_new(nsp, NSE_TYPE_WRITE, nsi, timeout_msecs, handler, userdata); + assert(nse); + + nse->writeinfo.dest.ss_family = AF_UNSPEC; + + if (datalen < 0) + datalen = (int)strlen(data); + + if (NsockLogLevel == NSOCK_LOG_DBG_ALL && datalen < 80) { + memcpy(displaystr, ": ", 2); + memcpy(displaystr + 2, data, datalen); + displaystr[2 + datalen] = '\0'; + replacenonprintable(displaystr + 2, datalen, '.'); + } else { + displaystr[0] = '\0'; + } + + nsock_log_info("Write request for %d bytes to IOD #%li EID %li [%s]%s", + datalen, nsi->id, nse->id, get_peeraddr_string(nsi), + displaystr); + + fs_cat(&nse->iobuf, data, datalen); + + nsock_pool_add_event(nsp, nse); + + return nse->id; +} + +/* Same as nsock_write except you can use a printf-style format and you can only use this for ASCII strings */ +nsock_event_id nsock_printf(nsock_pool ms_pool, nsock_iod ms_iod, + nsock_ev_handler handler, int timeout_msecs, void *userdata, char *format, ...) { + struct npool *nsp = (struct npool *)ms_pool; + struct niod *nsi = (struct niod *)ms_iod; + struct nevent *nse; + char buf[4096]; + char *buf2 = NULL; + size_t buf2size; + int res, res2; + int strlength = 0; + char displaystr[256]; + + va_list ap; + + nse = event_new(nsp, NSE_TYPE_WRITE, nsi, timeout_msecs, handler, userdata); + assert(nse); + + va_start(ap,format); + res = Vsnprintf(buf, sizeof(buf), format, ap); + va_end(ap); + + if (res >= 0) { + if (res >= sizeof(buf)) { + buf2size = res + 16; + buf2 = (char * )safe_malloc(buf2size); + va_start(ap,format); + res2 = Vsnprintf(buf2, buf2size, format, ap); + va_end(ap); + if (res2 < 0 || (size_t) res2 >= buf2size) { + free(buf2); + buf2 = NULL; + } else + strlength = res2; + } else { + buf2 = buf; + strlength = res; + } + } + + if (!buf2) { + nse->event_done = 1; + nse->status = NSE_STATUS_ERROR; + nse->errnum = EMSGSIZE; + } else { + if (strlength == 0) { + nse->event_done = 1; + nse->status = NSE_STATUS_SUCCESS; + } else { + fs_cat(&nse->iobuf, buf2, strlength); + } + } + + if (NsockLogLevel == NSOCK_LOG_DBG_ALL && + nse->status != NSE_STATUS_ERROR && + strlength < 80) { + memcpy(displaystr, ": ", 2); + memcpy(displaystr + 2, buf2, strlength); + displaystr[2 + strlength] = '\0'; + replacenonprintable(displaystr + 2, strlength, '.'); + } else { + displaystr[0] = '\0'; + } + + nsock_log_info("Write request for %d bytes to IOD #%li EID %li [%s]%s", + strlength, nsi->id, nse->id, get_peeraddr_string(nsi), + displaystr); + + if (buf2 != buf) + free(buf2); + + nsock_pool_add_event(nsp, nse); + + return nse->id; +} + diff --git a/nsock/src/proxy_http.c b/nsock/src/proxy_http.c new file mode 100644 index 0000000..a6831d4 --- /dev/null +++ b/nsock/src/proxy_http.c @@ -0,0 +1,210 @@ +/*************************************************************************** + * proxy_http.c -- HTTP Connect proxying. * + * * + ***********************IMPORTANT NSOCK LICENSE TERMS*********************** + * + * The nsock parallel socket event library is (C) 1999-2023 Nmap Software LLC + * This library is free software; you may redistribute and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation; Version 2. This guarantees your right to use, modify, and + * redistribute this software under certain conditions. If this license is + * unacceptable to you, Nmap Software LLC may be willing to sell alternative + * licenses (contact sales@nmap.com ). + * + * As a special exception to the GPL terms, Nmap Software LLC grants permission + * to link the code of this program with any version of the OpenSSL library + * which is distributed under a license identical to that listed in the included + * docs/licenses/OpenSSL.txt file, and distribute linked combinations including + * the two. You must obey the GNU GPL in all respects for all of the code used + * other than OpenSSL. If you modify this file, you may extend this exception to + * your version of the file, but you are not obligated to do so. + * + * If you received these files with a written license agreement stating terms + * other than the (GPL) terms above, then that alternative license agreement + * takes precedence over this comment. + * + * Source is provided to this software because we believe users have a right to + * know exactly what a program is going to do before they run it. This also + * allows you to audit the software for security holes. + * + * Source code also allows you to port Nmap to new platforms, fix bugs, and add + * new features. You are highly encouraged to send your changes to the + * dev@nmap.org mailing list for possible incorporation into the main + * distribution. By sending these changes to Fyodor or one of the Insecure.Org + * development mailing lists, or checking them into the Nmap source code + * repository, it is understood (unless you specify otherwise) that you are + * offering the Nmap Project (Nmap Software LLC) the unlimited, non-exclusive + * right to reuse, modify, and relicense the code. Nmap will always be available + * Open Source, but this is important because the inability to relicense code + * has caused devastating problems for other Free Software projects (such as KDE + * and NASM). We also occasionally relicense the code to third parties as + * discussed above. If you wish to specify special license conditions of your + * contributions, just say so when you send them. + * + * 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 v2.0 for more + * details (http://www.gnu.org/licenses/gpl-2.0.html). + * + ***************************************************************************/ + +/* $Id $ */ + +#define _GNU_SOURCE +#include <stdio.h> + +#include "nsock.h" +#include "nsock_internal.h" +#include "nsock_log.h" +#include <string.h> + +#define DEFAULT_PROXY_PORT_HTTP 8080 + + +extern struct timeval nsock_tod; +extern const struct proxy_spec ProxySpecHttp; + + +static int proxy_http_node_new(struct proxy_node **node, const struct uri *uri) { + int rc; + struct proxy_node *proxy; + + proxy = (struct proxy_node *)safe_zalloc(sizeof(struct proxy_node)); + proxy->spec = &ProxySpecHttp; + + rc = proxy_resolve(uri->host, (struct sockaddr *)&proxy->ss, &proxy->sslen, AF_UNSPEC); + if (rc < 0) { + free(proxy); + *node = NULL; + return -1; + } + + if (uri->port == -1) + proxy->port = DEFAULT_PROXY_PORT_HTTP; + else + proxy->port = (unsigned short)uri->port; + + rc = asprintf(&proxy->nodestr, "http://%s:%d", uri->host, proxy->port); + if (rc < 0) { + /* asprintf() failed for some reason but this is not a disaster (yet). + * Set nodestr to NULL and try to keep on going. */ + proxy->nodestr = NULL; + } + + *node = proxy; + + return 1; +} + +static void proxy_http_node_delete(struct proxy_node *node) { + if (!node) + return; + + free(node->nodestr); + + free(node); +} + +static int handle_state_initial(struct npool *nsp, struct nevent *nse, void *udata) { + struct proxy_chain_context *px_ctx = nse->iod->px_ctx; + struct sockaddr_storage *ss; + size_t sslen; + unsigned short port; + struct proxy_node *next; + int timeout; + + px_ctx->px_state = PROXY_STATE_HTTP_TCP_CONNECTED; + + next = proxy_ctx_node_next(px_ctx); + if (next) { + ss = &next->ss; + sslen = next->sslen; + port = next->port; + } else { + ss = &px_ctx->target_ss; + sslen = px_ctx->target_sslen; + port = px_ctx->target_port; + } + + timeout = TIMEVAL_MSEC_SUBTRACT(nse->timeout, nsock_tod); + + nsock_printf(nsp, (nsock_iod)nse->iod, nsock_proxy_ev_dispatch, + timeout, udata, "CONNECT %s:%d HTTP/1.1\r\n\r\n", + inet_ntop_ez(ss, sslen), (int)port); + + nsock_readlines(nsp, (nsock_iod)nse->iod, nsock_proxy_ev_dispatch, + timeout, udata, 1); + + return 0; +} + +static int handle_state_tcp_connected(struct npool *nsp, struct nevent *nse, void *udata) { + struct proxy_chain_context *px_ctx = nse->iod->px_ctx; + char *res; + int reslen; + + res = nse_readbuf(nse, &reslen); + + /* TODO string check!! */ + if (!((reslen >= 15) && strstr(res, "200 OK"))) { + struct proxy_node *node = px_ctx->px_current; + + nsock_log_debug("Connection refused from proxy %s", node->nodestr); + return -EINVAL; + } + + px_ctx->px_state = PROXY_STATE_HTTP_TUNNEL_ESTABLISHED; + + if (proxy_ctx_node_next(px_ctx) == NULL) { + forward_event(nsp, nse, udata); + } else { + px_ctx->px_current = proxy_ctx_node_next(px_ctx); + px_ctx->px_state = PROXY_STATE_INITIAL; + nsock_proxy_ev_dispatch(nsp, nse, udata); + } + return 0; +} + +static void proxy_http_handler(nsock_pool nspool, nsock_event nsevent, void *udata) { + int rc = 0; + struct npool *nsp = (struct npool *)nspool; + struct nevent *nse = (struct nevent *)nsevent; + + switch (nse->iod->px_ctx->px_state) { + case PROXY_STATE_INITIAL: + rc = handle_state_initial(nsp, nse, udata); + break; + + case PROXY_STATE_HTTP_TCP_CONNECTED: + if (nse->type == NSE_TYPE_READ) + rc = handle_state_tcp_connected(nsp, nse, udata); + break; + + case PROXY_STATE_HTTP_TUNNEL_ESTABLISHED: + forward_event(nsp, nse, udata); + break; + + default: + fatal("Invalid proxy state!"); + } + + if (rc) { + nse->status = NSE_STATUS_PROXYERROR; + forward_event(nsp, nse, udata); + } +} + + +/* ---- PROXY DEFINITION ---- */ +static const struct proxy_op ProxyOpsHttp = { + proxy_http_node_new, + proxy_http_node_delete, + proxy_http_handler, +}; + +const struct proxy_spec ProxySpecHttp = { + "http://", + PROXY_TYPE_HTTP, + &ProxyOpsHttp, +}; + diff --git a/nsock/src/proxy_socks4.c b/nsock/src/proxy_socks4.c new file mode 100644 index 0000000..c88ca38 --- /dev/null +++ b/nsock/src/proxy_socks4.c @@ -0,0 +1,241 @@ +/*************************************************************************** + * proxy_socks4.c -- SOCKS4 proxying. * + * * + ***********************IMPORTANT NSOCK LICENSE TERMS*********************** + * + * The nsock parallel socket event library is (C) 1999-2023 Nmap Software LLC + * This library is free software; you may redistribute and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation; Version 2. This guarantees your right to use, modify, and + * redistribute this software under certain conditions. If this license is + * unacceptable to you, Nmap Software LLC may be willing to sell alternative + * licenses (contact sales@nmap.com ). + * + * As a special exception to the GPL terms, Nmap Software LLC grants permission + * to link the code of this program with any version of the OpenSSL library + * which is distributed under a license identical to that listed in the included + * docs/licenses/OpenSSL.txt file, and distribute linked combinations including + * the two. You must obey the GNU GPL in all respects for all of the code used + * other than OpenSSL. If you modify this file, you may extend this exception to + * your version of the file, but you are not obligated to do so. + * + * If you received these files with a written license agreement stating terms + * other than the (GPL) terms above, then that alternative license agreement + * takes precedence over this comment. + * + * Source is provided to this software because we believe users have a right to + * know exactly what a program is going to do before they run it. This also + * allows you to audit the software for security holes. + * + * Source code also allows you to port Nmap to new platforms, fix bugs, and add + * new features. You are highly encouraged to send your changes to the + * dev@nmap.org mailing list for possible incorporation into the main + * distribution. By sending these changes to Fyodor or one of the Insecure.Org + * development mailing lists, or checking them into the Nmap source code + * repository, it is understood (unless you specify otherwise) that you are + * offering the Nmap Project (Nmap Software LLC) the unlimited, non-exclusive + * right to reuse, modify, and relicense the code. Nmap will always be available + * Open Source, but this is important because the inability to relicense code + * has caused devastating problems for other Free Software projects (such as KDE + * and NASM). We also occasionally relicense the code to third parties as + * discussed above. If you wish to specify special license conditions of your + * contributions, just say so when you send them. + * + * 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 v2.0 for more + * details (http://www.gnu.org/licenses/gpl-2.0.html). + * + ***************************************************************************/ + +/* $Id $ */ + +#define _GNU_SOURCE +#include <stdio.h> + +#include "nsock.h" +#include "nsock_internal.h" +#include "nsock_log.h" + +#include <string.h> + +#define DEFAULT_PROXY_PORT_SOCKS4 1080 + + +extern struct timeval nsock_tod; +extern const struct proxy_spec ProxySpecSocks4; + + +struct socks4_data { + uint8_t version; + uint8_t type; + uint16_t port; + uint32_t address; + uint8_t null; +} __attribute__((packed)); + + +static int proxy_socks4_node_new(struct proxy_node **node, const struct uri *uri) { + int rc; + struct proxy_node *proxy; + + proxy = (struct proxy_node *)safe_zalloc(sizeof(struct proxy_node)); + proxy->spec = &ProxySpecSocks4; + + rc = proxy_resolve(uri->host, (struct sockaddr *)&proxy->ss, &proxy->sslen, AF_INET); + if (rc < 0) + goto err_out; + + if (proxy->ss.ss_family != AF_INET) { + rc = -1; + goto err_out; + } + + if (uri->port == -1) + proxy->port = DEFAULT_PROXY_PORT_SOCKS4; + else + proxy->port = (unsigned short)uri->port; + + rc = asprintf(&proxy->nodestr, "socks4://%s:%d", uri->host, proxy->port); + if (rc < 0) { + /* asprintf() failed for some reason but this is not a disaster (yet). + * Set nodestr to NULL and try to keep on going. */ + proxy->nodestr = NULL; + } + + rc = 1; + +err_out: + if (rc < 0) { + free(proxy); + proxy = NULL; + } + *node = proxy; + return rc; +} + +static void proxy_socks4_node_delete(struct proxy_node *node) { + if (!node) + return; + + free(node->nodestr); + + free(node); +} + +static inline void socks4_data_init(struct socks4_data *socks4, + struct sockaddr_storage *ss, size_t sslen, + unsigned short port) { + struct sockaddr_in *sin = (struct sockaddr_in *)ss; + + memset(socks4, 0x00, sizeof(struct socks4_data)); + socks4->version = 4; + socks4->type = 1; + socks4->port = htons(port); + assert(ss->ss_family == AF_INET); + socks4->address = sin->sin_addr.s_addr; +} + +static int handle_state_initial(struct npool *nsp, struct nevent *nse, void *udata) { + struct proxy_chain_context *px_ctx = nse->iod->px_ctx; + struct sockaddr_storage *ss; + size_t sslen; + unsigned short port; + struct proxy_node *next; + struct socks4_data socks4; + int timeout; + + px_ctx->px_state = PROXY_STATE_SOCKS4_TCP_CONNECTED; + + next = proxy_ctx_node_next(px_ctx); + if (next) { + ss = &next->ss; + sslen = next->sslen; + port = next->port; + } else { + ss = &px_ctx->target_ss; + sslen = px_ctx->target_sslen; + port = px_ctx->target_port; + } + + socks4_data_init(&socks4, ss, sslen, port); + + timeout = TIMEVAL_MSEC_SUBTRACT(nse->timeout, nsock_tod); + + nsock_write(nsp, (nsock_iod)nse->iod, nsock_proxy_ev_dispatch, timeout, udata, + (char *)&socks4, sizeof(socks4)); + + nsock_readbytes(nsp, (nsock_iod)nse->iod, nsock_proxy_ev_dispatch, timeout, + udata, 8); + return 0; +} + +static int handle_state_tcp_connected(struct npool *nsp, struct nevent *nse, void *udata) { + struct proxy_chain_context *px_ctx = nse->iod->px_ctx; + char *res; + int reslen; + + res = nse_readbuf(nse, &reslen); + + if (!(reslen == 8 && res[1] == 90)) { + struct proxy_node *node = px_ctx->px_current; + + nsock_log_debug("Ignoring invalid socks4 reply from proxy %s", + node->nodestr); + return -EINVAL; + } + + px_ctx->px_state = PROXY_STATE_SOCKS4_TUNNEL_ESTABLISHED; + + if (proxy_ctx_node_next(px_ctx) == NULL) { + forward_event(nsp, nse, udata); + } else { + px_ctx->px_current = proxy_ctx_node_next(px_ctx); + px_ctx->px_state = PROXY_STATE_INITIAL; + nsock_proxy_ev_dispatch(nsp, nse, udata); + } + return 0; +} + +static void proxy_socks4_handler(nsock_pool nspool, nsock_event nsevent, void *udata) { + int rc = 0; + struct npool *nsp = (struct npool *)nspool; + struct nevent *nse = (struct nevent *)nsevent; + + switch (nse->iod->px_ctx->px_state) { + case PROXY_STATE_INITIAL: + rc = handle_state_initial(nsp, nse, udata); + break; + + case PROXY_STATE_SOCKS4_TCP_CONNECTED: + if (nse->type == NSE_TYPE_READ) + rc = handle_state_tcp_connected(nsp, nse, udata); + break; + + case PROXY_STATE_SOCKS4_TUNNEL_ESTABLISHED: + forward_event(nsp, nse, udata); + break; + + default: + fatal("Invalid proxy state!"); + } + + if (rc) { + nse->status = NSE_STATUS_PROXYERROR; + forward_event(nsp, nse, udata); + } +} + +/* ---- PROXY DEFINITION ---- */ +static const struct proxy_op ProxyOpsSocks4 = { + proxy_socks4_node_new, + proxy_socks4_node_delete, + proxy_socks4_handler, +}; + +const struct proxy_spec ProxySpecSocks4 = { + "socks4://", + PROXY_TYPE_SOCKS4, + &ProxyOpsSocks4, +}; + |