CC = @CC@
RANLIB = @RANLIB@
-
INCLUDE = -I${top_srcdir} -I${top_srcdir}/src \
-include ${top_srcdir}/src/freeradius-devel/autoconf.h \
-include ${top_srcdir}/src/freeradius-devel/build.h \
- -include ${top_srcdir}/src/freeradius-devel/features.h
-
-CFLAGS = $(IMACROS) $(INCLUDE) -std=c99 -fno-strict-aliasing @CFLAGS@
+ -include ${top_srcdir}/src/freeradius-devel/features.h \
+ -include ${top_srcdir}/src/freeradius-devel/radpaths.h
+CFLAGS = $(INCLUDE) -std=c99 -fno-strict-aliasing @CFLAGS@
CPPFLAGS = @CPPFLAGS@
LIBPREFIX = @LIBPREFIX@
EXEEXT = @EXEEXT@
INSTALLSTRIP = @INSTALLSTRIP@
DARWIN_CFLAGS = @DARWIN_CFLAGS@
+#
+# Linker arguments for libraries searched for by the main
+# configure script.
+#
+TALLOC_LIBS = @TALLOC_LIBS@
+TALLOC_LDFLAGS = @TALLOC_LDFLAGS@
+
+OPENSSL_LIBS = @OPENSSL_LIBS@
+OPENSSL_LDFLAGS = @OPENSSL_LDFLAGS@
+
+PCAP_LIBS = @PCAP_LIBS@
+PCAP_LDFLAGS = @PCAP_LDFLAGS@
+
+COLLECTDC_LIBS = @COLLECTDC_LIBS@
+COLLECTDC_LDFLAGS = @COLLECTDC_LDFLAGS@
+
LCRYPT = @CRYPTLIB@
-LIBS = @LIBS@
-LDFLAGS = @LDFLAGS@
+
+#
+# OpenSSL libs (if used) must be linked everywhere in order for
+# the server to work properly on on all platforms.
+#
+LIBS = $(OPENSSL_LIBS) $(TALLOC_LIBS) @LIBS@
+LDFLAGS = $(OPENSSL_LDFLAGS) $(TALLOC_LDFLAGS) @LDFLAGS@
LOGDIR = ${logdir}
RADDBDIR = ${raddbdir}
RUNDIR = ${localstatedir}/run/radiusd
SBINDIR = ${sbindir}
RADIR = ${radacctdir}
-LIBRADIUS = $(top_builddir)/src/lib/$(LIBPREFIX)freeradius-radius.la -ltalloc
+LIBRADIUS = $(top_builddir)/src/lib/$(LIBPREFIX)freeradius-radius.la $(TALLOC_LIBS)
USE_SHARED_LIBS = @USE_SHARED_LIBS@
bm_shared_libs = @USE_SHARED_LIBS@
bm_static_libs = @USE_STATIC_LIBS@
STATIC_MODULES = @STATIC_MODULES@
-
-OPENSSL_LIBS = @OPENSSL_LIBS@
-OPENSSL_INCLUDE = @OPENSSL_INCLUDE@
-
-#
-# If the system has OpenSSL, use it's version of MD4/MD5/SHA1, instead of
-# using ours.
-#
-ifneq "$(OPENSSL_INCLUDE)" ""
-CFLAGS += -DWITH_OPENSSL_MD4 -DWITH_OPENSSL_MD5
-endif
-
LIBREADLINE = @LIBREADLINE@
#
RADIUSD_VERSION_STRING = @RADIUSD_VERSION_STRING@
#
-# This allows dlopen to do runtime checks for version mistmatches
+# This allows dlopen to do runtime checks for version mismatches
# between what it was originally linked with, and the library it's
# actually loading.
#
-#LDFLAGS += -release=$(RADIUSD_VERSION_STRING)
-
MODULES = @MODULES@
HOSTINFO = @HOSTINFO@
+#
+# If the system has OpenSSL, use it's version of MD4/MD5/SHA1, instead of
+# using ours.
+#
+ifeq "$(WITH_OPENSSL)" "yes"
+CFLAGS += -DWITH_OPENSSL_MD4 -DWITH_OPENSSL_MD5
+endif
+
+OPENSSL_LIBS = @OPENSSL_LIBS@
+
ifneq ($(WITH_OPENSSL_MD5),)
LIBRADIUS_WITH_OPENSSL = 1
CFLAGS += -DWITH_OPENSSL_MD5
REGEX
CRYPTLIB
LIBPREFIX
+COLLECTDC_LDFLAGS
+COLLECTDC_LIBS
+PCAP_LDFLAGS
PCAP_LIBS
+OPENSSL_LDFLAGS
OPENSSL_LIBS
-OPENSSL_INCLUDE
LIBREADLINE
+TALLOC_LDFLAGS
+TALLOC_LIBS
DIRNAME
LOCATE
AUTOHEADER
with_modules
with_experimental_modules
with_udpfromto
-with_openssl
-with_openssl_includes
-with_openssl_libraries
with_rlm_FOO_lib_dir
with_rlm_FOO_include_dir
-with_talloc_include_dir
+with_openssl
+with_openssl_lib_dir
+with_openssl_include_dir
with_talloc_lib_dir
-with_pcap_include_dir
+with_talloc_include_dir
with_pcap_lib_dir
+with_pcap_include_dir
+with_collectdclient_lib_dir
+with_collectdclient_include_dir
with_execinfo_lib_dir
with_execinfo_include_dir
with_pcre_lib_dir
--with-vmps compile in VMPS support. (default=yes)
--with-dhcp compile in DHCP support. (default=yes)
--with-static-modules=QUOTED-MODULE-LIST
- --with-shared-libs build dynamic libraries and link against them. (default=yes)
+ --with-shared-libs build dynamic libraries and link against them.
+ (default=yes)
--with-modules=QUOTED-MODULE-LIST
- --with-experimental-modules use experimental and unstable modules. (default=no, unless --enable-developer=yes)
- --with-udpfromto compile in UDPFROMTO support. (default=yes)
- --with-openssl use OpenSSL. (default=yes)
- --with-openssl-includes=DIR directory to look for OpenSSL include files in
- --with-openssl-libraries=DIR directory to look for OpenSSL library files in
- --with-rlm-FOO-lib-dir=DIR directory to look for library files used by module FOO in
- --with-rlm-FOO-include-dir=DIR directory to look for include files used by module FOO in
- --with-talloc-include-dir=DIR directory to look for talloc include files in
- --with-talloc-lib-dir=DIR directory to look for talloc library files in
- --with-pcap-include-dir=DIR directory to look for pcap include files in
- --with-pcap-lib-dir=DIR directory to look for pcap library files in
- --with-execinfo-lib-dir=DIR directory to look for execinfo library files in
- --with-execinfo-include-dir=DIR directory to look for execinfo include files in
- --with-pcre-lib-dir=DIR directory to look for pcre library files in
- --with-pcre-include-dir=DIR directory to look for PCRE include files in
+ --with-experimental-modules
+ use experimental and unstable modules. (default=no,
+ unless --enable-developer=yes)
+ --with-udpfromto compile in UDPFROMTO support. (default=yes)
+ --with-rlm-FOO-lib-dir=DIR
+ directory in which to look for library files used by
+ module FOO
+ --with-rlm-FOO-include-dir=DIR
+ directory in which to look for include files used by
+ module FOO
+ --with-openssl use OpenSSL. (default=yes)
+ --with-openssl-lib-dir=DIR
+ directory to look for OpenSSL library files
+ --with-openssl-include-dir=DIR
+ directory to look for OpenSSL include files
+ --with-talloc-lib-dir=DIR
+ directory in which to look for talloc library files
+ --with-talloc-include-dir=DIR
+ directory in which to look for talloc include files
+ --with-pcap-lib-dir=DIR directory in which to look for pcap library files
+ --with-pcap-include-dir=DIR
+ directory in which to look for pcap include files
+ --with-collectdclient-lib-dir=DIR
+ directory in which to look for collectdclient
+ library files
+ --with-collectdclient-include-dir=DIR
+ directory in which to look for collectdclient
+ include files
+ --with-execinfo-lib-dir=DIR
+ directory in which to look for execinfo library
+ files
+ --with-execinfo-include-dir=DIR
+ directory in which to look for execinfo include
+ files
+ --with-pcre-lib-dir=DIR directory in which to look for pcre library files
+ --with-pcre-include-dir=DIR
+ directory in which to look for pcre include files
Some influential environment variables:
CC C compiler command
} # ac_fn_c_try_link
-# ac_fn_c_check_type LINENO TYPE VAR INCLUDES
-# -------------------------------------------
-# Tests whether TYPE exists after having included INCLUDES, setting cache
-# variable VAR accordingly.
-ac_fn_c_check_type ()
-{
- 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
- eval "$3=no"
- cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-$4
-int
-main ()
-{
-if (sizeof ($2))
- return 0;
- ;
- return 0;
-}
-_ACEOF
-if ac_fn_c_try_compile "$LINENO"; then :
- cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-$4
-int
-main ()
-{
-if (sizeof (($2)))
- return 0;
- ;
- return 0;
-}
-_ACEOF
-if ac_fn_c_try_compile "$LINENO"; then :
-
-else
- eval "$3=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
-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_type
-
# ac_fn_c_check_func LINENO FUNC VAR
# ----------------------------------
# Tests whether FUNC exists, setting the cache variable VAR accordingly
} # ac_fn_c_check_func
+# ac_fn_c_check_type LINENO TYPE VAR INCLUDES
+# -------------------------------------------
+# Tests whether TYPE exists after having included INCLUDES, setting cache
+# variable VAR accordingly.
+ac_fn_c_check_type ()
+{
+ 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
+ eval "$3=no"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+$4
+int
+main ()
+{
+if (sizeof ($2))
+ return 0;
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+$4
+int
+main ()
+{
+if (sizeof (($2)))
+ return 0;
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+
+else
+ eval "$3=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
+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_type
+
# ac_fn_c_check_decl LINENO SYMBOL VAR INCLUDES
# ---------------------------------------------
# Tests whether SYMBOL is declared in INCLUDES, setting cache variable VAR
case "$host" in
*-darwin*)
+ LDFLAGS="-L/usr/local/lib -L/usr/lib"
+
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if cc is apple llvm" >&5
$as_echo_n "checking if cc is apple llvm... " >&6; }
if ! $CC --version 2>&1 | grep -I 'Apple LLVM' > /dev/null; then
$as_echo "$osx_sdk_path" >&6; }
export CFLAGS="$CFLAGS --sysroot=$osx_sdk_path"
- export CPPFLAGS="$CPPFLAGS --sysroot=$osx_sdk_path"
export LDFLAGS="$LDFLAGS -L$osx_sdk_path/usr/lib/"
DARWIN_CFLAGS="--sysroot=$osx_sdk_path"
fi
-WITH_OPENSSL=yes
-# Check whether --with-openssl was given.
-if test "${with_openssl+set}" = set; then :
- withval=$with_openssl; case "$withval" in
- no)
- WITH_OPENSSL=no
- ;;
+
+# Check whether --with-rlm-FOO-lib-dir was given.
+if test "${with_rlm_FOO_lib_dir+set}" = set; then :
+ withval=$with_rlm_FOO_lib_dir; case "$withval" in
*)
- WITH_OPENSSL=yes
;;
esac
fi
-OPENSSL_INCLUDE_DIR=
-# Check whether --with-openssl-includes was given.
-if test "${with_openssl_includes+set}" = set; then :
- withval=$with_openssl_includes; case "$withval" in
- *) OPENSSL_INCLUDE_DIR="$withval"
+# Check whether --with-rlm-FOO-include-dir was given.
+if test "${with_rlm_FOO_include_dir+set}" = set; then :
+ withval=$with_rlm_FOO_include_dir; case "$withval" in
+ *)
;;
esac
fi
-OPENSSL_LIB_DIR=
+WITH_OPENSSL=yes
-# Check whether --with-openssl-libraries was given.
-if test "${with_openssl_libraries+set}" = set; then :
- withval=$with_openssl_libraries; case "$withval" in
- *) OPENSSL_LIB_DIR="$withval"
+# Check whether --with-openssl was given.
+if test "${with_openssl+set}" = set; then :
+ withval=$with_openssl; case "$withval" in
+ no)
+ WITH_OPENSSL=no
+ ;;
+ *)
+ WITH_OPENSSL=yes
;;
esac
fi
+openssl_lib_dir=
-
-# Check whether --with-rlm-FOO-lib-dir was given.
-if test "${with_rlm_FOO_lib_dir+set}" = set; then :
- withval=$with_rlm_FOO_lib_dir; case "$withval" in
- *)
+# Check whether --with-openssl-lib-dir was given.
+if test "${with_openssl_lib_dir+set}" = set; then :
+ withval=$with_openssl_lib_dir; case "$withval" in
+ *) openssl_lib_dir="$withval"
;;
esac
fi
+openssl_include_dir=
-# Check whether --with-rlm-FOO-include-dir was given.
-if test "${with_rlm_FOO_include_dir+set}" = set; then :
- withval=$with_rlm_FOO_include_dir; case "$withval" in
- *)
+# Check whether --with-openssl-include-dir was given.
+if test "${with_openssl_include_dir+set}" = set; then :
+ withval=$with_openssl_include_dir; case "$withval" in
+ *) openssl_include_dir="$withval"
;;
esac
-old_CFLAGS=$CFLAGS
-if test "x$WITH_THREADS" = "xyes"; then
- if test $ac_cv_prog_suncc = "yes"; then
- CFLAGS="$CFLAGS -mt"
- fi
+talloc_lib_dir=
- for ac_header in pthread.h
-do :
- ac_fn_c_check_header_mongrel "$LINENO" "pthread.h" "ac_cv_header_pthread_h" "$ac_includes_default"
-if test "x$ac_cv_header_pthread_h" = xyes; then :
- cat >>confdefs.h <<_ACEOF
-#define HAVE_PTHREAD_H 1
-_ACEOF
+# Check whether --with-talloc-lib-dir was given.
+if test "${with_talloc_lib_dir+set}" = set; then :
+ withval=$with_talloc_lib_dir; case "$withval" in
+ no)
+ as_fn_error $? "Need talloc-lib-dir" "$LINENO" 5
+ ;;
+ yes)
+ ;;
+ *)
+ talloc_lib_dir="$withval"
+ ;;
+ esac
+fi
-else
- WITH_THREADS="no"
+
+talloc_include_dir=
+
+# Check whether --with-talloc-include-dir was given.
+if test "${with_talloc_include_dir+set}" = set; then :
+ withval=$with_talloc_include_dir; case "$withval" in
+ no)
+ as_fn_error $? "Need talloc-include-dir" "$LINENO" 5
+ ;;
+ yes)
+ ;;
+ *)
+ talloc_include_dir="$withval"
+ ;;
+ esac
fi
-done
+smart_try_dir="$talloc_lib_dir"
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for pthread_create in -lpthread" >&5
-$as_echo_n "checking for pthread_create in -lpthread... " >&6; }
-if ${ac_cv_lib_pthread_pthread_create+:} false; then :
- $as_echo_n "(cached) " >&6
-else
- ac_check_lib_save_LIBS=$LIBS
-LIBS="-lpthread $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 pthread_create ();
+sm_lib_safe=`echo "talloc" | sed 'y%./+-%__p_%'`
+sm_func_safe=`echo "_talloc" | sed 'y%./+-%__p_%'`
+
+old_LIBS="$LIBS"
+old_CPPFLAGS="$CPPFLAGS"
+smart_lib=
+smart_ldflags=
+smart_lib_dir=
+
+if test "x$smart_try_dir" != "x"; then
+ for try in $smart_try_dir; do
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _talloc in -ltalloc in $try" >&5
+$as_echo_n "checking for _talloc in -ltalloc in $try... " >&6; }
+ LIBS="-ltalloc $old_LIBS"
+ CPPFLAGS="-L$try -Wl,-rpath,$try $old_CPPFLAGS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+extern char _talloc();
int
main ()
{
-return pthread_create ();
+_talloc()
;
return 0;
}
_ACEOF
if ac_fn_c_try_link "$LINENO"; then :
- ac_cv_lib_pthread_pthread_create=yes
+
+ smart_lib="-ltalloc"
+ smart_ldflags="-L$try -Wl,-rpath,$try"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+ break
+
else
- ac_cv_lib_pthread_pthread_create=no
+ { $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=$ac_check_lib_save_LIBS
+ done
+ LIBS="$old_LIBS"
+ CPPFLAGS="$old_CPPFLAGS"
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_pthread_pthread_create" >&5
-$as_echo "$ac_cv_lib_pthread_pthread_create" >&6; }
-if test "x$ac_cv_lib_pthread_pthread_create" = xyes; then :
- CFLAGS="$CFLAGS -D_REENTRANT -D_POSIX_PTHREAD_SEMANTICS"
- LIBS="-lpthread $LIBS"
-
-else
-
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for pthread_create in -lc_r" >&5
-$as_echo_n "checking for pthread_create in -lc_r... " >&6; }
-if ${ac_cv_lib_c_r_pthread_create+:} false; then :
- $as_echo_n "(cached) " >&6
-else
- ac_check_lib_save_LIBS=$LIBS
-LIBS="-lc_r $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
+if test "x$smart_lib" = "x"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _talloc in -ltalloc" >&5
+$as_echo_n "checking for _talloc in -ltalloc... " >&6; }
+ LIBS="-ltalloc $old_LIBS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+extern char _talloc();
+int
+main ()
+{
+_talloc()
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+
+ smart_lib="-ltalloc"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+
+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="$old_LIBS"
+fi
+
+if test "x$smart_lib" = "x"; then
+
+
+if test "x$LOCATE" != "x"; then
+ DIRS=
+ file=libtalloc${libltdl_cv_shlibext}
+
+ for x in `${LOCATE} $file 2>/dev/null`; do
+ base=`echo $x | sed "s%/${file}%%"`
+ if test "x$x" = "x$base"; then
+ continue;
+ fi
+
+ dir=`${DIRNAME} $x 2>/dev/null`
+ exclude=`echo ${dir} | ${GREP} /home`
+ if test "x$exclude" != "x"; then
+ continue
+ fi
+
+ already=`echo \$smart_lib_dir ${DIRS} | ${GREP} ${dir}`
+ if test "x$already" = "x"; then
+ DIRS="$DIRS $dir"
+ fi
+ done
+fi
+
+eval "smart_lib_dir=\"\$smart_lib_dir $DIRS\""
+
+
+
+if test "x$LOCATE" != "x"; then
+ DIRS=
+ file=libtalloc.a
+
+ for x in `${LOCATE} $file 2>/dev/null`; do
+ base=`echo $x | sed "s%/${file}%%"`
+ if test "x$x" = "x$base"; then
+ continue;
+ fi
+
+ dir=`${DIRNAME} $x 2>/dev/null`
+ exclude=`echo ${dir} | ${GREP} /home`
+ if test "x$exclude" != "x"; then
+ continue
+ fi
+
+ already=`echo \$smart_lib_dir ${DIRS} | ${GREP} ${dir}`
+ if test "x$already" = "x"; then
+ DIRS="$DIRS $dir"
+ fi
+ done
+fi
+
+eval "smart_lib_dir=\"\$smart_lib_dir $DIRS\""
+
+
+ for try in $smart_lib_dir /usr/local/lib /opt/lib; do
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _talloc in -ltalloc in $try" >&5
+$as_echo_n "checking for _talloc in -ltalloc in $try... " >&6; }
+ LIBS="-ltalloc $old_LIBS"
+ CPPFLAGS="-L$try -Wl,-rpath,$try $old_CPPFLAGS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+extern char _talloc();
+int
+main ()
+{
+_talloc()
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+
+ smart_lib="-ltalloc"
+ smart_ldflags="-L$try -Wl,-rpath,$try"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+ break
+
+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
+ done
+ LIBS="$old_LIBS"
+ CPPFLAGS="$old_CPPFLAGS"
+fi
+
+if test "x$smart_lib" != "x"; then
+ eval "ac_cv_lib_${sm_lib_safe}_${sm_func_safe}=yes"
+ LIBS="$smart_ldflags $smart_lib $old_LIBS"
+ SMART_LIBS="$smart_ldflags $smart_lib $SMART_LIBS"
+fi
+
+if test "x$ac_cv_lib_talloc__talloc" != "xyes"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: talloc library not found. Use --with-talloc-lib-dir=<path>." >&5
+$as_echo "$as_me: WARNING: talloc library not found. Use --with-talloc-lib-dir=<path>." >&2;}
+ as_fn_error $? "FreeRADIUS requires libtalloc" "$LINENO" 5
+fi
+
+TALLOC_LIBS="${smart_lib}"
+TALLOC_LDFLAGS="${smart_ldflags}"
+
+
+LIBS="$old_LIBS"
+
+old_CFLAGS=$CFLAGS
+if test "x$WITH_THREADS" = "xyes"; then
+ if test $ac_cv_prog_suncc = "yes"; then
+ CFLAGS="$CFLAGS -mt"
+ fi
+
+ for ac_header in pthread.h
+do :
+ ac_fn_c_check_header_mongrel "$LINENO" "pthread.h" "ac_cv_header_pthread_h" "$ac_includes_default"
+if test "x$ac_cv_header_pthread_h" = xyes; then :
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_PTHREAD_H 1
+_ACEOF
+
+else
+
+ WITH_THREADS="no"
+ fail=pthread.h
+
+fi
+
+done
+
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for pthread_create in -lpthread" >&5
+$as_echo_n "checking for pthread_create in -lpthread... " >&6; }
+if ${ac_cv_lib_pthread_pthread_create+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lpthread $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 pthread_create ();
+int
+main ()
+{
+return pthread_create ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ ac_cv_lib_pthread_pthread_create=yes
+else
+ ac_cv_lib_pthread_pthread_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_pthread_pthread_create" >&5
+$as_echo "$ac_cv_lib_pthread_pthread_create" >&6; }
+if test "x$ac_cv_lib_pthread_pthread_create" = xyes; then :
+
+ CFLAGS="$CFLAGS -D_REENTRANT -D_POSIX_PTHREAD_SEMANTICS"
+ LIBS="-lpthread $LIBS"
+
+else
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for pthread_create in -lc_r" >&5
+$as_echo_n "checking for pthread_create in -lc_r... " >&6; }
+if ${ac_cv_lib_c_r_pthread_create+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lc_r $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"
if test "x$ac_cv_lib_c_r_pthread_create" = xyes; then :
CFLAGS="$CFLAGS -pthread -D_THREAD_SAFE"
else
- WITH_THREADS="no"
+
+ WITH_THREADS="no"
+ fail=-lpthread
+
fi
fi
+
+ if test "x$WITH_THREADS" != "xyes"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: silently not building with thread support." >&5
+$as_echo "$as_me: WARNING: silently not building with thread support." >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: FAILURE: thread support requires: $fail." >&5
+$as_echo "$as_me: WARNING: FAILURE: thread support requires: $fail." >&2;}
+ else
+
+$as_echo "#define WITH_THREADS 1" >>confdefs.h
+
+ fi
fi
if test "x$WITH_THREADS" != "xyes"; then
fi
-if test "x$WITH_THREADS" = "xyes"; then
-
-$as_echo "#define WITH_THREADS 1" >>confdefs.h
-
-fi
-
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlopen in -ldl" >&5
$as_echo_n "checking for dlopen in -ldl... " >&6; }
if ${ac_cv_lib_dl_dlopen+:} false; then :
fi
+pcap_lib_dir=
+
+# Check whether --with-pcap-lib-dir was given.
+if test "${with_pcap_lib_dir+set}" = set; then :
+ withval=$with_pcap_lib_dir; case "$withval" in
+ no)
+ as_fn_error $? "Need pcap-lib-dir" "$LINENO" 5
+ ;;
+ yes)
+ ;;
+ *)
+ pcap_lib_dir="$withval"
+ ;;
+ esac
+fi
+
+
+pcap_include_dir=
+
+# Check whether --with-pcap-include-dir was given.
+if test "${with_pcap_include_dir+set}" = set; then :
+ withval=$with_pcap_include_dir; case "$withval" in
+ no)
+ as_fn_error $? "Need pcap-include-dir" "$LINENO" 5
+ ;;
+ yes)
+ ;;
+ *)
+ pcap_include_dir="$withval"
+ ;;
+ esac
+fi
+
+
smart_try_dir="$pcap_lib_dir"
sm_func_safe=`echo "pcap_open_live" | sed 'y%./+-%__p_%'`
old_LIBS="$LIBS"
+old_CPPFLAGS="$CPPFLAGS"
smart_lib=
+smart_ldflags=
smart_lib_dir=
if test "x$smart_try_dir" != "x"; then
for try in $smart_try_dir; do
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for pcap_open_live in -lpcap in $try" >&5
$as_echo_n "checking for pcap_open_live in -lpcap in $try... " >&6; }
- LIBS="-L$try -lpcap $old_LIBS -Wl,-rpath,$try"
+ LIBS="-lpcap $old_LIBS"
+ CPPFLAGS="-L$try -Wl,-rpath,$try $old_CPPFLAGS"
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
extern char pcap_open_live();
_ACEOF
if ac_fn_c_try_link "$LINENO"; then :
- smart_lib="-L$try -lpcap -Wl,-rpath,$try"
+ smart_lib="-lpcap"
+ smart_ldflags="-L$try -Wl,-rpath,$try"
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
$as_echo "yes" >&6; }
break
conftest$ac_exeext conftest.$ac_ext
done
LIBS="$old_LIBS"
+ CPPFLAGS="$old_CPPFLAGS"
fi
if test "x$smart_lib" = "x"; then
for try in $smart_lib_dir /usr/local/lib /opt/lib; do
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for pcap_open_live in -lpcap in $try" >&5
$as_echo_n "checking for pcap_open_live in -lpcap in $try... " >&6; }
- LIBS="-L$try -lpcap $old_LIBS -Wl,-rpath,$try"
+ LIBS="-lpcap $old_LIBS"
+ CPPFLAGS="-L$try -Wl,-rpath,$try $old_CPPFLAGS"
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
extern char pcap_open_live();
_ACEOF
if ac_fn_c_try_link "$LINENO"; then :
- smart_lib="-L$try -lpcap -Wl,-rpath,$try"
+ smart_lib="-lpcap"
+ smart_ldflags="-L$try -Wl,-rpath,$try"
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
$as_echo "yes" >&6; }
break
conftest$ac_exeext conftest.$ac_ext
done
LIBS="$old_LIBS"
+ CPPFLAGS="$old_CPPFLAGS"
fi
if test "x$smart_lib" != "x"; then
eval "ac_cv_lib_${sm_lib_safe}_${sm_func_safe}=yes"
- LIBS="$smart_lib $old_LIBS"
- SMART_LIBS="$smart_lib $SMART_LIBS"
+ LIBS="$smart_ldflags $smart_lib $old_LIBS"
+ SMART_LIBS="$smart_ldflags $smart_lib $SMART_LIBS"
fi
if test "x$ac_cv_lib_pcap_pcap_open_live" != "xyes"; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: pcap library not found. Use --with-pcap-lib-dir=<path>." >&5
-$as_echo "$as_me: WARNING: pcap library not found. Use --with-pcap-lib-dir=<path>." >&2;}
- { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: pcap library not found, silently disabling the RADIUS sniffer and ARP listener." >&5
-$as_echo "$as_me: WARNING: pcap library not found, silently disabling the RADIUS sniffer and ARP listener." >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: pcap library not found, silently disabling the RADIUS sniffer, and ARP listener. Use --with-pcap-lib-dir=<path>." >&5
+$as_echo "$as_me: WARNING: pcap library not found, silently disabling the RADIUS sniffer, and ARP listener. Use --with-pcap-lib-dir=<path>." >&2;}
else
- PCAP_LIBS="${smart_lib}"
- LIBS=$old_LIBS
$as_echo "#define HAVE_LIBPCAP 1" >>confdefs.h
-fi
+ for ac_func in \
+ pcap_fopen_offline \
+ pcap_dump_fopen \
+ pcap_create \
+ pcap_activate
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for a readline compatible library" >&5
+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
+
+fi
+done
+
+
+ PCAP_LIBS="${smart_lib}"
+ PCAP_LDFLAGS="${smart_ldflags}"
+fi
+LIBS="${old_LIBS}"
+
+collectdclient_lib_dir=
+
+# Check whether --with-collectdclient-lib-dir was given.
+if test "${with_collectdclient_lib_dir+set}" = set; then :
+ withval=$with_collectdclient_lib_dir; case "$withval" in
+ no)
+ as_fn_error $? "Need collectdclient-lib-dir" "$LINENO" 5
+ ;;
+ yes)
+ ;;
+ *)
+ collectdclient_lib_dir="$withval"
+ ;;
+ esac
+fi
+
+
+collectdclient_include_dir=
+
+# Check whether --with-collectdclient-include-dir was given.
+if test "${with_collectdclient_include_dir+set}" = set; then :
+ withval=$with_collectdclient_include_dir; case "$withval" in
+ no)
+ as_fn_error $? "Need collectdclient-include-dir" "$LINENO" 5
+ ;;
+ yes)
+ ;;
+ *)
+ collectdclient_include_dir="$withval"
+ ;;
+ esac
+fi
+
+
+smart_try_dir="$collectdclient_lib_dir"
+
+
+sm_lib_safe=`echo "collectdclient" | sed 'y%./+-%__p_%'`
+sm_func_safe=`echo "lcc_connect" | sed 'y%./+-%__p_%'`
+
+old_LIBS="$LIBS"
+old_CPPFLAGS="$CPPFLAGS"
+smart_lib=
+smart_ldflags=
+smart_lib_dir=
+
+if test "x$smart_try_dir" != "x"; then
+ for try in $smart_try_dir; do
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for lcc_connect in -lcollectdclient in $try" >&5
+$as_echo_n "checking for lcc_connect in -lcollectdclient in $try... " >&6; }
+ LIBS="-lcollectdclient $old_LIBS"
+ CPPFLAGS="-L$try -Wl,-rpath,$try $old_CPPFLAGS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+extern char lcc_connect();
+int
+main ()
+{
+lcc_connect()
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+
+ smart_lib="-lcollectdclient"
+ smart_ldflags="-L$try -Wl,-rpath,$try"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+ break
+
+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
+ done
+ LIBS="$old_LIBS"
+ CPPFLAGS="$old_CPPFLAGS"
+fi
+
+if test "x$smart_lib" = "x"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for lcc_connect in -lcollectdclient" >&5
+$as_echo_n "checking for lcc_connect in -lcollectdclient... " >&6; }
+ LIBS="-lcollectdclient $old_LIBS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+extern char lcc_connect();
+int
+main ()
+{
+lcc_connect()
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+
+ smart_lib="-lcollectdclient"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+
+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="$old_LIBS"
+fi
+
+if test "x$smart_lib" = "x"; then
+
+
+if test "x$LOCATE" != "x"; then
+ DIRS=
+ file=libcollectdclient${libltdl_cv_shlibext}
+
+ for x in `${LOCATE} $file 2>/dev/null`; do
+ base=`echo $x | sed "s%/${file}%%"`
+ if test "x$x" = "x$base"; then
+ continue;
+ fi
+
+ dir=`${DIRNAME} $x 2>/dev/null`
+ exclude=`echo ${dir} | ${GREP} /home`
+ if test "x$exclude" != "x"; then
+ continue
+ fi
+
+ already=`echo \$smart_lib_dir ${DIRS} | ${GREP} ${dir}`
+ if test "x$already" = "x"; then
+ DIRS="$DIRS $dir"
+ fi
+ done
+fi
+
+eval "smart_lib_dir=\"\$smart_lib_dir $DIRS\""
+
+
+
+if test "x$LOCATE" != "x"; then
+ DIRS=
+ file=libcollectdclient.a
+
+ for x in `${LOCATE} $file 2>/dev/null`; do
+ base=`echo $x | sed "s%/${file}%%"`
+ if test "x$x" = "x$base"; then
+ continue;
+ fi
+
+ dir=`${DIRNAME} $x 2>/dev/null`
+ exclude=`echo ${dir} | ${GREP} /home`
+ if test "x$exclude" != "x"; then
+ continue
+ fi
+
+ already=`echo \$smart_lib_dir ${DIRS} | ${GREP} ${dir}`
+ if test "x$already" = "x"; then
+ DIRS="$DIRS $dir"
+ fi
+ done
+fi
+
+eval "smart_lib_dir=\"\$smart_lib_dir $DIRS\""
+
+
+ for try in $smart_lib_dir /usr/local/lib /opt/lib; do
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for lcc_connect in -lcollectdclient in $try" >&5
+$as_echo_n "checking for lcc_connect in -lcollectdclient in $try... " >&6; }
+ LIBS="-lcollectdclient $old_LIBS"
+ CPPFLAGS="-L$try -Wl,-rpath,$try $old_CPPFLAGS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+extern char lcc_connect();
+int
+main ()
+{
+lcc_connect()
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+
+ smart_lib="-lcollectdclient"
+ smart_ldflags="-L$try -Wl,-rpath,$try"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+ break
+
+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
+ done
+ LIBS="$old_LIBS"
+ CPPFLAGS="$old_CPPFLAGS"
+fi
+
+if test "x$smart_lib" != "x"; then
+ eval "ac_cv_lib_${sm_lib_safe}_${sm_func_safe}=yes"
+ LIBS="$smart_ldflags $smart_lib $old_LIBS"
+ SMART_LIBS="$smart_ldflags $smart_lib $SMART_LIBS"
+fi
+
+if test "x$ac_cv_lib_collectdclient_lcc_connect" != "xyes"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: collectdclient library not found. Use --with-collectdclient-lib-dir=<path>." >&5
+$as_echo "$as_me: WARNING: collectdclient library not found. Use --with-collectdclient-lib-dir=<path>." >&2;}
+else
+ COLLECTDC_LIBS="${smart_lib}"
+ COLLECTDC_LDFLAGS="${smart_ldflags}"
+fi
+LIBS="${old_LIBS}"
+
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for a readline compatible library" >&5
$as_echo_n "checking for a readline compatible library... " >&6; }
if ${vl_cv_lib_readline+:} false; then :
$as_echo_n "(cached) " >&6
-case "$host" in
- *-interix*)
- CFLAGS="$CFLAGS -D_ALL_SOURCE"
- ;;
- *-darwin*)
- CFLAGS="$CFLAGS -DDARWIN"
- LIBS="-framework DirectoryService $LIBS"
- ;;
-esac
+smart_try_dir="$talloc_include_dir"
-ac_header_dirent=no
-for ac_hdr in dirent.h sys/ndir.h sys/dir.h ndir.h; do
- as_ac_Header=`$as_echo "ac_cv_header_dirent_$ac_hdr" | $as_tr_sh`
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_hdr that defines DIR" >&5
-$as_echo_n "checking for $ac_hdr that defines DIR... " >&6; }
-if eval \${$as_ac_Header+:} false; then :
- $as_echo_n "(cached) " >&6
-else
- cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+
+ac_safe=`echo "talloc.h" | sed 'y%./+-%__pm%'`
+old_CPPFLAGS="$CPPFLAGS"
+smart_include=
+smart_include_dir=
+
+if test "x$smart_try_dir" != "x"; then
+ for try in $smart_try_dir; do
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for talloc.h in $try" >&5
+$as_echo_n "checking for talloc.h in $try... " >&6; }
+ CPPFLAGS="-isystem $try $old_CPPFLAGS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
-#include <sys/types.h>
-#include <$ac_hdr>
+ #include <talloc.h>
int
main ()
{
-if ((DIR *) 0)
-return 0;
+int a = 1;
;
return 0;
}
_ACEOF
if ac_fn_c_try_compile "$LINENO"; then :
- eval "$as_ac_Header=yes"
+
+ smart_include="-isystem $try"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+ break
+
else
- eval "$as_ac_Header=no"
+
+ smart_include=
+ { $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_ext
+ done
+ CPPFLAGS="$old_CPPFLAGS"
fi
-eval ac_res=\$$as_ac_Header
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
-$as_echo "$ac_res" >&6; }
-if eval test \"x\$"$as_ac_Header"\" = x"yes"; then :
- cat >>confdefs.h <<_ACEOF
-#define `$as_echo "HAVE_$ac_hdr" | $as_tr_cpp` 1
-_ACEOF
-ac_header_dirent=$ac_hdr; break
-fi
+if test "x$smart_include" = "x"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for talloc.h" >&5
+$as_echo_n "checking for talloc.h... " >&6; }
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
-done
-# Two versions of opendir et al. are in -ldir and -lx on SCO Xenix.
-if test $ac_header_dirent = dirent.h; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing opendir" >&5
-$as_echo_n "checking for library containing opendir... " >&6; }
-if ${ac_cv_search_opendir+:} false; then :
- $as_echo_n "(cached) " >&6
-else
- ac_func_search_save_LIBS=$LIBS
+ #include <talloc.h>
+int
+main ()
+{
+int a = 1;
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+
+ smart_include=" "
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+ break
+
+else
+
+ smart_include=
+ { $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_ext
+fi
+
+if test "x$smart_include" = "x"; then
+
+
+if test "x$LOCATE" != "x"; then
+ DIRS=
+ file=talloc.h
+
+ for x in `${LOCATE} $file 2>/dev/null`; do
+ base=`echo $x | sed "s%/${file}%%"`
+ if test "x$x" = "x$base"; then
+ continue;
+ fi
+
+ dir=`${DIRNAME} $x 2>/dev/null`
+ exclude=`echo ${dir} | ${GREP} /home`
+ if test "x$exclude" != "x"; then
+ continue
+ fi
+
+ already=`echo \$smart_include_dir ${DIRS} | ${GREP} ${dir}`
+ if test "x$already" = "x"; then
+ DIRS="$DIRS $dir"
+ fi
+ done
+fi
+
+eval "smart_include_dir=\"\$smart_include_dir $DIRS\""
+
+ for try in $smart_include_dir /usr/local/include /opt/include; do
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for talloc.h in $try" >&5
+$as_echo_n "checking for talloc.h in $try... " >&6; }
+ CPPFLAGS="-isystem $try $old_CPPFLAGS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ #include <talloc.h>
+int
+main ()
+{
+int a = 1;
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+
+ smart_include="-isystem $try"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+ break
+
+else
+
+ smart_include=
+ { $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_ext
+ done
+ CPPFLAGS="$old_CPPFLAGS"
+fi
+
+if test "x$smart_include" != "x"; then
+ eval "ac_cv_header_$ac_safe=yes"
+ CPPFLAGS="$smart_include $old_CPPFLAGS"
+ SMART_CPPFLAGS="$smart_include $SMART_CPPFLAGS"
+fi
+
+if test "x$ac_cv_header_talloc_h" != "xyes"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: talloc headers not found. Use --with-talloc-include-dir=<path>." >&5
+$as_echo "$as_me: WARNING: talloc headers not found. Use --with-talloc-include-dir=<path>." >&2;}
+ as_fn_error $? "FreeRADIUS requires libtalloc" "$LINENO" 5
+fi
+
+case "$host" in
+ *-interix*)
+ CFLAGS="$CFLAGS -D_ALL_SOURCE"
+ ;;
+ *-darwin*)
+ CFLAGS="$CFLAGS -DDARWIN"
+ LIBS="-framework DirectoryService $LIBS"
+ ;;
+esac
+
+ac_header_dirent=no
+for ac_hdr in dirent.h sys/ndir.h sys/dir.h ndir.h; do
+ as_ac_Header=`$as_echo "ac_cv_header_dirent_$ac_hdr" | $as_tr_sh`
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_hdr that defines DIR" >&5
+$as_echo_n "checking for $ac_hdr that defines DIR... " >&6; }
+if eval \${$as_ac_Header+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <sys/types.h>
+#include <$ac_hdr>
+
+int
+main ()
+{
+if ((DIR *) 0)
+return 0;
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ eval "$as_ac_Header=yes"
+else
+ eval "$as_ac_Header=no"
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+eval ac_res=\$$as_ac_Header
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+if eval test \"x\$"$as_ac_Header"\" = x"yes"; then :
+ cat >>confdefs.h <<_ACEOF
+#define `$as_echo "HAVE_$ac_hdr" | $as_tr_cpp` 1
+_ACEOF
+
+ac_header_dirent=$ac_hdr; break
+fi
+
+done
+# Two versions of opendir et al. are in -ldir and -lx on SCO Xenix.
+if test $ac_header_dirent = dirent.h; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing opendir" >&5
+$as_echo_n "checking for library containing opendir... " >&6; }
+if ${ac_cv_search_opendir+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_func_search_save_LIBS=$LIBS
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
unistd.h \
crypt.h \
errno.h \
- features.h \
resource.h \
sys/resource.h \
getopt.h \
stddef.h \
fnmatch.h \
sia.h \
- siad.h
+ siad.h \
+ features.h
do :
as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
for ac_header in net/if.h
do :
ac_fn_c_check_header_compile "$LINENO" "net/if.h" "ac_cv_header_net_if_h" "
- #ifdef HAVE_SYS_SOCKET_H
- # include <sys/socket.h>
- #endif
+ #ifdef HAVE_SYS_SOCKET_H
+ # include <sys/socket.h>
+ #endif
+
"
if test "x$ac_cv_header_net_if_h" = xyes; then :
fi
if test "x$WITH_OPENSSL" = xyes; then
- old_LIBS=$LIBS
- old_LDFLAGS="$LDFLAGS"
+ OLD_LIBS="$LIBS"
- OPENSSL_INCLUDE="-DNO_OPENSSL"
- OPENSSL_LIBS=
- if test "x$OPENSSL_LIB_DIR" != "x"; then
- LDFLAGS="-L$OPENSSL_LIB_DIR $LDFLAGS"
- fi
+ CFLAGS="$CFLAGS -DOPENSSL_NO_KRB5"
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for DH_new in -lcrypto" >&5
-$as_echo_n "checking for DH_new in -lcrypto... " >&6; }
-if ${ac_cv_lib_crypto_DH_new+:} 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. */
+ smart_try_dir="$openssl_lib_dir"
-/* 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 DH_new ();
+
+sm_lib_safe=`echo "crypto" | sed 'y%./+-%__p_%'`
+sm_func_safe=`echo "DH_new" | sed 'y%./+-%__p_%'`
+
+old_LIBS="$LIBS"
+old_CPPFLAGS="$CPPFLAGS"
+smart_lib=
+smart_ldflags=
+smart_lib_dir=
+
+if test "x$smart_try_dir" != "x"; then
+ for try in $smart_try_dir; do
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for DH_new in -lcrypto in $try" >&5
+$as_echo_n "checking for DH_new in -lcrypto in $try... " >&6; }
+ LIBS="-lcrypto $old_LIBS"
+ CPPFLAGS="-L$try -Wl,-rpath,$try $old_CPPFLAGS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+extern char DH_new();
int
main ()
{
-return DH_new ();
+DH_new()
;
return 0;
}
_ACEOF
if ac_fn_c_try_link "$LINENO"; then :
- ac_cv_lib_crypto_DH_new=yes
+
+ smart_lib="-lcrypto"
+ smart_ldflags="-L$try -Wl,-rpath,$try"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+ break
+
else
- ac_cv_lib_crypto_DH_new=no
+ { $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=$ac_check_lib_save_LIBS
+ done
+ LIBS="$old_LIBS"
+ CPPFLAGS="$old_CPPFLAGS"
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_crypto_DH_new" >&5
-$as_echo "$ac_cv_lib_crypto_DH_new" >&6; }
-if test "x$ac_cv_lib_crypto_DH_new" = xyes; then :
-
- LIBS="-lcrypto $LIBS"
-
-$as_echo "#define HAVE_LIBCRYPTO 1" >>confdefs.h
- { $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 $LIBS"
-cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+if test "x$smart_lib" = "x"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for DH_new in -lcrypto" >&5
+$as_echo_n "checking for DH_new in -lcrypto... " >&6; }
+ LIBS="-lcrypto $old_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 ();
+extern char DH_new();
int
main ()
{
-return SSL_new ();
+DH_new()
;
return 0;
}
_ACEOF
if ac_fn_c_try_link "$LINENO"; then :
- ac_cv_lib_ssl_SSL_new=yes
+
+ smart_lib="-lcrypto"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+
else
- ac_cv_lib_ssl_SSL_new=no
+ { $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=$ac_check_lib_save_LIBS
+ LIBS="$old_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 :
-
-$as_echo "#define HAVE_LIBSSL 1" >>confdefs.h
+if test "x$smart_lib" = "x"; then
- if test "x$OPENSSL_LIB_DIR" != "x"; then
- OPENSSL_LIBS="-L$OPENSSL_LIB_DIR"
- fi
- OPENSSL_LIBS="$OPENSSL_LIBS -lcrypto -lssl -lcrypto"
-else
+if test "x$LOCATE" != "x"; then
+ DIRS=
+ file=libcrypto${libltdl_cv_shlibext}
- { { $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 linking to libssl
-See \`config.log' for more details" "$LINENO" 5; }
+ for x in `${LOCATE} $file 2>/dev/null`; do
+ base=`echo $x | sed "s%/${file}%%"`
+ if test "x$x" = "x$base"; then
+ continue;
+ fi
+ dir=`${DIRNAME} $x 2>/dev/null`
+ exclude=`echo ${dir} | ${GREP} /home`
+ if test "x$exclude" != "x"; then
+ continue
+ fi
+ already=`echo \$smart_lib_dir ${DIRS} | ${GREP} ${dir}`
+ if test "x$already" = "x"; then
+ DIRS="$DIRS $dir"
+ fi
+ done
fi
-
-fi
+eval "smart_lib_dir=\"\$smart_lib_dir $DIRS\""
- old_CPPFLAGS=$CPPFLAGS
- old_CFLAGS=$CFLAGS
- if test "x$OPENSSL_INCLUDE_DIR" != "x"; then
- CPPFLAGS="-isystem $OPENSSL_INCLUDE_DIR $CPPFLAGS"
- CFLAGS="-isystem $OPENSSL_INCLUDE_DIR $CFLAGS"
- fi
- CPPFLAGS="$CPPFLAGS -DOPENSSL_NO_KRB5"
- for ac_header in \
- openssl/ssl.h \
- openssl/crypto.h \
- openssl/err.h \
- openssl/evp.h \
- openssl/md5.h \
- openssl/md4.h \
- openssl/sha.h \
- openssl/ocsp.h \
- openssl/engine.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
+if test "x$LOCATE" != "x"; then
+ DIRS=
+ file=libcrypto.a
-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 $? "failed locating OpenSSL headers
-See \`config.log' for more details" "$LINENO" 5; }
+ for x in `${LOCATE} $file 2>/dev/null`; do
+ base=`echo $x | sed "s%/${file}%%"`
+ if test "x$x" = "x$base"; then
+ continue;
+ fi
+ dir=`${DIRNAME} $x 2>/dev/null`
+ exclude=`echo ${dir} | ${GREP} /home`
+ if test "x$exclude" != "x"; then
+ continue
+ fi
+ already=`echo \$smart_lib_dir ${DIRS} | ${GREP} ${dir}`
+ if test "x$already" = "x"; then
+ DIRS="$DIRS $dir"
+ fi
+ done
fi
-done
+eval "smart_lib_dir=\"\$smart_lib_dir $DIRS\""
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for OpenSSL version >= 0.9.7" >&5
-$as_echo_n "checking for OpenSSL version >= 0.9.7... " >&6; }
- cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+ for try in $smart_lib_dir /usr/local/lib /opt/lib; do
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for DH_new in -lcrypto in $try" >&5
+$as_echo_n "checking for DH_new in -lcrypto in $try... " >&6; }
+ LIBS="-lcrypto $old_LIBS"
+ CPPFLAGS="-L$try -Wl,-rpath,$try $old_CPPFLAGS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
-#include <openssl/crypto.h>
- #if (OPENSSL_VERSION_NUMBER >= 0x00907000L)
- yes
- #endif
-
+extern char DH_new();
+int
+main ()
+{
+DH_new()
+ ;
+ return 0;
+}
_ACEOF
-if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
- $EGREP "yes" >/dev/null 2>&1; then :
+if ac_fn_c_try_link "$LINENO"; then :
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+ smart_lib="-lcrypto"
+ smart_ldflags="-L$try -Wl,-rpath,$try"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
$as_echo "yes" >&6; }
+ break
else
-
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
$as_echo "no" >&6; }
- { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
-$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
-as_fn_error $? "OpenSSL version too old
-See \`config.log' for more details" "$LINENO" 5; }
-
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+ done
+ LIBS="$old_LIBS"
+ CPPFLAGS="$old_CPPFLAGS"
+fi
+if test "x$smart_lib" != "x"; then
+ eval "ac_cv_lib_${sm_lib_safe}_${sm_func_safe}=yes"
+ LIBS="$smart_ldflags $smart_lib $old_LIBS"
+ SMART_LIBS="$smart_ldflags $smart_lib $SMART_LIBS"
fi
-rm -f conftest*
+ if test "x$ac_cv_lib_crypto_DH_new" = "xyes"; then
- if test "x$OPENSSL_INCLUDE_DIR" != "x"; then
- OPENSSL_INCLUDE="-isystem $OPENSSL_INCLUDE_DIR -DOPENSSL_NO_KRB5"
- else
- OPENSSL_INCLUDE="-DOPENSSL_NO_KRB5"
- fi
+$as_echo "#define HAVE_LIBCRYPTO 1" >>confdefs.h
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking OpenSSL library and header version consistency" >&5
-$as_echo_n "checking OpenSSL library and header version consistency... " >&6; }
- if test "$cross_compiling" = yes; then :
- { { $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 test program while cross compiling
-See \`config.log' for more details" "$LINENO" 5; }
-else
- cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
+ OPENSSL_LIBS="$smart_lib"
+ OPENSSL_LDFLAGS="$smart_ldflags"
- #include <stdio.h>
- #include <openssl/opensslv.h>
- #include <openssl/crypto.h>
+
+sm_lib_safe=`echo "ssl" | sed 'y%./+-%__p_%'`
+sm_func_safe=`echo "SSL_new" | sed 'y%./+-%__p_%'`
+
+old_LIBS="$LIBS"
+old_CPPFLAGS="$CPPFLAGS"
+smart_lib=
+smart_ldflags=
+smart_lib_dir=
+
+if test "x$smart_try_dir" != "x"; then
+ for try in $smart_try_dir; do
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for SSL_new in -lssl in $try" >&5
+$as_echo_n "checking for SSL_new in -lssl in $try... " >&6; }
+ LIBS="-lssl $old_LIBS"
+ CPPFLAGS="-L$try -Wl,-rpath,$try $old_CPPFLAGS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+extern char SSL_new();
int
main ()
{
+SSL_new()
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
- if (SSLeay() == OPENSSL_VERSION_NUMBER) {
- return 0;
- } else {
- printf("library: %lx header: %lx... ", (unsigned long) SSLeay(), (unsigned long) OPENSSL_VERSION_NUMBER);
- return 1;
- }
+ smart_lib="-lssl"
+ smart_ldflags="-L$try -Wl,-rpath,$try"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+ break
+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
+ done
+ LIBS="$old_LIBS"
+ CPPFLAGS="$old_CPPFLAGS"
+fi
+if test "x$smart_lib" = "x"; 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; }
+ LIBS="-lssl $old_LIBS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+extern char SSL_new();
+int
+main ()
+{
+SSL_new()
;
return 0;
}
_ACEOF
-if ac_fn_c_try_run "$LINENO"; then :
+if ac_fn_c_try_link "$LINENO"; then :
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+ smart_lib="-lssl"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
$as_echo "yes" >&6; }
else
-
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
$as_echo "no" >&6; }
- { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
-$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
-as_fn_error $? "OpenSSL library version does not match header version
-See \`config.log' for more details" "$LINENO" 5; }
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+ LIBS="$old_LIBS"
+fi
+if test "x$smart_lib" = "x"; then
-fi
-rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
- conftest.$ac_objext conftest.beam conftest.$ac_ext
+
+if test "x$LOCATE" != "x"; then
+ DIRS=
+ file=libssl${libltdl_cv_shlibext}
+
+ for x in `${LOCATE} $file 2>/dev/null`; do
+ base=`echo $x | sed "s%/${file}%%"`
+ if test "x$x" = "x$base"; then
+ continue;
+ fi
+
+ dir=`${DIRNAME} $x 2>/dev/null`
+ exclude=`echo ${dir} | ${GREP} /home`
+ if test "x$exclude" != "x"; then
+ continue
+ fi
+
+ already=`echo \$smart_lib_dir ${DIRS} | ${GREP} ${dir}`
+ if test "x$already" = "x"; then
+ DIRS="$DIRS $dir"
+ fi
+ done
fi
+eval "smart_lib_dir=\"\$smart_lib_dir $DIRS\""
- if test "x$OPENSSL_LIBS" = x; then
- LIBS=$old_LIBS
- LDFLAGS="$old_LDFLAGS"
- fi
- if test "x$OPENSSL_INCLUDE" = x; then
- CPPFLAGS=$old_CPPFLAGS
- CFLAGS=$old_CFLAGS
- fi
+
+
+if test "x$LOCATE" != "x"; then
+ DIRS=
+ file=libssl.a
+
+ for x in `${LOCATE} $file 2>/dev/null`; do
+ base=`echo $x | sed "s%/${file}%%"`
+ if test "x$x" = "x$base"; then
+ continue;
+ fi
+
+ dir=`${DIRNAME} $x 2>/dev/null`
+ exclude=`echo ${dir} | ${GREP} /home`
+ if test "x$exclude" != "x"; then
+ continue
+ fi
+
+ already=`echo \$smart_lib_dir ${DIRS} | ${GREP} ${dir}`
+ if test "x$already" = "x"; then
+ DIRS="$DIRS $dir"
+ fi
+ done
fi
+eval "smart_lib_dir=\"\$smart_lib_dir $DIRS\""
+
+ for try in $smart_lib_dir /usr/local/lib /opt/lib; do
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for SSL_new in -lssl in $try" >&5
+$as_echo_n "checking for SSL_new in -lssl in $try... " >&6; }
+ LIBS="-lssl $old_LIBS"
+ CPPFLAGS="-L$try -Wl,-rpath,$try $old_CPPFLAGS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+extern char SSL_new();
+int
+main ()
+{
+SSL_new()
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
-export OPENSSL_LIBS
+ smart_lib="-lssl"
+ smart_ldflags="-L$try -Wl,-rpath,$try"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+ break
-if test "x$PCAP_LIBS" = x; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: skipping test for pcap.h." >&5
-$as_echo "$as_me: skipping test for pcap.h." >&6;}
else
- smart_try_dir="$pcap_include_dir"
+ { $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
+ done
+ LIBS="$old_LIBS"
+ CPPFLAGS="$old_CPPFLAGS"
+fi
+
+if test "x$smart_lib" != "x"; then
+ eval "ac_cv_lib_${sm_lib_safe}_${sm_func_safe}=yes"
+ LIBS="$smart_ldflags $smart_lib $old_LIBS"
+ SMART_LIBS="$smart_ldflags $smart_lib $SMART_LIBS"
+fi
+
+ if test "x$ac_cv_lib_ssl_SSL_new" != "xyes"; then
+ { { $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 linking to libssl. Use --with-openssl-lib-dir=<path>, or --with-openssl=no (builds without OpenSSL)
+See \`config.log' for more details" "$LINENO" 5; }
+ else
+$as_echo "#define HAVE_LIBSSL 1" >>confdefs.h
-ac_safe=`echo "pcap.h" | sed 'y%./+-%__pm%'`
-old_CFLAGS="$CFLAGS"
+ OPENSSL_LIBS="$OPENSSL_LIBS $smart_lib"
+
+ if test "$OPENSSL_LDFLAGS" != "$smart_ldflags"; then
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "\"inconsistent LDFLAGS between -lssl '$smart_ldflags' and -lcrypto '$OPENSSL_LDFLAGS'\"
+See \`config.log' for more details" "$LINENO" 5; }
+ fi
+ fi
+ 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 $? "failed linking to libcrypto. Use --with-openssl-lib-dir=<path>, or --with-openssl=no (builds without OpenSSL)
+See \`config.log' for more details" "$LINENO" 5; }
+ fi
+
+ smart_try_dir="$openssl_include_dir"
+
+
+ac_safe=`echo "openssl/ssl.h" | sed 'y%./+-%__pm%'`
+old_CPPFLAGS="$CPPFLAGS"
smart_include=
smart_include_dir=
if test "x$smart_try_dir" != "x"; then
for try in $smart_try_dir; do
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for pcap.h in $try" >&5
-$as_echo_n "checking for pcap.h in $try... " >&6; }
- CFLAGS="$old_CFLAGS -isystem $try"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for openssl/ssl.h in $try" >&5
+$as_echo_n "checking for openssl/ssl.h in $try... " >&6; }
+ CPPFLAGS="-isystem $try $old_CPPFLAGS"
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
- #include <pcap.h>
+ #include <openssl/ssl.h>
int
main ()
{
fi
rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
done
- CFLAGS="$old_CFLAGS"
+ CPPFLAGS="$old_CPPFLAGS"
fi
if test "x$smart_include" = "x"; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for pcap.h" >&5
-$as_echo_n "checking for pcap.h... " >&6; }
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for openssl/ssl.h" >&5
+$as_echo_n "checking for openssl/ssl.h... " >&6; }
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
- #include <pcap.h>
+ #include <openssl/ssl.h>
int
main ()
{
if test "x$LOCATE" != "x"; then
DIRS=
- file=pcap.h
+ file=openssl/ssl.h
for x in `${LOCATE} $file 2>/dev/null`; do
base=`echo $x | sed "s%/${file}%%"`
eval "smart_include_dir=\"\$smart_include_dir $DIRS\""
for try in $smart_include_dir /usr/local/include /opt/include; do
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for pcap.h in $try" >&5
-$as_echo_n "checking for pcap.h in $try... " >&6; }
- CFLAGS="$old_CFLAGS -isystem $try"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for openssl/ssl.h in $try" >&5
+$as_echo_n "checking for openssl/ssl.h in $try... " >&6; }
+ CPPFLAGS="-isystem $try $old_CPPFLAGS"
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
- #include <pcap.h>
+ #include <openssl/ssl.h>
int
main ()
{
fi
rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
done
- CFLAGS="$old_CFLAGS"
+ CPPFLAGS="$old_CPPFLAGS"
fi
if test "x$smart_include" != "x"; then
eval "ac_cv_header_$ac_safe=yes"
- CFLAGS="$old_CFLAGS $smart_include"
- SMART_CFLAGS="$SMART_CFLAGS $smart_include"
+ CPPFLAGS="$smart_include $old_CPPFLAGS"
+ SMART_CPPFLAGS="$smart_include $SMART_CPPFLAGS"
fi
- if test "x$ac_cv_header_pcap_h" != "xyes"; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: pcap headers not found. Use --with-pcap-include-dir=<path>." >&5
-$as_echo "$as_me: WARNING: pcap headers not found. Use --with-pcap-include-dir=<path>." >&2;}
- { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: pcap.h not found, silently disabling the RADIUS sniffer, and ARP listener." >&5
-$as_echo "$as_me: WARNING: pcap.h not found, silently disabling the RADIUS sniffer, and ARP listener." >&2;}
- else
+ if test "x$ac_cv_header_openssl_ssl_h" = "xyes"; then
-$as_echo "#define HAVE_PCAP_H 1" >>confdefs.h
+$as_echo "#define HAVE_OPENSSL_SSL_H 1" >>confdefs.h
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for pcap_fopen_offline in -lpcap" >&5
-$as_echo_n "checking for pcap_fopen_offline in -lpcap... " >&6; }
-if ${ac_cv_lib_pcap_pcap_fopen_offline+:} false; then :
- $as_echo_n "(cached) " >&6
+ for ac_header in \
+ openssl/crypto.h \
+ openssl/err.h \
+ openssl/evp.h \
+ openssl/md5.h \
+ openssl/md4.h \
+ openssl/sha.h \
+ openssl/ocsp.h \
+ openssl/engine.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
+
else
- ac_check_lib_save_LIBS=$LIBS
-LIBS="-lpcap $LIBS"
-cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+
+ { { $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 locating OpenSSL headers. Use --with-openssl-include-dir=<path>, or --with-openssl=no (builds without OpenSSL)
+See \`config.log' for more details" "$LINENO" 5; }
+
+
+fi
+
+done
+
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for OpenSSL version >= 0.9.7" >&5
+$as_echo_n "checking for OpenSSL version >= 0.9.7... " >&6; }
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
+#include <openssl/crypto.h>
+ #if (OPENSSL_VERSION_NUMBER >= 0x00907000L)
+ yes
+ #endif
-/* 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_fopen_offline ();
-int
-main ()
-{
-return pcap_fopen_offline ();
- ;
- return 0;
-}
_ACEOF
-if ac_fn_c_try_link "$LINENO"; then :
- ac_cv_lib_pcap_pcap_fopen_offline=yes
-else
- ac_cv_lib_pcap_pcap_fopen_offline=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_fopen_offline" >&5
-$as_echo "$ac_cv_lib_pcap_pcap_fopen_offline" >&6; }
-if test "x$ac_cv_lib_pcap_pcap_fopen_offline" = xyes; then :
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ $EGREP "yes" >/dev/null 2>&1; then :
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
-$as_echo "#define HAVE_PCAP_FOPEN_OFFLINE 1" >>confdefs.h
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "OpenSSL version too old
+See \`config.log' for more details" "$LINENO" 5; }
fi
+rm -f conftest*
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for pcap_dump_fopen in -lpcap" >&5
-$as_echo_n "checking for pcap_dump_fopen in -lpcap... " >&6; }
-if ${ac_cv_lib_pcap_pcap_dump_fopen+:} false; then :
- $as_echo_n "(cached) " >&6
+ old_CPPFLAGS="$CPPFLAGS"
+ CPPFLAGS="$OPENSSL_LDFLAGS $CPPFLAGS"
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking OpenSSL library and header version consistency" >&5
+$as_echo_n "checking OpenSSL library and header version consistency... " >&6; }
+ if test "$cross_compiling" = yes; then :
+ { { $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 test program while cross compiling
+See \`config.log' for more details" "$LINENO" 5; }
else
- ac_check_lib_save_LIBS=$LIBS
-LIBS="-lpcap $LIBS"
-cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+ 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_dump_fopen ();
+ #include <stdio.h>
+ #include <openssl/opensslv.h>
+ #include <openssl/crypto.h>
+
int
main ()
{
-return pcap_dump_fopen ();
+
+ printf("library: %lx header: %lx... ", (unsigned long) SSLeay(), (unsigned long) OPENSSL_VERSION_NUMBER);
+ if (SSLeay() == OPENSSL_VERSION_NUMBER) {
+ return 0;
+ } else {
+ return 1;
+ }
+
+
;
return 0;
}
_ACEOF
-if ac_fn_c_try_link "$LINENO"; then :
- ac_cv_lib_pcap_pcap_dump_fopen=yes
-else
- ac_cv_lib_pcap_pcap_dump_fopen=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_dump_fopen" >&5
-$as_echo "$ac_cv_lib_pcap_pcap_dump_fopen" >&6; }
-if test "x$ac_cv_lib_pcap_pcap_dump_fopen" = xyes; then :
+if ac_fn_c_try_run "$LINENO"; then :
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
-$as_echo "#define HAVE_PCAP_DUMP_FOPEN 1" >>confdefs.h
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "OpenSSL library version does not match header version
+See \`config.log' for more details" "$LINENO" 5; }
fi
-
- fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
+ conftest.$ac_objext conftest.beam conftest.$ac_ext
fi
+ CPPFLAGS="$old_CPPFLAGS"
+ fi
+ LIBS="$OLD_LIBS"
-ac_fn_c_check_type "$LINENO" "off_t" "ac_cv_type_off_t" "$ac_includes_default"
-if test "x$ac_cv_type_off_t" = xyes; then :
-
-else
-
-cat >>confdefs.h <<_ACEOF
-#define off_t long int
-_ACEOF
+ export OPENSSL_LIBS OPENSSL_LDFLAGS
fi
-ac_fn_c_check_type "$LINENO" "pid_t" "ac_cv_type_pid_t" "$ac_includes_default"
-if test "x$ac_cv_type_pid_t" = xyes; then :
-
+if test "x$PCAP_LIBS" = x; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: skipping test for pcap.h." >&5
+$as_echo "$as_me: skipping test for pcap.h." >&6;}
else
+ smart_try_dir="$pcap_include_dir"
-cat >>confdefs.h <<_ACEOF
-#define pid_t int
-_ACEOF
-
-fi
-ac_fn_c_check_type "$LINENO" "size_t" "ac_cv_type_size_t" "$ac_includes_default"
-if test "x$ac_cv_type_size_t" = xyes; then :
+ac_safe=`echo "pcap.h" | sed 'y%./+-%__pm%'`
+old_CPPFLAGS="$CPPFLAGS"
+smart_include=
+smart_include_dir=
-else
+if test "x$smart_try_dir" != "x"; then
+ for try in $smart_try_dir; do
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for pcap.h in $try" >&5
+$as_echo_n "checking for pcap.h in $try... " >&6; }
+ CPPFLAGS="-isystem $try $old_CPPFLAGS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
-cat >>confdefs.h <<_ACEOF
-#define size_t unsigned int
+ #include <pcap.h>
+int
+main ()
+{
+int a = 1;
+ ;
+ return 0;
+}
_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
-fi
+ smart_include="-isystem $try"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+ break
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for uid_t in sys/types.h" >&5
-$as_echo_n "checking for uid_t in sys/types.h... " >&6; }
-if ${ac_cv_type_uid_t+:} false; then :
- $as_echo_n "(cached) " >&6
else
- cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-#include <sys/types.h>
-_ACEOF
-if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
- $EGREP "uid_t" >/dev/null 2>&1; then :
- ac_cv_type_uid_t=yes
-else
- ac_cv_type_uid_t=no
-fi
-rm -f conftest*
+ smart_include=
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_type_uid_t" >&5
-$as_echo "$ac_cv_type_uid_t" >&6; }
-if test $ac_cv_type_uid_t = no; then
-
-$as_echo "#define uid_t int" >>confdefs.h
-
-
-$as_echo "#define gid_t int" >>confdefs.h
-
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ done
+ CPPFLAGS="$old_CPPFLAGS"
fi
-
-
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for socklen_t" >&5
-$as_echo_n "checking for socklen_t... " >&6; }
-if ${ac_cv_type_socklen_t+:} false; then :
- $as_echo_n "(cached) " >&6
-else
- ac_cv_type_socklen_t=no
- cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+if test "x$smart_include" = "x"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for pcap.h" >&5
+$as_echo_n "checking for pcap.h... " >&6; }
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
-#ifdef HAVE_SYS_TYPES_H
- # include <sys/types.h>
- #endif
-
- #ifdef HAVE_SYS_SOCKET_H
- # include <sys/socket.h>
- #endif
+ #include <pcap.h>
int
main ()
{
-socklen_t foo
+int a = 1;
;
return 0;
}
_ACEOF
if ac_fn_c_try_compile "$LINENO"; then :
- ac_cv_type_socklen_t=yes
+
+ smart_include=" "
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+ break
+
+else
+
+ smart_include=
+ { $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_ext
+fi
+if test "x$smart_include" = "x"; then
-fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_type_socklen_t" >&5
-$as_echo "$ac_cv_type_socklen_t" >&6; }
- if test "$ac_cv_type_socklen_t" != "yes"; then
+if test "x$LOCATE" != "x"; then
+ DIRS=
+ file=pcap.h
-$as_echo "#define socklen_t int" >>confdefs.h
+ for x in `${LOCATE} $file 2>/dev/null`; do
+ base=`echo $x | sed "s%/${file}%%"`
+ if test "x$x" = "x$base"; then
+ continue;
+ fi
- fi
+ dir=`${DIRNAME} $x 2>/dev/null`
+ exclude=`echo ${dir} | ${GREP} /home`
+ if test "x$exclude" != "x"; then
+ continue
+ fi
+ already=`echo \$smart_include_dir ${DIRS} | ${GREP} ${dir}`
+ if test "x$already" = "x"; then
+ DIRS="$DIRS $dir"
+ fi
+ done
+fi
+eval "smart_include_dir=\"\$smart_include_dir $DIRS\""
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for uint8_t" >&5
-$as_echo_n "checking for uint8_t... " >&6; }
-if ${ac_cv_type_uint8_t+:} false; then :
- $as_echo_n "(cached) " >&6
-else
- ac_cv_type_uint8_t=no
- cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+ for try in $smart_include_dir /usr/local/include /opt/include; do
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for pcap.h in $try" >&5
+$as_echo_n "checking for pcap.h in $try... " >&6; }
+ CPPFLAGS="-isystem $try $old_CPPFLAGS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
-#ifdef HAVE_INTTYPES_H
- # include <inttypes.h>
- #endif
-
- #ifdef HAVE_STDINT_H
- # include <stdint.h>
- #endif
+ #include <pcap.h>
int
main ()
{
-uint8_t foo
+int a = 1;
;
return 0;
}
_ACEOF
if ac_fn_c_try_compile "$LINENO"; then :
- ac_cv_type_uint8_t=yes
+
+ smart_include="-isystem $try"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+ break
+
+else
+
+ smart_include=
+ { $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_ext
+ done
+ CPPFLAGS="$old_CPPFLAGS"
+fi
-
+if test "x$smart_include" != "x"; then
+ eval "ac_cv_header_$ac_safe=yes"
+ CPPFLAGS="$smart_include $old_CPPFLAGS"
+ SMART_CPPFLAGS="$smart_include $SMART_CPPFLAGS"
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_type_uint8_t" >&5
-$as_echo "$ac_cv_type_uint8_t" >&6; }
- if test "$ac_cv_type_uint8_t" != "yes"; then
+ if test "x$ac_cv_header_pcap_h" == "xyes"; then
-$as_echo "#define uint8_t unsigned char" >>confdefs.h
+$as_echo "#define HAVE_PCAP_H 1" >>confdefs.h
- fi
+ else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: pcap headers not found, silently disabling the RADIUS sniffer, and ARP listener. Use --with-pcap-include-dir=<path>." >&5
+$as_echo "$as_me: WARNING: pcap headers not found, silently disabling the RADIUS sniffer, and ARP listener. Use --with-pcap-include-dir=<path>." >&2;}
+ fi
+fi
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for uint16_t" >&5
-$as_echo_n "checking for uint16_t... " >&6; }
-if ${ac_cv_type_uint16_t+:} false; then :
- $as_echo_n "(cached) " >&6
+if test "x$COLLECTDC_LIBS" = x; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: skipping test for collectd/client.h." >&5
+$as_echo "$as_me: skipping test for collectd/client.h." >&6;}
else
- ac_cv_type_uint16_t=no
- cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-#ifdef HAVE_INTTYPES_H
- # include <inttypes.h>
- #endif
+ smart_try_dir="$collectdclient_include_dir"
- #ifdef HAVE_STDINT_H
- # include <stdint.h>
- #endif
+ac_safe=`echo "collectd/client.h" | sed 'y%./+-%__pm%'`
+old_CPPFLAGS="$CPPFLAGS"
+smart_include=
+smart_include_dir=
+
+if test "x$smart_try_dir" != "x"; then
+ for try in $smart_try_dir; do
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for collectd/client.h in $try" >&5
+$as_echo_n "checking for collectd/client.h in $try... " >&6; }
+ CPPFLAGS="-isystem $try $old_CPPFLAGS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ #include <collectd/client.h>
int
main ()
{
-uint16_t foo
+int a = 1;
;
return 0;
}
_ACEOF
if ac_fn_c_try_compile "$LINENO"; then :
- ac_cv_type_uint16_t=yes
+
+ smart_include="-isystem $try"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+ break
+
+else
+
+ smart_include=
+ { $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_ext
+ done
+ CPPFLAGS="$old_CPPFLAGS"
+fi
+
+if test "x$smart_include" = "x"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for collectd/client.h" >&5
+$as_echo_n "checking for collectd/client.h... " >&6; }
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ #include <collectd/client.h>
+int
+main ()
+{
+int a = 1;
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+
+ smart_include=" "
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+ break
+
+else
+ smart_include=
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_type_uint16_t" >&5
-$as_echo "$ac_cv_type_uint16_t" >&6; }
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
- if test "$ac_cv_type_uint16_t" != "yes"; then
+if test "x$smart_include" = "x"; then
-$as_echo "#define uint16_t unsigned short" >>confdefs.h
- fi
+if test "x$LOCATE" != "x"; then
+ DIRS=
+ file=collectd/client.h
+ for x in `${LOCATE} $file 2>/dev/null`; do
+ base=`echo $x | sed "s%/${file}%%"`
+ if test "x$x" = "x$base"; then
+ continue;
+ fi
+ dir=`${DIRNAME} $x 2>/dev/null`
+ exclude=`echo ${dir} | ${GREP} /home`
+ if test "x$exclude" != "x"; then
+ continue
+ fi
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for uint32_t" >&5
-$as_echo_n "checking for uint32_t... " >&6; }
-if ${ac_cv_type_uint32_t+:} false; then :
- $as_echo_n "(cached) " >&6
-else
- ac_cv_type_uint32_t=no
- cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-#ifdef HAVE_INTTYPES_H
- # include <inttypes.h>
- #endif
+ already=`echo \$smart_include_dir ${DIRS} | ${GREP} ${dir}`
+ if test "x$already" = "x"; then
+ DIRS="$DIRS $dir"
+ fi
+ done
+fi
- #ifdef HAVE_STDINT_H
- # include <stdint.h>
- #endif
+eval "smart_include_dir=\"\$smart_include_dir $DIRS\""
+
+ for try in $smart_include_dir /usr/local/include /opt/include; do
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for collectd/client.h in $try" >&5
+$as_echo_n "checking for collectd/client.h in $try... " >&6; }
+ CPPFLAGS="-isystem $try $old_CPPFLAGS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+ #include <collectd/client.h>
int
main ()
{
-uint32_t foo
+int a = 1;
;
return 0;
}
_ACEOF
if ac_fn_c_try_compile "$LINENO"; then :
- ac_cv_type_uint32_t=yes
+
+ smart_include="-isystem $try"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+ break
+
+else
+
+ smart_include=
+ { $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_ext
+ done
+ CPPFLAGS="$old_CPPFLAGS"
+fi
-
+if test "x$smart_include" != "x"; then
+ eval "ac_cv_header_$ac_safe=yes"
+ CPPFLAGS="$smart_include $old_CPPFLAGS"
+ SMART_CPPFLAGS="$smart_include $SMART_CPPFLAGS"
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_type_uint32_t" >&5
-$as_echo "$ac_cv_type_uint32_t" >&6; }
- if test "$ac_cv_type_uint32_t" != "yes"; then
+ if test "x$ac_cv_header_collectd_client_h" == "xyes"; then
+
+$as_echo "#define HAVE_COLLECTDC_H 1" >>confdefs.h
-$as_echo "#define uint32_t unsigned int" >>confdefs.h
+
+ else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: collectdclient headers not found. Use --with-collectdclient-include-dir=<path>." >&5
+$as_echo "$as_me: WARNING: collectdclient headers not found. Use --with-collectdclient-include-dir=<path>." >&2;}
fi
+fi
+ac_fn_c_check_type "$LINENO" "off_t" "ac_cv_type_off_t" "$ac_includes_default"
+if test "x$ac_cv_type_off_t" = xyes; then :
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for uint64_t" >&5
-$as_echo_n "checking for uint64_t... " >&6; }
-if ${ac_cv_type_uint64_t+:} false; then :
+else
+
+cat >>confdefs.h <<_ACEOF
+#define off_t long int
+_ACEOF
+
+fi
+
+ac_fn_c_check_type "$LINENO" "pid_t" "ac_cv_type_pid_t" "$ac_includes_default"
+if test "x$ac_cv_type_pid_t" = xyes; then :
+
+else
+
+cat >>confdefs.h <<_ACEOF
+#define pid_t int
+_ACEOF
+
+fi
+
+ac_fn_c_check_type "$LINENO" "size_t" "ac_cv_type_size_t" "$ac_includes_default"
+if test "x$ac_cv_type_size_t" = xyes; then :
+
+else
+
+cat >>confdefs.h <<_ACEOF
+#define size_t unsigned int
+_ACEOF
+
+fi
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for uid_t in sys/types.h" >&5
+$as_echo_n "checking for uid_t in sys/types.h... " >&6; }
+if ${ac_cv_type_uid_t+:} false; then :
$as_echo_n "(cached) " >&6
else
- ac_cv_type_uint64_t=no
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <sys/types.h>
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ $EGREP "uid_t" >/dev/null 2>&1; then :
+ ac_cv_type_uid_t=yes
+else
+ ac_cv_type_uid_t=no
+fi
+rm -f conftest*
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_type_uid_t" >&5
+$as_echo "$ac_cv_type_uid_t" >&6; }
+if test $ac_cv_type_uid_t = no; then
+
+$as_echo "#define uid_t int" >>confdefs.h
+
+
+$as_echo "#define gid_t int" >>confdefs.h
+
+fi
+
+
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for socklen_t" >&5
+$as_echo_n "checking for socklen_t... " >&6; }
+if ${ac_cv_type_socklen_t+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_cv_type_socklen_t=no
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
-#ifdef HAVE_INTTYPES_H
- # include <inttypes.h>
+#ifdef HAVE_SYS_TYPES_H
+ # include <sys/types.h>
#endif
- #ifdef HAVE_STDINT_H
- # include <stdint.h>
+ #ifdef HAVE_SYS_SOCKET_H
+ # include <sys/socket.h>
#endif
int
main ()
{
-uint64_t foo
+socklen_t foo
;
return 0;
}
_ACEOF
if ac_fn_c_try_compile "$LINENO"; then :
- ac_cv_type_uint64_t=yes
+ ac_cv_type_socklen_t=yes
fi
rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_type_uint64_t" >&5
-$as_echo "$ac_cv_type_uint64_t" >&6; }
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_type_socklen_t" >&5
+$as_echo "$ac_cv_type_socklen_t" >&6; }
- if test "$ac_cv_type_uint64_t" != "yes"; then
+ if test "$ac_cv_type_socklen_t" != "yes"; then
-$as_echo "#define uint64_t unsigned long long" >>confdefs.h
+$as_echo "#define socklen_t int" >>confdefs.h
fi
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for sig_t" >&5
-$as_echo_n "checking for sig_t... " >&6; }
-if ${ac_cv_type_sig_t+:} false; then :
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for uint8_t" >&5
+$as_echo_n "checking for uint8_t... " >&6; }
+if ${ac_cv_type_uint8_t+:} false; then :
$as_echo_n "(cached) " >&6
else
- ac_cv_type_sig_t=no
+ ac_cv_type_uint8_t=no
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
-#ifdef HAVE_SIGNAL_H
- # include <signal.h>
+#ifdef HAVE_INTTYPES_H
+ # include <inttypes.h>
+ #endif
+
+ #ifdef HAVE_STDINT_H
+ # include <stdint.h>
#endif
int
main ()
{
-sig_t foo
+uint8_t foo
;
return 0;
}
_ACEOF
if ac_fn_c_try_compile "$LINENO"; then :
- ac_cv_type_sig_t=yes
+ ac_cv_type_uint8_t=yes
fi
rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_type_sig_t" >&5
-$as_echo "$ac_cv_type_sig_t" >&6; }
-
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_type_uint8_t" >&5
+$as_echo "$ac_cv_type_uint8_t" >&6; }
+
+ if test "$ac_cv_type_uint8_t" != "yes"; then
+
+$as_echo "#define uint8_t unsigned char" >>confdefs.h
+
+ fi
+
+
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for uint16_t" >&5
+$as_echo_n "checking for uint16_t... " >&6; }
+if ${ac_cv_type_uint16_t+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_cv_type_uint16_t=no
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#ifdef HAVE_INTTYPES_H
+ # include <inttypes.h>
+ #endif
+
+ #ifdef HAVE_STDINT_H
+ # include <stdint.h>
+ #endif
+
+int
+main ()
+{
+uint16_t foo
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ac_cv_type_uint16_t=yes
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_type_uint16_t" >&5
+$as_echo "$ac_cv_type_uint16_t" >&6; }
+
+ if test "$ac_cv_type_uint16_t" != "yes"; then
+
+$as_echo "#define uint16_t unsigned short" >>confdefs.h
+
+ fi
+
+
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for uint32_t" >&5
+$as_echo_n "checking for uint32_t... " >&6; }
+if ${ac_cv_type_uint32_t+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_cv_type_uint32_t=no
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#ifdef HAVE_INTTYPES_H
+ # include <inttypes.h>
+ #endif
+
+ #ifdef HAVE_STDINT_H
+ # include <stdint.h>
+ #endif
+
+int
+main ()
+{
+uint32_t foo
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ac_cv_type_uint32_t=yes
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_type_uint32_t" >&5
+$as_echo "$ac_cv_type_uint32_t" >&6; }
+
+ if test "$ac_cv_type_uint32_t" != "yes"; then
+
+$as_echo "#define uint32_t unsigned int" >>confdefs.h
+
+ fi
+
+
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for uint64_t" >&5
+$as_echo_n "checking for uint64_t... " >&6; }
+if ${ac_cv_type_uint64_t+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_cv_type_uint64_t=no
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#ifdef HAVE_INTTYPES_H
+ # include <inttypes.h>
+ #endif
+
+ #ifdef HAVE_STDINT_H
+ # include <stdint.h>
+ #endif
+
+int
+main ()
+{
+uint64_t foo
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ac_cv_type_uint64_t=yes
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_type_uint64_t" >&5
+$as_echo "$ac_cv_type_uint64_t" >&6; }
+
+ if test "$ac_cv_type_uint64_t" != "yes"; then
+
+$as_echo "#define uint64_t unsigned long long" >>confdefs.h
+
+ fi
+
+
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for sig_t" >&5
+$as_echo_n "checking for sig_t... " >&6; }
+if ${ac_cv_type_sig_t+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_cv_type_sig_t=no
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#ifdef HAVE_SIGNAL_H
+ # include <signal.h>
+ #endif
+
+int
+main ()
+{
+sig_t foo
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ac_cv_type_sig_t=yes
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_type_sig_t" >&5
+$as_echo "$ac_cv_type_sig_t" >&6; }
+
if test "$ac_cv_type_sig_t" != "yes"; then
$as_echo "#define sig_t void(*sig_t)(int)" >>confdefs.h
$as_echo "$as_me: Setting additional developer CFLAGS" >&6;}
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for the compiler flag \"-Wdocumentation\"" >&5
-$as_echo_n "checking for the compiler flag \"-Wdocumentation\"... " >&6; }
-if ${ax_cv_cc_wdocumentation_flag+:} false; then :
- $as_echo_n "(cached) " >&6
-else
-
-
- CFLAGS_SAVED=$CFLAGS
- CFLAGS="$CFLAGS -Werror -Wdocumentation"
-
- 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
-
- cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-
-int
-main ()
-{
-return 0;
- ;
- return 0;
-}
-_ACEOF
-if ac_fn_c_try_compile "$LINENO"; then :
- ax_cv_cc_wdocumentation_flag="yes"
-else
- ax_cv_cc_wdocumentation_flag="no"
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
- 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
-
-
- CFLAGS="$CFLAGS_SAVED"
-
-fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ax_cv_cc_wdocumentation_flag" >&5
-$as_echo "$ax_cv_cc_wdocumentation_flag" >&6; }
-
- if test "x$ax_cv_cc_wdocumentation_flag" = "xyes"; then
- devflags="-Wdocumentation"
- fi
-
- if test "x$GCC" = "xyes"; then
- devflags="$devflags -Wshadow -Wpointer-arith -Wcast-qual -Wcast-align -Wwrite-strings -Wstrict-prototypes -Wmissing-prototypes -Wmissing-declarations -Wnested-externs -W -Wredundant-decls -Wundef -Wformat-y2k -Wno-format-extra-args -Wno-format-zero-length -Wno-cast-align -Wformat-nonliteral -Wformat-security -Wformat=2 -DWITH_VERIFY_PTR=1"
- INSTALLSTRIP=""
- fi
-
- { $as_echo "$as_me:${as_lineno-$LINENO}: Developer CFLAGS are \"$devflags\"" >&5
-$as_echo "$as_me: Developer CFLAGS are \"$devflags\"" >&6;}
-
- CFLAGS="$CFLAGS $devflags"
- if test "x$EXPERIMENTAL" != "xno"; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: is developer build, enabling experimental modules implicitly, disable with --without-experimental-modules" >&5
-$as_echo "$as_me: is developer build, enabling experimental modules implicitly, disable with --without-experimental-modules" >&6;}
- EXPERIMENTAL=yes
- fi
-else
- devflags=""
- CFLAGS="$CFLAGS -DNDEBUG"
- INSTALLSTRIP=""
-fi
-
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if building with -DNDEBUG" >&5
-$as_echo_n "checking if building with -DNDEBUG... " >&6; }
-if echo "$CFLAGS" | grep '\-DNDEBUG' > /dev/null; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-
-$as_echo "#define WITH_NDEBUG 1" >>confdefs.h
-
-else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-fi
-
-export EXPERIMENTAL
-
-if test -d $srcdir/.git -a "x$GIT" = "xyes"; then
- RADIUSD_VERSION_COMMIT=`git log --pretty=format:'%h' -n 1`
-
-cat >>confdefs.h <<_ACEOF
-#define RADIUSD_VERSION_COMMIT ${RADIUSD_VERSION_COMMIT}
-_ACEOF
-
-fi
-
-
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for __thread support in compiler" >&5
-$as_echo_n "checking for __thread support in compiler... " >&6; }
- if test "$cross_compiling" = yes; then :
- have_tls=no
-else
- cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-
- static __thread int val;
- int main(int argc, char **argv) {
- val = 0;
- return val;
- }
-
-
-_ACEOF
-if ac_fn_c_try_run "$LINENO"; then :
- have_tls=yes
-else
- have_tls=no
-fi
-rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
- conftest.$ac_objext conftest.beam conftest.$ac_ext
-fi
-
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $have_tls" >&5
-$as_echo "$have_tls" >&6; }
- if test "x$have_tls" = "xyes"; then
-
-$as_echo "#define HAVE_THREAD_TLS 1" >>confdefs.h
-
- fi
-
-
-
-talloc_include_dir=
-
-# Check whether --with-talloc-include-dir was given.
-if test "${with_talloc_include_dir+set}" = set; then :
- withval=$with_talloc_include_dir; case "$withval" in
- no)
- as_fn_error $? "Need talloc-include-dir" "$LINENO" 5
- ;;
- yes)
- ;;
- *)
- talloc_include_dir="$withval"
- ;;
- esac
-fi
-
-
-talloc_lib_dir=
-
-# Check whether --with-talloc-lib-dir was given.
-if test "${with_talloc_lib_dir+set}" = set; then :
- withval=$with_talloc_lib_dir; case "$withval" in
- no)
- as_fn_error $? "Need talloc-lib-dir" "$LINENO" 5
- ;;
- yes)
- ;;
- *)
- talloc_lib_dir="$withval"
- ;;
- esac
-fi
-
-
-pcap_include_dir=
-
-# Check whether --with-pcap-include-dir was given.
-if test "${with_pcap_include_dir+set}" = set; then :
- withval=$with_pcap_include_dir; case "$withval" in
- no)
- as_fn_error $? "Need pcap-include-dir" "$LINENO" 5
- ;;
- yes)
- ;;
- *)
- pcap_include_dir="$withval"
- ;;
- esac
-fi
-
-
-pcap_lib_dir=
-
-# Check whether --with-pcap-lib-dir was given.
-if test "${with_pcap_lib_dir+set}" = set; then :
- withval=$with_pcap_lib_dir; case "$withval" in
- no)
- as_fn_error $? "Need pcap-lib-dir" "$LINENO" 5
- ;;
- yes)
- ;;
- *)
- pcap_lib_dir="$withval"
- ;;
- esac
-fi
-
-
-smart_try_dir="$talloc_include_dir"
-
-
-ac_safe=`echo "talloc.h" | sed 'y%./+-%__pm%'`
-old_CFLAGS="$CFLAGS"
-smart_include=
-smart_include_dir=
-
-if test "x$smart_try_dir" != "x"; then
- for try in $smart_try_dir; do
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for talloc.h in $try" >&5
-$as_echo_n "checking for talloc.h in $try... " >&6; }
- CFLAGS="$old_CFLAGS -isystem $try"
- cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-
- #include <talloc.h>
-int
-main ()
-{
-int a = 1;
- ;
- return 0;
-}
-_ACEOF
-if ac_fn_c_try_compile "$LINENO"; then :
-
- smart_include="-isystem $try"
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
- break
-
-else
-
- smart_include=
- { $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_ext
- done
- CFLAGS="$old_CFLAGS"
-fi
-
-if test "x$smart_include" = "x"; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for talloc.h" >&5
-$as_echo_n "checking for talloc.h... " >&6; }
- cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-
- #include <talloc.h>
-int
-main ()
-{
-int a = 1;
- ;
- return 0;
-}
-_ACEOF
-if ac_fn_c_try_compile "$LINENO"; then :
-
- smart_include=" "
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
- break
-
-else
-
- smart_include=
- { $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_ext
-fi
-
-if test "x$smart_include" = "x"; then
-
-
-if test "x$LOCATE" != "x"; then
- DIRS=
- file=talloc.h
-
- for x in `${LOCATE} $file 2>/dev/null`; do
- base=`echo $x | sed "s%/${file}%%"`
- if test "x$x" = "x$base"; then
- continue;
- fi
-
- dir=`${DIRNAME} $x 2>/dev/null`
- exclude=`echo ${dir} | ${GREP} /home`
- if test "x$exclude" != "x"; then
- continue
- fi
-
- already=`echo \$smart_include_dir ${DIRS} | ${GREP} ${dir}`
- if test "x$already" = "x"; then
- DIRS="$DIRS $dir"
- fi
- done
-fi
-
-eval "smart_include_dir=\"\$smart_include_dir $DIRS\""
-
- for try in $smart_include_dir /usr/local/include /opt/include; do
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for talloc.h in $try" >&5
-$as_echo_n "checking for talloc.h in $try... " >&6; }
- CFLAGS="$old_CFLAGS -isystem $try"
- cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-
- #include <talloc.h>
-int
-main ()
-{
-int a = 1;
- ;
- return 0;
-}
-_ACEOF
-if ac_fn_c_try_compile "$LINENO"; then :
-
- smart_include="-isystem $try"
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
- break
-
-else
-
- smart_include=
- { $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_ext
- done
- CFLAGS="$old_CFLAGS"
-fi
-
-if test "x$smart_include" != "x"; then
- eval "ac_cv_header_$ac_safe=yes"
- CFLAGS="$old_CFLAGS $smart_include"
- SMART_CFLAGS="$SMART_CFLAGS $smart_include"
-fi
-
-if test "x$ac_cv_header_talloc_h" != "xyes"; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: talloc headers not found. Use --with-talloc-include-dir=<path>." >&5
-$as_echo "$as_me: WARNING: talloc headers not found. Use --with-talloc-include-dir=<path>." >&2;}
- as_fn_error $? "FreeRADIUS requires libtalloc" "$LINENO" 5
-fi
-
-smart_try_dir="$talloc_lib_dir"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for the compiler flag \"-Wdocumentation\"" >&5
+$as_echo_n "checking for the compiler flag \"-Wdocumentation\"... " >&6; }
+if ${ax_cv_cc_wdocumentation_flag+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
-sm_lib_safe=`echo "talloc" | sed 'y%./+-%__p_%'`
-sm_func_safe=`echo "_talloc" | sed 'y%./+-%__p_%'`
+ CFLAGS_SAVED=$CFLAGS
+ CFLAGS="$CFLAGS -Werror -Wdocumentation"
-old_LIBS="$LIBS"
-smart_lib=
-smart_lib_dir=
+ 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 "x$smart_try_dir" != "x"; then
- for try in $smart_try_dir; do
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _talloc in -ltalloc in $try" >&5
-$as_echo_n "checking for _talloc in -ltalloc in $try... " >&6; }
- LIBS="-L$try -ltalloc $old_LIBS -Wl,-rpath,$try"
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
-extern char _talloc();
+
int
main ()
{
-_talloc()
+return 0;
;
return 0;
}
_ACEOF
-if ac_fn_c_try_link "$LINENO"; then :
+if ac_fn_c_try_compile "$LINENO"; then :
+ ax_cv_cc_wdocumentation_flag="yes"
+else
+ ax_cv_cc_wdocumentation_flag="no"
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ 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
- smart_lib="-L$try -ltalloc -Wl,-rpath,$try"
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+
+ CFLAGS="$CFLAGS_SAVED"
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ax_cv_cc_wdocumentation_flag" >&5
+$as_echo "$ax_cv_cc_wdocumentation_flag" >&6; }
+
+ if test "x$ax_cv_cc_wdocumentation_flag" = "xyes"; then
+ devflags="-Wdocumentation"
+ fi
+
+ if test "x$GCC" = "xyes"; then
+ devflags="$devflags -Wshadow -Wpointer-arith -Wcast-qual -Wcast-align -Wwrite-strings -Wstrict-prototypes -Wmissing-prototypes -Wmissing-declarations -Wnested-externs -W -Wredundant-decls -Wundef -Wformat-y2k -Wno-format-extra-args -Wno-format-zero-length -Wno-cast-align -Wformat-nonliteral -Wformat-security -Wformat=2 -DWITH_VERIFY_PTR=1"
+ INSTALLSTRIP=""
+ fi
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: Developer CFLAGS are \"$devflags\"" >&5
+$as_echo "$as_me: Developer CFLAGS are \"$devflags\"" >&6;}
+
+ CFLAGS="$CFLAGS $devflags"
+ if test "x$EXPERIMENTAL" != "xno"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: is developer build, enabling experimental modules implicitly, disable with --without-experimental-modules" >&5
+$as_echo "$as_me: is developer build, enabling experimental modules implicitly, disable with --without-experimental-modules" >&6;}
+ EXPERIMENTAL=yes
+ fi
+else
+ devflags=""
+ CFLAGS="$CFLAGS -DNDEBUG"
+ INSTALLSTRIP=""
+fi
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if building with -DNDEBUG" >&5
+$as_echo_n "checking if building with -DNDEBUG... " >&6; }
+if echo "$CFLAGS" | grep '\-DNDEBUG' > /dev/null; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
$as_echo "yes" >&6; }
- break
+
+$as_echo "#define WITH_NDEBUG 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
- done
- LIBS="$old_LIBS"
+
+export EXPERIMENTAL
+
+if test -d $srcdir/.git -a "x$GIT" = "xyes"; then
+ RADIUSD_VERSION_COMMIT=`git log --pretty=format:'%h' -n 1`
+
+cat >>confdefs.h <<_ACEOF
+#define RADIUSD_VERSION_COMMIT ${RADIUSD_VERSION_COMMIT}
+_ACEOF
+
fi
-if test "x$smart_lib" = "x"; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _talloc in -ltalloc" >&5
-$as_echo_n "checking for _talloc in -ltalloc... " >&6; }
- LIBS="-ltalloc $old_LIBS"
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for __thread support in compiler" >&5
+$as_echo_n "checking for __thread support in compiler... " >&6; }
+ if test "$cross_compiling" = yes; then :
+ have_tls=no
+else
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
-extern char _talloc();
-int
-main ()
-{
-_talloc()
- ;
- return 0;
-}
-_ACEOF
-if ac_fn_c_try_link "$LINENO"; then :
- smart_lib="-ltalloc"
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
+ static __thread int val;
+ int main(int argc, char **argv) {
+ val = 0;
+ return val;
+ }
+
+_ACEOF
+if ac_fn_c_try_run "$LINENO"; then :
+ have_tls=yes
else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+ have_tls=no
fi
-rm -f core conftest.err conftest.$ac_objext \
- conftest$ac_exeext conftest.$ac_ext
- LIBS="$old_LIBS"
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
+ conftest.$ac_objext conftest.beam conftest.$ac_ext
fi
-if test "x$smart_lib" = "x"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $have_tls" >&5
+$as_echo "$have_tls" >&6; }
+ if test "x$have_tls" = "xyes"; then
+$as_echo "#define TLS_STORAGE_CLASS __thread" >>confdefs.h
-if test "x$LOCATE" != "x"; then
- DIRS=
- file=libtalloc${libltdl_cv_shlibext}
+ fi
- for x in `${LOCATE} $file 2>/dev/null`; do
- base=`echo $x | sed "s%/${file}%%"`
- if test "x$x" = "x$base"; then
- continue;
- fi
+ if test "x$have_tls" = "xno"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for __declspec(thread) support in compiler" >&5
+$as_echo_n "checking for __declspec(thread) support in compiler... " >&6; }
+ if test "$cross_compiling" = yes; then :
+ have_tls=no
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
- dir=`${DIRNAME} $x 2>/dev/null`
- exclude=`echo ${dir} | ${GREP} /home`
- if test "x$exclude" != "x"; then
- continue
- fi
+ static _Thread_local int val;
+ int main(int argc, char **argv) {
+ val = 0;
+ return val;
+ }
- already=`echo \$smart_lib_dir ${DIRS} | ${GREP} ${dir}`
- if test "x$already" = "x"; then
- DIRS="$DIRS $dir"
- fi
- done
+
+_ACEOF
+if ac_fn_c_try_run "$LINENO"; then :
+ have_tls=yes
+else
+ have_tls=no
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
+ conftest.$ac_objext conftest.beam conftest.$ac_ext
fi
-eval "smart_lib_dir=\"\$smart_lib_dir $DIRS\""
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $have_tls" >&5
+$as_echo "$have_tls" >&6; }
+ if test "x$have_tls" = "xyes"; then
+$as_echo "#define TLS_STORAGE_CLASS __declspec(thread)" >>confdefs.h
+ fi
+ fi
+ if test "x$have_tls" = "xno"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _Thread_local support in compiler" >&5
+$as_echo_n "checking for _Thread_local support in compiler... " >&6; }
+ if test "$cross_compiling" = yes; then :
+ have_tls=no
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
-if test "x$LOCATE" != "x"; then
- DIRS=
- file=libtalloc.a
+ static _Thread_local int val;
+ int main(int argc, char **argv) {
+ val = 0;
+ return val;
+ }
- for x in `${LOCATE} $file 2>/dev/null`; do
- base=`echo $x | sed "s%/${file}%%"`
- if test "x$x" = "x$base"; then
- continue;
- fi
- dir=`${DIRNAME} $x 2>/dev/null`
- exclude=`echo ${dir} | ${GREP} /home`
- if test "x$exclude" != "x"; then
- continue
- fi
+_ACEOF
+if ac_fn_c_try_run "$LINENO"; then :
+ have_tls=yes
+else
+ have_tls=no
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
+ conftest.$ac_objext conftest.beam conftest.$ac_ext
+fi
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $have_tls" >&5
+$as_echo "$have_tls" >&6; }
+ if test "x$have_tls" = "xyes"; then
+
+$as_echo "#define TLS_STORAGE_CLASS _Thread_local" >>confdefs.h
- already=`echo \$smart_lib_dir ${DIRS} | ${GREP} ${dir}`
- if test "x$already" = "x"; then
- DIRS="$DIRS $dir"
fi
- done
-fi
+ fi
-eval "smart_lib_dir=\"\$smart_lib_dir $DIRS\""
- for try in $smart_lib_dir /usr/local/lib /opt/lib; do
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _talloc in -ltalloc in $try" >&5
-$as_echo_n "checking for _talloc in -ltalloc in $try... " >&6; }
- LIBS="-L$try -ltalloc $old_LIBS -Wl,-rpath,$try"
- cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for talloc_set_memlimit in -ltalloc" >&5
+$as_echo_n "checking for talloc_set_memlimit in -ltalloc... " >&6; }
+if ${ac_cv_lib_talloc_talloc_set_memlimit+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-ltalloc $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
-extern char _talloc();
+
+/* 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 talloc_set_memlimit ();
int
main ()
{
-_talloc()
+return talloc_set_memlimit ();
;
return 0;
}
_ACEOF
if ac_fn_c_try_link "$LINENO"; then :
-
- smart_lib="-L$try -ltalloc -Wl,-rpath,$try"
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
- break
-
+ ac_cv_lib_talloc_talloc_set_memlimit=yes
else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+ ac_cv_lib_talloc_talloc_set_memlimit=no
fi
rm -f core conftest.err conftest.$ac_objext \
conftest$ac_exeext conftest.$ac_ext
- done
- LIBS="$old_LIBS"
+LIBS=$ac_check_lib_save_LIBS
fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_talloc_talloc_set_memlimit" >&5
+$as_echo "$ac_cv_lib_talloc_talloc_set_memlimit" >&6; }
+if test "x$ac_cv_lib_talloc_talloc_set_memlimit" = xyes; then :
+
+
+$as_echo "#define HAVE_TALLOC_SET_MEMLIMIT 1" >>confdefs.h
+
-if test "x$smart_lib" != "x"; then
- eval "ac_cv_lib_${sm_lib_safe}_${sm_func_safe}=yes"
- LIBS="$smart_lib $old_LIBS"
- SMART_LIBS="$smart_lib $SMART_LIBS"
-fi
-if test "x$ac_cv_lib_talloc__talloc" != "xyes"; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: talloc library not found. Use --with-talloc-lib-dir=<path>." >&5
-$as_echo "$as_me: WARNING: talloc library not found. Use --with-talloc-lib-dir=<path>." >&2;}
- as_fn_error $? "FreeRADIUS requires libtalloc" "$LINENO" 5
fi
+
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for crypt in -lcrypt" >&5
$as_echo_n "checking for crypt in -lcrypt... " >&6; }
if ${ac_cv_lib_crypt_crypt+:} false; then :
if test "${with_execinfo_include_dir+set}" = set; then :
withval=$with_execinfo_include_dir; case "$withval" in
no)
- as_fn_error $? "Need execinfo-include-dir" "$LINENO" 5
+ as_fn_error $? "Need execinfo-include-dir" "$LINENO" 5
;;
yes)
;;
ac_safe=`echo "execinfo.h" | sed 'y%./+-%__pm%'`
-old_CFLAGS="$CFLAGS"
+old_CPPFLAGS="$CPPFLAGS"
smart_include=
smart_include_dir=
for try in $smart_try_dir; do
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for execinfo.h in $try" >&5
$as_echo_n "checking for execinfo.h in $try... " >&6; }
- CFLAGS="$old_CFLAGS -isystem $try"
+ CPPFLAGS="-isystem $try $old_CPPFLAGS"
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
fi
rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
done
- CFLAGS="$old_CFLAGS"
+ CPPFLAGS="$old_CPPFLAGS"
fi
if test "x$smart_include" = "x"; then
for try in $smart_include_dir /usr/local/include /opt/include; do
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for execinfo.h in $try" >&5
$as_echo_n "checking for execinfo.h in $try... " >&6; }
- CFLAGS="$old_CFLAGS -isystem $try"
+ CPPFLAGS="-isystem $try $old_CPPFLAGS"
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
fi
rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
done
- CFLAGS="$old_CFLAGS"
+ CPPFLAGS="$old_CPPFLAGS"
fi
if test "x$smart_include" != "x"; then
eval "ac_cv_header_$ac_safe=yes"
- CFLAGS="$old_CFLAGS $smart_include"
- SMART_CFLAGS="$SMART_CFLAGS $smart_include"
+ CPPFLAGS="$smart_include $old_CPPFLAGS"
+ SMART_CPPFLAGS="$smart_include $SMART_CPPFLAGS"
fi
if test "x$ac_cv_header_execinfo_h" = "xyes"; then
sm_func_safe=`echo "backtrace_symbols" | sed 'y%./+-%__p_%'`
old_LIBS="$LIBS"
+old_CPPFLAGS="$CPPFLAGS"
smart_lib=
+smart_ldflags=
smart_lib_dir=
if test "x$smart_try_dir" != "x"; then
for try in $smart_try_dir; do
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for backtrace_symbols in -lexecinfo in $try" >&5
$as_echo_n "checking for backtrace_symbols in -lexecinfo in $try... " >&6; }
- LIBS="-L$try -lexecinfo $old_LIBS -Wl,-rpath,$try"
+ LIBS="-lexecinfo $old_LIBS"
+ CPPFLAGS="-L$try -Wl,-rpath,$try $old_CPPFLAGS"
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
extern char backtrace_symbols();
_ACEOF
if ac_fn_c_try_link "$LINENO"; then :
- smart_lib="-L$try -lexecinfo -Wl,-rpath,$try"
+ smart_lib="-lexecinfo"
+ smart_ldflags="-L$try -Wl,-rpath,$try"
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
$as_echo "yes" >&6; }
break
conftest$ac_exeext conftest.$ac_ext
done
LIBS="$old_LIBS"
+ CPPFLAGS="$old_CPPFLAGS"
fi
if test "x$smart_lib" = "x"; then
for try in $smart_lib_dir /usr/local/lib /opt/lib; do
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for backtrace_symbols in -lexecinfo in $try" >&5
$as_echo_n "checking for backtrace_symbols in -lexecinfo in $try... " >&6; }
- LIBS="-L$try -lexecinfo $old_LIBS -Wl,-rpath,$try"
+ LIBS="-lexecinfo $old_LIBS"
+ CPPFLAGS="-L$try -Wl,-rpath,$try $old_CPPFLAGS"
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
extern char backtrace_symbols();
_ACEOF
if ac_fn_c_try_link "$LINENO"; then :
- smart_lib="-L$try -lexecinfo -Wl,-rpath,$try"
+ smart_lib="-lexecinfo"
+ smart_ldflags="-L$try -Wl,-rpath,$try"
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
$as_echo "yes" >&6; }
break
conftest$ac_exeext conftest.$ac_ext
done
LIBS="$old_LIBS"
+ CPPFLAGS="$old_CPPFLAGS"
fi
if test "x$smart_lib" != "x"; then
eval "ac_cv_lib_${sm_lib_safe}_${sm_func_safe}=yes"
- LIBS="$smart_lib $old_LIBS"
- SMART_LIBS="$smart_lib $SMART_LIBS"
+ LIBS="$smart_ldflags $smart_lib $old_LIBS"
+ SMART_LIBS="$smart_ldflags $smart_lib $SMART_LIBS"
fi
if test "x$ac_cv_lib_execinfo_backtrace_symbols" != "xyes"; then
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
$as_echo "yes" >&6; }
- ac_cv_lib_execinfo_backtrace_symbols=yes
+ ac_cv_lib_execinfo_backtrace_symbols="yes"
else
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
$as_echo "no" >&6; }
- ac_cv_lib_execinfo_backtrace_symbols=no
fi
if test "${with_pcre_lib_dir+set}" = set; then :
withval=$with_pcre_lib_dir; case "$withval" in
no)
- as_fn_error $? "Need pcre-lib-dir" "$LINENO" 5
+ as_fn_error $? "Need pcre-lib-dir" "$LINENO" 5
;;
yes)
;;
*)
pcre_lib_dir="$withval"
;;
- esac
+ esac
fi
*)
pcre_include_dir="$withval"
;;
- esac
+ esac
fi
ac_safe=`echo "pcreposix.h" | sed 'y%./+-%__pm%'`
-old_CFLAGS="$CFLAGS"
+old_CPPFLAGS="$CPPFLAGS"
smart_include=
smart_include_dir=
for try in $smart_try_dir; do
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for pcreposix.h in $try" >&5
$as_echo_n "checking for pcreposix.h in $try... " >&6; }
- CFLAGS="$old_CFLAGS -isystem $try"
+ CPPFLAGS="-isystem $try $old_CPPFLAGS"
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
fi
rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
done
- CFLAGS="$old_CFLAGS"
+ CPPFLAGS="$old_CPPFLAGS"
fi
if test "x$smart_include" = "x"; then
for try in $smart_include_dir /usr/local/include /opt/include; do
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for pcreposix.h in $try" >&5
$as_echo_n "checking for pcreposix.h in $try... " >&6; }
- CFLAGS="$old_CFLAGS -isystem $try"
+ CPPFLAGS="-isystem $try $old_CPPFLAGS"
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
fi
rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
done
- CFLAGS="$old_CFLAGS"
+ CPPFLAGS="$old_CPPFLAGS"
fi
if test "x$smart_include" != "x"; then
eval "ac_cv_header_$ac_safe=yes"
- CFLAGS="$old_CFLAGS $smart_include"
- SMART_CFLAGS="$SMART_CFLAGS $smart_include"
+ CPPFLAGS="$smart_include $old_CPPFLAGS"
+ SMART_CPPFLAGS="$smart_include $SMART_CPPFLAGS"
fi
if test "x$ac_cv_header_pcreposix_h" = "xyes"; then
ac_safe=`echo "regex.h" | sed 'y%./+-%__pm%'`
-old_CFLAGS="$CFLAGS"
+old_CPPFLAGS="$CPPFLAGS"
smart_include=
smart_include_dir=
for try in $smart_try_dir; do
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for regex.h in $try" >&5
$as_echo_n "checking for regex.h in $try... " >&6; }
- CFLAGS="$old_CFLAGS -isystem $try"
+ CPPFLAGS="-isystem $try $old_CPPFLAGS"
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
fi
rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
done
- CFLAGS="$old_CFLAGS"
+ CPPFLAGS="$old_CPPFLAGS"
fi
if test "x$smart_include" = "x"; then
for try in $smart_include_dir /usr/local/include /opt/include; do
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for regex.h in $try" >&5
$as_echo_n "checking for regex.h in $try... " >&6; }
- CFLAGS="$old_CFLAGS -isystem $try"
+ CPPFLAGS="-isystem $try $old_CPPFLAGS"
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
fi
rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
done
- CFLAGS="$old_CFLAGS"
+ CPPFLAGS="$old_CPPFLAGS"
fi
if test "x$smart_include" != "x"; then
eval "ac_cv_header_$ac_safe=yes"
- CFLAGS="$old_CFLAGS $smart_include"
- SMART_CFLAGS="$SMART_CFLAGS $smart_include"
+ CPPFLAGS="$smart_include $old_CPPFLAGS"
+ SMART_CPPFLAGS="$smart_include $SMART_CPPFLAGS"
fi
if test "x$ac_cv_header_regex_h" = "xyes"; then
AC_CANONICAL_SYSTEM
dnl #
-dnl # As of OSX 10.9 (Mavericks), /usr is no longer populated with the
-dnl # standard set of headers and libraries, instead were meant to use
-dnl # one of the SDKs which contains system headers and libraries for
-dnl # different versions of OSX and iOS.
-dnl #
-case "$host" in
- *-darwin*)
- dnl #
- dnl # The version of GCC apple ships with Mavericks works out of the
- dnl # box, and presumably selects the highest version SDK for OSX.
- dnl #
- AC_MSG_CHECKING([if cc is apple llvm])
- if ! $CC --version 2>&1 | grep -I 'Apple LLVM' > /dev/null; then
- AC_MSG_RESULT(no)
- AC_CHECK_PROG(SW_VERS, sw_vers, yes, no)
- AC_CHECK_PROG(XCODEBUILD, xcodebuild, yes, no)
-
- if test "x$SW_VERS" = "xyes" && test "x$XCODEBUILD" = "xyes"; then
- AC_MSG_NOTICE([determining OSX SDK path])
- osx_sdk_path=$(xcodebuild -version -sdk macosx$(sw_vers -productVersion | egrep -o '^[[0-9]]+\.[[0-9]]+') Path)
- AC_MSG_RESULT([$osx_sdk_path])
-
- dnl #
- dnl # We need to export these, else the child configure scripts all fail
- dnl # their compiler checks.
- dnl #
- export CFLAGS="$CFLAGS --sysroot=$osx_sdk_path"
- export CPPFLAGS="$CPPFLAGS --sysroot=$osx_sdk_path"
- export LDFLAGS="$LDFLAGS -L$osx_sdk_path/usr/lib/"
- DARWIN_CFLAGS="--sysroot=$osx_sdk_path"
- AC_SUBST(DARWIN_CFLAGS)
- fi
- else
- AC_MSG_RESULT(yes)
- fi
- ;;
-esac
-
-dnl #
dnl # Check for GNU cc
dnl #
AC_PROG_CC
USE_SHARED_LIBS=yes
AC_ARG_WITH(shared-libs,
-[ --with-shared-libs build dynamic libraries and link against them. (default=yes)],
+[AS_HELP_STRING([--with-shared-libs ],
+[build dynamic libraries and link against them. (default=yes)])],
[ case "$withval" in
no)
USE_SHARED_LIBS=no
dnl #
EXPERIMENTAL=
AC_ARG_WITH(experimental-modules,
-[ --with-experimental-modules use experimental and unstable modules. (default=no, unless --enable-developer=yes) ],
+[AS_HELP_STRING([--with-experimental-modules],
+[use experimental and unstable modules. (default=no, unless --enable-developer=yes)])],
[ case "$withval" in
yes)
EXPERIMENTAL=yes
dnl #
WITH_UDPFROMTO=yes
AC_ARG_WITH(udpfromto,
-[ --with-udpfromto compile in UDPFROMTO support. (default=yes)],
+[ --with-udpfromto compile in UDPFROMTO support. (default=yes)],
[ case "$withval" in
yes)
WITH_UDPFROMTO=yes
fi
dnl #
-dnl # extra argument: --with-openssl
+dnl # These next two arguments don't actually do anything. They're
+dnl # place holders so that the top-level configure script can tell
+dnl # the user how to configure lower-level modules
dnl #
-WITH_OPENSSL=yes
-AC_ARG_WITH(openssl,
-[ --with-openssl use OpenSSL. (default=yes)],
+
+dnl #
+dnl # extra argument: --with-rlm-FOO-lib-dir
+dnl #
+AC_ARG_WITH(rlm-FOO-lib-dir,
+[AS_HELP_STRING([--with-rlm-FOO-lib-dir=DIR],
+[directory in which to look for library files used by module FOO])],
[ case "$withval" in
- no)
- WITH_OPENSSL=no
- ;;
*)
- WITH_OPENSSL=yes
;;
esac ]
)
dnl #
-dnl # extra argument: --with-openssl-includes=dir
+dnl # extra argument: --with-rlm-FOO-include-dir
dnl #
-OPENSSL_INCLUDE_DIR=
-AC_ARG_WITH(openssl-includes,
-[ --with-openssl-includes=DIR directory to look for OpenSSL include files in],
+AC_ARG_WITH(rlm-FOO-include-dir,
+[AS_HELP_STRING([--with-rlm-FOO-include-dir=DIR],
+[directory in which to look for include files used by module FOO])],
[ case "$withval" in
- *) OPENSSL_INCLUDE_DIR="$withval"
+ *)
;;
esac ]
)
dnl #
-dnl # extra argument: --with-openssl-libraries=dir
+dnl # extra argument: --with-openssl
dnl #
-OPENSSL_LIB_DIR=
-AC_ARG_WITH(openssl-libraries,
-[ --with-openssl-libraries=DIR directory to look for OpenSSL library files in],
+WITH_OPENSSL=yes
+AC_ARG_WITH(openssl,
+[ --with-openssl use OpenSSL. (default=yes)],
[ case "$withval" in
- *) OPENSSL_LIB_DIR="$withval"
+ no)
+ WITH_OPENSSL=no
+ ;;
+ *)
+ WITH_OPENSSL=yes
;;
esac ]
)
dnl #
-dnl # These next two arguments don't actually do anything. They're
-dnl # place holders so that the top-level configure script can tell
-dnl # the user how to configure lower-level modules
-dnl #
-
-dnl #
-dnl # extra argument: --with-rlm-FOO-lib-dir
+dnl # extra argument: --with-openssl-lib-dir=dir
dnl #
-AC_ARG_WITH(rlm-FOO-lib-dir,
-[ --with-rlm-FOO-lib-dir=DIR directory to look for library files used by module FOO in],
+openssl_lib_dir=
+AC_ARG_WITH(openssl-lib-dir,
+[AS_HELP_STRING([--with-openssl-lib-dir=DIR],
+[directory to look for OpenSSL library files])],
[ case "$withval" in
- *)
+ *) openssl_lib_dir="$withval"
;;
esac ]
)
dnl #
-dnl # extra argument: --with-rlm-FOO-include-dir
+dnl # extra argument: --with-openssl-includes=dir
dnl #
-AC_ARG_WITH(rlm-FOO-include-dir,
-[ --with-rlm-FOO-include-dir=DIR directory to look for include files used by module FOO in],
+openssl_include_dir=
+AC_ARG_WITH(openssl-include-dir,
+[AS_HELP_STRING([--with-openssl-include-dir=DIR],
+[directory to look for OpenSSL include files])],
[ case "$withval" in
- *)
+ *) openssl_include_dir="$withval"
;;
esac ]
)
dnl #
dnl #############################################################
+dnl Check for talloc
+dnl extra argument: --with-talloc-lib-dir=DIR
+talloc_lib_dir=
+AC_ARG_WITH(talloc-lib-dir,
+ [AS_HELP_STRING([--with-talloc-lib-dir=DIR],
+ [directory in which to look for talloc library files])],
+ [case "$withval" in
+ no)
+ AC_MSG_ERROR([Need talloc-lib-dir])
+ ;;
+ yes)
+ ;;
+ *)
+ talloc_lib_dir="$withval"
+ ;;
+ esac])
+
+dnl extra argument: --with-talloc-include-dir=DIR
+talloc_include_dir=
+AC_ARG_WITH(talloc-include-dir,
+ [AS_HELP_STRING([--with-talloc-include-dir=DIR],
+ [directory in which to look for talloc include files])],
+ [case "$withval" in
+ no)
+ AC_MSG_ERROR([Need talloc-include-dir])
+ ;;
+ yes)
+ ;;
+ *)
+ talloc_include_dir="$withval"
+ ;;
+ esac])
+
+smart_try_dir="$talloc_lib_dir"
+FR_SMART_CHECK_LIB(talloc, _talloc)
+if test "x$ac_cv_lib_talloc__talloc" != "xyes"; then
+ AC_MSG_WARN([talloc library not found. Use --with-talloc-lib-dir=<path>.])
+ AC_MSG_ERROR([FreeRADIUS requires libtalloc])
+fi
+
+TALLOC_LIBS="${smart_lib}"
+TALLOC_LDFLAGS="${smart_ldflags}"
+AC_SUBST(TALLOC_LIBS)
+AC_SUBST(TALLOC_LDFLAGS)
+LIBS="$old_LIBS"
+
dnl #
dnl # If using pthreads, check for -lpthread (posix) or -lc_r (*BSD)
dnl #
CFLAGS="$CFLAGS -mt"
fi
- AC_CHECK_HEADERS(pthread.h, [], [ WITH_THREADS="no" ])
+ AC_CHECK_HEADERS(pthread.h, [],
+ [
+ WITH_THREADS="no"
+ fail=[pthread.h]
+ ])
dnl #
dnl # pthread stuff is usually in -lpthread
LIBS="-lpthread $LIBS"
],
[
+ dnl #
+ dnl # -pthread is not a typo, it's a GCC option which sets additional flags required
+ dnl # for multithreading with the pthreads library.
+ dnl #
AC_CHECK_LIB(c_r, pthread_create,
[ CFLAGS="$CFLAGS -pthread -D_THREAD_SAFE" ],
- [ WITH_THREADS="no" ]
+ [
+ WITH_THREADS="no"
+ fail=[-lpthread]
+ ]
)
]
)
+
+ if test "x$WITH_THREADS" != "xyes"; then
+ AC_MSG_WARN([silently not building with thread support.])
+ AC_MSG_WARN([FAILURE: thread support requires: $fail.])
+ else
+ AC_DEFINE(WITH_THREADS, [1], [define if you want thread support])
+ fi
fi
dnl #
)
fi
-if test "x$WITH_THREADS" = "xyes"; then
- AC_DEFINE(WITH_THREADS, [1], [define if you want thread support])
-fi
-
dnl #
dnl # Check if we need -lsocket
dnl #
dnl #
dnl # Check the pcap library for the RADIUS sniffer.
dnl #
+dnl extra argument: --with-pcap-lib-dir=DIR
+pcap_lib_dir=
+AC_ARG_WITH(pcap-lib-dir,
+ [AS_HELP_STRING([--with-pcap-lib-dir=DIR],
+ [directory in which to look for pcap library files])],
+ [case "$withval" in
+ no)
+ AC_MSG_ERROR([Need pcap-lib-dir])
+ ;;
+ yes)
+ ;;
+ *)
+ pcap_lib_dir="$withval"
+ ;;
+ esac])
+
+dnl extra argument: --with-pcap-include-dir=DIR
+pcap_include_dir=
+AC_ARG_WITH(pcap-include-dir,
+ [AS_HELP_STRING([--with-pcap-include-dir=DIR],
+ [directory in which to look for pcap include files])],
+ [case "$withval" in
+ no)
+ AC_MSG_ERROR([Need pcap-include-dir])
+ ;;
+ yes)
+ ;;
+ *)
+ pcap_include_dir="$withval"
+ ;;
+ esac])
+
smart_try_dir="$pcap_lib_dir"
FR_SMART_CHECK_LIB(pcap, pcap_open_live)
if test "x$ac_cv_lib_pcap_pcap_open_live" != "xyes"; then
- AC_MSG_WARN([pcap library not found. Use --with-pcap-lib-dir=<path>.])
- AC_MSG_WARN([pcap library not found, silently disabling the RADIUS sniffer and ARP listener.])
+ AC_MSG_WARN([pcap library not found, silently disabling the RADIUS sniffer, and ARP listener. Use --with-pcap-lib-dir=<path>.])
else
- PCAP_LIBS="${smart_lib}"
- LIBS=$old_LIBS
AC_DEFINE(HAVE_LIBPCAP, 1,
[Define to 1 if you have the `pcap' library (-lpcap).]
)
+
+ AC_CHECK_FUNCS(\
+ pcap_fopen_offline \
+ pcap_dump_fopen \
+ pcap_create \
+ pcap_activate
+ )
+
+ PCAP_LIBS="${smart_lib}"
+ PCAP_LDFLAGS="${smart_ldflags}"
fi
+dnl Set by FR_SMART_CHECK_LIB
+LIBS="${old_LIBS}"
+
+dnl Check for collectdclient
+dnl extra argument: --with-collectdclient-lib-dir=DIR
+collectdclient_lib_dir=
+AC_ARG_WITH(collectdclient-lib-dir,
+ [AS_HELP_STRING([--with-collectdclient-lib-dir=DIR],
+ [directory in which to look for collectdclient library files])],
+ [case "$withval" in
+ no)
+ AC_MSG_ERROR([Need collectdclient-lib-dir])
+ ;;
+ yes)
+ ;;
+ *)
+ collectdclient_lib_dir="$withval"
+ ;;
+ esac])
+
+dnl extra argument: --with-collectdclient-include-dir=DIR
+collectdclient_include_dir=
+AC_ARG_WITH(collectdclient-include-dir,
+ [AS_HELP_STRING([--with-collectdclient-include-dir=DIR],
+ [directory in which to look for collectdclient include files])],
+ [case "$withval" in
+ no)
+ AC_MSG_ERROR([Need collectdclient-include-dir])
+ ;;
+ yes)
+ ;;
+ *)
+ collectdclient_include_dir="$withval"
+ ;;
+ esac])
+
+smart_try_dir="$collectdclient_lib_dir"
+FR_SMART_CHECK_LIB(collectdclient, lcc_connect)
+if test "x$ac_cv_lib_collectdclient_lcc_connect" != "xyes"; then
+ AC_MSG_WARN([collectdclient library not found. Use --with-collectdclient-lib-dir=<path>.])
+else
+ COLLECTDC_LIBS="${smart_lib}"
+ COLLECTDC_LDFLAGS="${smart_ldflags}"
+fi
+dnl Set by FR_SMART_CHECKLIB
+LIBS="${old_LIBS}"
VL_LIB_READLINE
dnl #############################################################
dnl #
+dnl # Check for talloc header files
+dnl #
+smart_try_dir="$talloc_include_dir"
+FR_SMART_CHECK_INCLUDE([talloc.h])
+if test "x$ac_cv_header_talloc_h" != "xyes"; then
+ AC_MSG_WARN([talloc headers not found. Use --with-talloc-include-dir=<path>.])
+ AC_MSG_ERROR([FreeRADIUS requires libtalloc])
+fi
+
+dnl #
dnl # Interix requires us to set -D_ALL_SOURCE, otherwise
dnl # getopt will be #included, but won't link. <sigh>
dnl #
-dnl #
case "$host" in
*-interix*)
CFLAGS="$CFLAGS -D_ALL_SOURCE"
unistd.h \
crypt.h \
errno.h \
- features.h \
resource.h \
sys/resource.h \
getopt.h \
stddef.h \
fnmatch.h \
sia.h \
- siad.h
+ siad.h \
+ features.h
)
dnl #
dnl # FreeBSD requires sys/socket.h before net/if.h
dnl #
AC_CHECK_HEADERS(net/if.h, [], [],
-[
- #ifdef HAVE_SYS_SOCKET_H
- # include <sys/socket.h>
- #endif
-])
+ [
+ #ifdef HAVE_SYS_SOCKET_H
+ # include <sys/socket.h>
+ #endif
+ ]
+)
dnl #
dnl # other checks which require headers
dnl # Were we told to use OpenSSL, if we were and we find an error, call AC_MSG_FAILURE and exit
dnl #
if test "x$WITH_OPENSSL" = xyes; then
- old_LIBS=$LIBS
- old_LDFLAGS="$LDFLAGS"
-
- OPENSSL_INCLUDE="-DNO_OPENSSL"
- OPENSSL_LIBS=
- if test "x$OPENSSL_LIB_DIR" != "x"; then
- LDFLAGS="-L$OPENSSL_LIB_DIR $LDFLAGS"
- fi
+ OLD_LIBS="$LIBS"
dnl #
- dnl # Check we can link to libssl
+ dnl # Apparently OpenSSL will attempt to build with kerberos if we don't pass this?!
dnl #
- AC_CHECK_LIB(crypto, DH_new,
- [
- LIBS="-lcrypto $LIBS"
- AC_DEFINE(HAVE_LIBCRYPTO, 1, [Define to 1 if you have the `crypto' library (-lcrypto).])
- AC_CHECK_LIB(ssl, SSL_new,
- [
- AC_DEFINE(HAVE_LIBSSL, 1, [Define to 1 if you have the `ssl' library (-lssl).])
- if test "x$OPENSSL_LIB_DIR" != "x"; then
- OPENSSL_LIBS="-L$OPENSSL_LIB_DIR"
- fi
- OPENSSL_LIBS="$OPENSSL_LIBS -lcrypto -lssl -lcrypto"
- ],
- [
- AC_MSG_FAILURE([failed linking to libssl])
- ]
- )
- ],
- []
- )
+ CFLAGS="$CFLAGS -DOPENSSL_NO_KRB5"
dnl #
- dnl # Check we can find required headers
+ dnl # Check we can link to libcrypto and libssl
dnl #
- old_CPPFLAGS=$CPPFLAGS
- old_CFLAGS=$CFLAGS
- if test "x$OPENSSL_INCLUDE_DIR" != "x"; then
- CPPFLAGS="-isystem $OPENSSL_INCLUDE_DIR $CPPFLAGS"
- CFLAGS="-isystem $OPENSSL_INCLUDE_DIR $CFLAGS"
+ smart_try_dir="$openssl_lib_dir"
+ FR_SMART_CHECK_LIB(crypto, DH_new)
+ if test "x$ac_cv_lib_crypto_DH_new" = "xyes"; then
+ AC_DEFINE(HAVE_LIBCRYPTO, 1, [Define to 1 if you have the `crypto' library (-lcrypto).])
+ OPENSSL_LIBS="$smart_lib"
+ OPENSSL_LDFLAGS="$smart_ldflags"
+
+ FR_SMART_CHECK_LIB(ssl, SSL_new)
+ if test "x$ac_cv_lib_ssl_SSL_new" != "xyes"; then
+ AC_MSG_FAILURE([failed linking to libssl. Use --with-openssl-lib-dir=<path>, or --with-openssl=no (builds without OpenSSL)])
+ else
+ AC_DEFINE(HAVE_LIBSSL, 1, [Define to 1 if you have the `ssl' library (-lssl).])
+ OPENSSL_LIBS="$OPENSSL_LIBS $smart_lib"
+
+ if test "$OPENSSL_LDFLAGS" != "$smart_ldflags"; then
+ AC_MSG_FAILURE(["inconsistent LDFLAGS between -lssl '$smart_ldflags' and -lcrypto '$OPENSSL_LDFLAGS'"])
+ fi
+ fi
+ else
+ AC_MSG_FAILURE([failed linking to libcrypto. Use --with-openssl-lib-dir=<path>, or --with-openssl=no (builds without OpenSSL)])
fi
- dnl #
- dnl # Stupid RedHat shit
- dnl #
- CPPFLAGS="$CPPFLAGS -DOPENSSL_NO_KRB5"
- AC_CHECK_HEADERS( \
- openssl/ssl.h \
- openssl/crypto.h \
- openssl/err.h \
- openssl/evp.h \
- openssl/md5.h \
- openssl/md4.h \
- openssl/sha.h \
- openssl/ocsp.h \
- openssl/engine.h,
- [],
- [
- AC_MSG_FAILURE([failed locating OpenSSL headers])
- ]
- )
+ smart_try_dir="$openssl_include_dir"
+ FR_SMART_CHECK_INCLUDE(openssl/ssl.h)
+ if test "x$ac_cv_header_openssl_ssl_h" = "xyes"; then
+ AC_DEFINE(HAVE_OPENSSL_SSL_H, 1, [Define to 1 if you have the <openssl/ssl.h> header file.])
+
+ AC_CHECK_HEADERS( \
+ openssl/crypto.h \
+ openssl/err.h \
+ openssl/evp.h \
+ openssl/md5.h \
+ openssl/md4.h \
+ openssl/sha.h \
+ openssl/ocsp.h \
+ openssl/engine.h,
+ [],
+ [
+ AC_MSG_FAILURE([failed locating OpenSSL headers. Use --with-openssl-include-dir=<path>, or --with-openssl=no (builds without OpenSSL)])
+ ]
+ )
- AC_MSG_CHECKING([for OpenSSL version >= 0.9.7])
- AC_EGREP_CPP(yes,
- [#include <openssl/crypto.h>
- #if (OPENSSL_VERSION_NUMBER >= 0x00907000L)
- yes
- #endif
- ],
- [
- AC_MSG_RESULT(yes)
- ],
- [
- AC_MSG_RESULT(no)
- AC_MSG_FAILURE([OpenSSL version too old])
- ]
- )
+ AC_MSG_CHECKING([for OpenSSL version >= 0.9.7])
+ AC_EGREP_CPP(yes,
+ [#include <openssl/crypto.h>
+ #if (OPENSSL_VERSION_NUMBER >= 0x00907000L)
+ yes
+ #endif
+ ],
+ [
+ AC_MSG_RESULT(yes)
+ ],
+ [
+ AC_MSG_RESULT(no)
+ AC_MSG_FAILURE([OpenSSL version too old])
+ ]
+ )
- if test "x$OPENSSL_INCLUDE_DIR" != "x"; then
- OPENSSL_INCLUDE="-isystem $OPENSSL_INCLUDE_DIR -DOPENSSL_NO_KRB5"
- else
- OPENSSL_INCLUDE="-DOPENSSL_NO_KRB5"
- fi
+ dnl #
+ dnl # CPPFLAGS are passed to the compiler first, so we use
+ dnl # them to ensure things like --sysroot don't override the
+ dnl # library location we discovered previously.
+ dnl #
+ old_CPPFLAGS="$CPPFLAGS"
+ CPPFLAGS="$OPENSSL_LDFLAGS $CPPFLAGS"
- dnl #
- dnl # Now check that the header versions match the library
- dnl #
- AC_MSG_CHECKING([OpenSSL library and header version consistency])
- AC_RUN_IFELSE(
- [AC_LANG_PROGRAM(
- [[
- #include <stdio.h>
- #include <openssl/opensslv.h>
- #include <openssl/crypto.h>
- ]],
- [[
- if (SSLeay() == OPENSSL_VERSION_NUMBER) {
- return 0;
- } else {
+ dnl #
+ dnl # Now check that the header versions match the library
+ dnl #
+ AC_MSG_CHECKING([OpenSSL library and header version consistency])
+ AC_RUN_IFELSE(
+ [AC_LANG_PROGRAM(
+ [[
+ #include <stdio.h>
+ #include <openssl/opensslv.h>
+ #include <openssl/crypto.h>
+ ]],
+ [[
printf("library: %lx header: %lx... ", (unsigned long) SSLeay(), (unsigned long) OPENSSL_VERSION_NUMBER);
- return 1;
- }
- ]]
- )],
- [
- AC_MSG_RESULT(yes)
- ],
- [
- AC_MSG_RESULT(no)
- AC_MSG_FAILURE([OpenSSL library version does not match header version])
- ]
- )
-
- if test "x$OPENSSL_LIBS" = x; then
- LIBS=$old_LIBS
- LDFLAGS="$old_LDFLAGS"
- fi
- if test "x$OPENSSL_INCLUDE" = x; then
- CPPFLAGS=$old_CPPFLAGS
- CFLAGS=$old_CFLAGS
+ if (SSLeay() == OPENSSL_VERSION_NUMBER) {
+ return 0;
+ } else {
+ return 1;
+ }
+ ]]
+ )],
+ [
+ AC_MSG_RESULT(yes)
+ ],
+ [
+ AC_MSG_RESULT(no)
+ AC_MSG_FAILURE([OpenSSL library version does not match header version])
+ ]
+ )
+ CPPFLAGS="$old_CPPFLAGS"
fi
-fi
-AC_SUBST(OPENSSL_INCLUDE)
-AC_SUBST(OPENSSL_LIBS)
-export OPENSSL_LIBS
+ LIBS="$OLD_LIBS"
+ AC_SUBST(OPENSSL_LIBS)
+ AC_SUBST(OPENSSL_LDFLAGS)
+ export OPENSSL_LIBS OPENSSL_LDFLAGS
+fi
dnl #
dnl # Check the pcap includes for the RADIUS sniffer.
if test "x$PCAP_LIBS" = x; then
AC_MSG_NOTICE([skipping test for pcap.h.])
else
+ dnl #
+ dnl # Check for pcap header files
+ dnl #
smart_try_dir="$pcap_include_dir"
FR_SMART_CHECK_INCLUDE([pcap.h])
- if test "x$ac_cv_header_pcap_h" != "xyes"; then
- AC_MSG_WARN([pcap headers not found. Use --with-pcap-include-dir=<path>.])
- AC_MSG_WARN([pcap.h not found, silently disabling the RADIUS sniffer, and ARP listener.])
- else
+ if test "x$ac_cv_header_pcap_h" == "xyes"; then
AC_DEFINE(HAVE_PCAP_H, 1, [Define to 1 if you have the <pcap.h> header file.])
+ AC_SUBST(PCAP_LIBS)
+ AC_SUBST(PCAP_LDFLAGS)
+ else
+ AC_MSG_WARN([pcap headers not found, silently disabling the RADIUS sniffer, and ARP listener. Use --with-pcap-include-dir=<path>.])
+ fi
+fi
- AC_CHECK_LIB(pcap, pcap_fopen_offline,
- [
- AC_DEFINE(HAVE_PCAP_FOPEN_OFFLINE, 1, [Define to 1 if you have the function pcap_fopen_offline.])
- ]
- )
-
- AC_CHECK_LIB(pcap, pcap_dump_fopen,
- [
- AC_DEFINE(HAVE_PCAP_DUMP_FOPEN, 1, [Define to 1 if you have the function pcap_dump_fopen.])
- ]
- )
+dnl Check for collectd-client
+if test "x$COLLECTDC_LIBS" = x; then
+ AC_MSG_NOTICE([skipping test for collectd/client.h.])
+else
+ dnl #
+ dnl # Check for collectd-client header files
+ dnl #
+ smart_try_dir="$collectdclient_include_dir"
+ FR_SMART_CHECK_INCLUDE([collectd/client.h])
+ if test "x$ac_cv_header_collectd_client_h" == "xyes"; then
+ AC_DEFINE(HAVE_COLLECTDC_H, 1, [Define to 1 if you have the `collectdclient' library (-lcollectdclient).])
+ AC_SUBST(COLLECTDC_LIBS)
+ AC_SUBST(COLLECTDC_LDFLAGS)
+ else
+ AC_MSG_WARN([collectdclient headers not found. Use --with-collectdclient-include-dir=<path>.])
fi
fi
-AC_SUBST(PCAP_LIBS)
dnl #############################################################
dnl #
dnl #
dnl #############################################################
-dnl Check for talloc
-dnl extra argument: --with-talloc-include-dir=DIR
-talloc_include_dir=
-AC_ARG_WITH(talloc-include-dir,
- [ --with-talloc-include-dir=DIR directory to look for talloc include files in],
- [case "$withval" in
- no)
- AC_MSG_ERROR([Need talloc-include-dir])
- ;;
- yes)
- ;;
- *)
- talloc_include_dir="$withval"
- ;;
- esac])
-
-dnl Check for talloc
-dnl extra argument: --with-talloc-lib-dir=DIR
-talloc_lib_dir=
-AC_ARG_WITH(talloc-lib-dir,
- [ --with-talloc-lib-dir=DIR directory to look for talloc library files in],
- [case "$withval" in
- no)
- AC_MSG_ERROR([Need talloc-lib-dir])
- ;;
- yes)
- ;;
- *)
- talloc_lib_dir="$withval"
- ;;
- esac])
-
-dnl Check for pcap
-dnl extra argument: --with-pcap-include-dir=DIR
-pcap_include_dir=
-AC_ARG_WITH(pcap-include-dir,
- [ --with-pcap-include-dir=DIR directory to look for pcap include files in],
- [case "$withval" in
- no)
- AC_MSG_ERROR([Need pcap-include-dir])
- ;;
- yes)
- ;;
- *)
- pcap_include_dir="$withval"
- ;;
- esac])
-
-dnl Check for pcap
-dnl extra argument: --with-pcap-lib-dir=DIR
-pcap_lib_dir=
-AC_ARG_WITH(pcap-lib-dir,
- [ --with-pcap-lib-dir=DIR directory to look for pcap library files in],
- [case "$withval" in
- no)
- AC_MSG_ERROR([Need pcap-lib-dir])
- ;;
- yes)
- ;;
- *)
- pcap_lib_dir="$withval"
- ;;
- esac])
-
dnl #
-dnl # Check for talloc header files
+dnl # Check for talloc_set_memlimit
+dnl # This was only included in version 2.0.8
dnl #
-smart_try_dir="$talloc_include_dir"
-FR_SMART_CHECK_INCLUDE([talloc.h])
-if test "x$ac_cv_header_talloc_h" != "xyes"; then
- AC_MSG_WARN([talloc headers not found. Use --with-talloc-include-dir=<path>.])
- AC_MSG_ERROR([FreeRADIUS requires libtalloc])
-fi
-
-smart_try_dir="$talloc_lib_dir"
-FR_SMART_CHECK_LIB(talloc, _talloc)
-if test "x$ac_cv_lib_talloc__talloc" != "xyes"; then
- AC_MSG_WARN([talloc library not found. Use --with-talloc-lib-dir=<path>.])
- AC_MSG_ERROR([FreeRADIUS requires libtalloc])
-fi
+AC_CHECK_LIB(talloc, talloc_set_memlimit,
+ [
+ AC_DEFINE(HAVE_TALLOC_SET_MEMLIMIT, 1, [Define to 1 if you have the function talloc_set_memlimit.])
+ ]
+)
dnl #
dnl # Check for libcrypt
dnl extra argument: --with-execinfo-lib-dir
execinfo_lib_dir=
AC_ARG_WITH(execinfo-lib-dir,
-[ --with-execinfo-lib-dir=DIR directory to look for execinfo library files in],
+[AS_HELP_STRING([--with-execinfo-lib-dir=DIR],
+[directory in which to look for execinfo library files])],
[ case "$withval" in
no)
AC_MSG_ERROR([Need execinfo-lib-dir])
dnl extra argument: --with-execinfo-include-dir
execinfo_include_dir=
AC_ARG_WITH(execinfo-include-dir,
-[ --with-execinfo-include-dir=DIR directory to look for execinfo include files in],
+[AS_HELP_STRING([--with-execinfo-include-dir=DIR],
+[directory in which to look for execinfo include files])],
[ case "$withval" in
no)
- AC_MSG_ERROR(Need execinfo-include-dir)
+ AC_MSG_ERROR([Need execinfo-include-dir])
;;
yes)
;;
backtrace_symbols(&sym, sizeof(sym)) ],
[
AC_MSG_RESULT(yes)
- ac_cv_lib_execinfo_backtrace_symbols=yes
+ ac_cv_lib_execinfo_backtrace_symbols="yes"
],
[
AC_MSG_RESULT(no)
- ac_cv_lib_execinfo_backtrace_symbols=no
]
)
fi
dnl extra argument: --with-pcre-lib-dir
pcre_lib_dir=
AC_ARG_WITH(pcre-lib-dir,
- [ --with-pcre-lib-dir=DIR directory to look for pcre library files in],
- [ case "$withval" in
+[AS_HELP_STRING([--with-pcre-lib-dir=DIR],
+[directory in which to look for pcre library files])],
+[ case "$withval" in
no)
- AC_MSG_ERROR([Need pcre-lib-dir])
+ AC_MSG_ERROR(Need pcre-lib-dir)
;;
yes)
;;
*)
pcre_lib_dir="$withval"
;;
- esac ]
+ esac ]
)
dnl extra argument: --with-pcre-include--dir
pcre_include_dir=
AC_ARG_WITH(pcre-include-dir,
- [ --with-pcre-include-dir=DIR directory to look for PCRE include files in],
- [ case "$withval" in
+[AS_HELP_STRING([--with-pcre-include-dir=DIR],
+[directory in which to look for pcre include files])],
+[ case "$withval" in
no)
AC_MSG_ERROR(Need pcre-include-dir)
;;
*)
pcre_include_dir="$withval"
;;
- esac ]
+ esac ]
)
REGEX=no
reply:FreeRADIUS-Response-Delay = 1
* Allow tag and array references anywhere attributes
are allowed in "unlang".
+ * many enhancements to radsniff, including output
+ to collectd, ipv6 support and packet loss statistics.
Bug fixes
* Fix xlat expression %{attribute[n]} so that it actually
to double-check your Perl scripts if they use "\" characters.
See mods-available/perl for documentation.
* Don't re-run "authorize" if a home server fails to respond.
- * "0x" isn't printed in front of octets types, for xlat
+ * Don't append "0x" to hex output of octets types, for xlat
expansions. This is the same as v2, and makes it easier
to concatenate multiple attributes of type "octets"
* FreeBSD fixes for execinfo linking.
fr_event_list_t *fr_event_list_create(TALLOC_CTX *ctx, fr_event_status_t status);
+int fr_event_list_num_fds(fr_event_list_t *el);
int fr_event_list_num_elements(fr_event_list_t *el);
int fr_event_insert(fr_event_list_t *el,
int fr_event_fd_delete(fr_event_list_t *el, int type, int fd);
int fr_event_loop(fr_event_list_t *el);
void fr_event_loop_exit(fr_event_list_t *el, int code);
+bool fr_event_loop_exiting(fr_event_list_t *el);
#ifdef __cplusplus
}
/* radius.c */
int rad_send(RADIUS_PACKET *, RADIUS_PACKET const *, char const *secret);
-int rad_packet_ok(RADIUS_PACKET *packet, int flags);
+bool rad_packet_ok(RADIUS_PACKET *packet, int flags, decode_fail_t *reason);
RADIUS_PACKET *rad_recv(int fd, int flags);
ssize_t rad_recv_header(int sockfd, fr_ipaddr_t *src_ipaddr, int *src_port,
int *code);
int rad_tlv_ok(uint8_t const *data, size_t length,
size_t dv_type, size_t dv_length);
+ssize_t data2vp(RADIUS_PACKET *packet, RADIUS_PACKET const *original,
+ char const *secret,
+ DICT_ATTR const *da, uint8_t const *start,
+ size_t const attrlen, size_t const packetlen,
+ VALUE_PAIR **pvp);
+
ssize_t rad_attr2vp(RADIUS_PACKET *packet, RADIUS_PACKET const *original,
char const *secret,
uint8_t const *data, size_t length,
int8_t paircmp_value(VALUE_PAIR const *a, VALUE_PAIR const *b);
int8_t paircmp_op(VALUE_PAIR const *a, FR_TOKEN op, VALUE_PAIR const *b);
int8_t paircmp(VALUE_PAIR *a, VALUE_PAIR *b);
+int8_t pairlistcmp(VALUE_PAIR *a, VALUE_PAIR *b);
typedef int8_t (*fr_pair_cmp_t)(VALUE_PAIR const *a, VALUE_PAIR const *b);
int8_t attrcmp(VALUE_PAIR const *a, VALUE_PAIR const *b);
--- /dev/null
+#ifndef FR_PCAP_H
+#define FR_PCAP_H
+/*
+ * This program is is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, version 2 if the
+ * License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+/**
+ * $Id$
+ * @file include/pcap.h
+ * @brief Prototypes and constants for PCAP functions.
+ *
+ * @author Arran Cudbard-Bell <a.cudbardb@freeradius.org>
+ * @copyright 2013 Arran Cudbard-Bell <a.cudbardb@freeradius.org>
+ */
+#include <freeradius-devel/libradius.h>
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <pcap.h>
+
+/*
+ * Length of a DEC/Intel/Xerox or 802.3 Ethernet header.
+ * Note that some compilers may pad "struct ether_header" to
+ * a multiple of 4 *bytes, for example, so "sizeof (struct
+ * ether_header)" may not give the right answer.
+ *
+ * 6 Byte SRC, 6 Byte DST, 2 Byte Ether type, 4 Byte CVID, 4 Byte SVID
+ */
+#define ETHER_HDRLEN 22
+#define IP_HDRLEN 60
+
+/*
+ * RADIUS packet length.
+ * RFC 2865, Section 3., subsection 'length' says:
+ * " ... and maximum length is 4096."
+ */
+#define MAX_RADIUS_LEN 4096
+#define MIN_RADIUS_LEN 20
+#define SNAPLEN ETHER_HDRLEN + IP_HDRLEN + sizeof(struct udp_header) + MAX_RADIUS_LEN
+#define PCAP_BUFFER_DEFAULT (10000)
+/*
+ * It's unclear why this differs between platforms
+ */
+#ifndef __linux__
+# define PCAP_NONBLOCK_TIMEOUT (0)
+#else
+# define PCAP_NONBLOCK_TIMEOUT (-1)
+#endif
+
+#ifndef BIOCIMMEDIATE
+#define BIOCIMMEDIATE (2147762800)
+#endif
+
+/*
+ * Older versions of libpcap don't define this
+ */
+#ifndef PCAP_NETMASK_UNKNOWN
+# define PCAP_NETMASK_UNKNOWN 0
+#endif
+
+/*
+ * The number of bytes in an ethernet (MAC) address.
+ */
+#define ETHER_ADDR_LEN 6
+
+/*
+ * Structure of a DEC/Intel/Xerox or 802.3 Ethernet header.
+ */
+struct ethernet_header {
+ uint8_t ether_dst[ETHER_ADDR_LEN];
+ uint8_t ether_src[ETHER_ADDR_LEN];
+ uint16_t ether_type;
+};
+
+/*
+ * Structure of an internet header, naked of options.
+ */
+
+#define IP_V(ip) (((ip)->ip_vhl & 0xf0) >> 4)
+#define IP_HL(ip) ((ip)->ip_vhl & 0x0f)
+
+#define I_DF 0x4000 //!< Dont fragment flag.
+#define IP_MF 0x2000 //!< More fragments flag.
+#define IP_OFFMASK 0x1fff //!< Mask for fragmenting bits.
+
+typedef struct ip_header {
+ uint8_t ip_vhl; //!< Header length, version.
+
+ uint8_t ip_tos; //!< Type of service.
+ uint16_t ip_len; //!< Total length.
+ uint16_t ip_id; //!< identification.
+ uint16_t ip_off; //!< Fragment offset field.
+
+ uint8_t ip_ttl; //!< Time To Live.
+ uint8_t ip_p; //!< Protocol.
+ uint16_t ip_sum; //!< Checksum.
+ struct in_addr ip_src, ip_dst; //!< Src and Dst address
+} ip_header_t;
+
+typedef struct ip_header6 {
+ uint32_t ip_vtcfl; //!< Version, traffic class, flow label.
+ uint16_t ip_len; //!< Payload length
+
+ uint8_t ip_next; //!< Next header (protocol)
+ uint8_t ip_hopl; //!< IP Hop Limit
+
+ struct in6_addr ip_src, ip_dst; //!< Src and Dst address
+} ip_header6_t;
+
+/*
+ * UDP protocol header.
+ * Per RFC 768, September, 1981.
+ */
+typedef struct udp_header {
+ uint16_t src; //!< Source port.
+ uint16_t dst; //!< Destination port.
+ uint16_t len; //!< UDP length.
+ uint16_t checksum; //!< UDP checksum.
+} udp_header_t;
+
+typedef struct radius_packet_t {
+ uint8_t code;
+ uint8_t id;
+ uint8_t length[2];
+ uint8_t vector[AUTH_VECTOR_LEN];
+ uint8_t data[1];
+} radius_packet_t;
+
+#define AUTH_HDR_LEN 20
+
+typedef enum {
+ PCAP_INVALID = 0,
+ PCAP_INTERFACE_IN,
+ PCAP_FILE_IN,
+ PCAP_STDIO_IN,
+ PCAP_INTERFACE_OUT,
+ PCAP_FILE_OUT,
+ PCAP_STDIO_OUT
+} fr_pcap_type_t;
+
+extern const FR_NAME_NUMBER pcap_types[];
+
+/*
+ * Internal pcap structures
+ */
+typedef struct fr_pcap fr_pcap_t;
+struct fr_pcap {
+ char errbuf[PCAP_ERRBUF_SIZE]; //!< Last error on this interface.
+ fr_pcap_type_t type; //!< What type of handle this is.
+ char *name; //!< Name of file or interface.
+ bool promiscuous; //!< Whether the interface is in promiscuous mode.
+ //!< Only valid for live capture handles.
+ int buffer_pkts; //!< How big to make the PCAP ring buffer.
+ //!< Actual buffer size is SNAPLEN * buffer.
+ //!< Only valid for live capture handles.
+
+ pcap_t *handle; //!< libpcap handle.
+ pcap_dumper_t *dumper; //!< libpcap dumper handle.
+
+ int link_type; //!< Link layer type.
+
+ int fd; //!< Selectable file descriptor we feed to select.
+ struct pcap_stat pstats; //!< The last set of pcap stats for this handle.
+
+ fr_pcap_t *next; //!< Next handle in collection.
+};
+
+
+fr_pcap_t *fr_pcap_init(TALLOC_CTX *ctx, char const *name, fr_pcap_type_t type);
+int fr_pcap_open(fr_pcap_t *handle);
+int fr_pcap_apply_filter(fr_pcap_t *handle, char const *expression);
+char *fr_pcap_device_names(TALLOC_CTX *ctx, fr_pcap_t *handle, char c);
+ssize_t fr_pcap_link_layer_offset(uint8_t const *data, size_t len, int link_type);
+uint16_t fr_udp_checksum(uint8_t const *data, uint16_t len, uint16_t checksum,
+ struct in_addr const src_addr, struct in_addr const dst_addr);
+#endif
+
/*
- * radsniff.h Structures and defines for the RADIUS sniffer.
+ * This program is is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, version 2 if the
+ * License as published by the Free Software Foundation.
*
- * Version: $Id$
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
*
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+/**
+ * $Id$
+ * @file radsniff.h
+ * @brief Structures and prototypes for the RADIUS sniffer.
*
- * Copyright 2006 The FreeRADIUS server project
- * Copyright 2006 Nicolas Baradakis <nicolas.baradakis@cegetel.net>
+ * @copyright 2013 Arran Cudbard-Bell <arran.cudbardb@freeradius.org>
+ * @copyright 2006 The FreeRADIUS server project
+ * @copyright 2006 Nicolas Baradakis <nicolas.baradakis@cegetel.net>
*/
RCSIDH(radsniff_h, "$Id$")
#include <sys/types.h>
#include <netinet/in.h>
+#include <pcap/pcap.h>
+#include <freeradius-devel/libradius.h>
+#include <freeradius-devel/pcap.h>
+#include <freeradius-devel/event.h>
+
+#ifdef HAVE_COLLECTDC_H
+# include <collectd/client.h>
+#endif
+
+#define RS_DEFAULT_PREFIX "radsniff" //!< Default instance
+#define RS_DEFAULT_SECRET "testing123" //!< Default secret
+#define RS_DEFAULT_TIMEOUT 5200 //!< Standard timeout of 5s + 300ms to cover network latency
+#define RS_FORCE_YIELD 1000 //!< Service another descriptor every X number of packets
+#define RS_RETRANSMIT_MAX 5 //!< Maximum number of times we expect to see a packet retransmitted
+#define RS_MAX_ATTRS 50 //!< Maximum number of attributes we can filter on.
+#define RS_SOCKET_REOPEN_DELAY 5000 //!< How long we delay re-opening a collectd socket.
+
/*
- * The number of bytes in an ethernet (MAC) address.
+ * Logging macros
*/
-#define ETHER_ADDR_LEN 6
+#undef DEBUG2
+#define DEBUG2(fmt, ...) if (fr_debug_flag > 2) fprintf(fr_log_fp , fmt "\n", ## __VA_ARGS__)
+#undef DEBUG
+#define DEBUG(fmt, ...) if (fr_debug_flag > 1) fprintf(fr_log_fp , fmt "\n", ## __VA_ARGS__)
+#undef INFO
+#define INFO(fmt, ...) if (fr_debug_flag > 0) fprintf(fr_log_fp , fmt "\n", ## __VA_ARGS__)
-/*
- * Structure of a DEC/Intel/Xerox or 802.3 Ethernet header.
+#define ERROR(fmt, ...) fr_perror("radsniff: " fmt, ## __VA_ARGS__)
+
+#define RIDEBUG_ENABLED() (conf->print_packet && (fr_debug_flag > 0))
+#define RDEBUG_ENABLED() (conf->print_packet && (fr_debug_flag > 1))
+#define RDEBUG_ENABLED2() (conf->print_packet && (fr_debug_flag > 2))
+
+#define REDEBUG(fmt, ...) if (conf->print_packet) fprintf(fr_log_fp , "%s (%" PRIu64 ") " fmt ": %s\n", timestr, count, ## __VA_ARGS__, fr_strerror())
+#define RIDEBUG(fmt, ...) if (conf->print_packet && (fr_debug_flag > 0)) fprintf(fr_log_fp , "%s (%" PRIu64 ") " fmt "\n", timestr, count, ## __VA_ARGS__)
+#define RDEBUG(fmt, ...) if (conf->print_packet && (fr_debug_flag > 1)) fprintf(fr_log_fp , "%s (%" PRIu64 ") " fmt "\n", timestr, count, ## __VA_ARGS__)
+#define RDEBUG2(fmt, ...) if (conf->print_packet && (fr_debug_flag > 2)) fprintf(fr_log_fp , "%s (%" PRIu64 ") " fmt "\n", timestr, count, ## __VA_ARGS__)
+
+typedef enum {
+ RS_NORMAL = 0x01,
+ RS_UNLINKED = 0x02,
+ RS_RTX = 0x04,
+ RS_REUSED = 0x08,
+ RS_ERROR = 0x10,
+ RS_LOST = 0x20
+} rs_status_t;
+
+typedef void (*rs_packet_logger_t)(uint64_t count, rs_status_t status, fr_pcap_t *handle, RADIUS_PACKET *packet,
+ struct timeval *elapsed, struct timeval *latency, bool response, bool body);
+typedef enum {
+#ifdef HAVE_COLLECTDC_H
+ RS_STATS_OUT_COLLECTD = 1,
+#endif
+ RS_STATS_OUT_STDIO
+} stats_out_t;
+
+typedef struct rs rs_t;
+
+#ifdef HAVE_COLLECTDC_H
+typedef struct rs_stats_tmpl rs_stats_tmpl_t;
+typedef struct rs_stats_value_tmpl rs_stats_value_tmpl_t;
+#endif
+
+typedef struct rs_counters {
+ uint64_t type[PW_CODE_MAX];
+} rs_counters_t;
+
+/** Stats for a single interval
+ *
+ * And interval is defined as the time between a call to the stats output function.
*/
-struct ethernet_header {
- uint8_t ethernet_dhost[ETHER_ADDR_LEN];
- uint8_t ethernet_shost[ETHER_ADDR_LEN];
- uint16_t ethernet_type;
-};
+typedef struct rs_latency {
+ int intervals; //!< Number of stats intervals.
-/*
- * Length of a DEC/Intel/Xerox or 802.3 Ethernet header.
- * Note that some compilers may pad "struct ether_header" to
- * a multiple of 4 *bytes, for example, so "sizeof (struct
- * ether_header)" may not give the right answer.
+ double latency_smoothed; //!< Smoothed moving average.
+ uint64_t latency_smoothed_count; //!< Number of CMA datapoints processed.
+
+ struct {
+ uint64_t received_total; //!< Total received over interval.
+ uint64_t linked_total; //!< Total request/response pairs over interval.
+ uint64_t unlinked_total; //!< Total unlinked over interval.
+ uint64_t reused_total; //!< Total reused over interval.
+ uint64_t lost_total; //!< Total packets definitely lost in this interval.
+ uint64_t rt_total[RS_RETRANSMIT_MAX + 1]; //!< Number of RTX until complete
+ //!< over interval.
+
+
+ double received; //!< Number of this type of packet we've received.
+ double linked; //!< Number of request/response pairs
+ double unlinked; //!< Response with no request.
+ double reused; //!< ID re-used too quickly.
+ double lost; //!< Never got a response to a request.
+ double rt[RS_RETRANSMIT_MAX + 1]; //!< Number of times we saw the same
+ //!< request packet.
+
+ long double latency_total; //!< Total latency between requests/responses in the
+ //!< interval.
+ double latency_average; //!< Average latency (this iteration).
+
+ double latency_high; //!< Latency high water mark.
+ double latency_low; //!< Latency low water mark.
+ } interval;
+} rs_latency_t;
+
+typedef struct rs_malformed {
+ uint64_t min_length_packet;
+ uint64_t min_length_field;
+ uint64_t min_length_mimatch;
+ uint64_t header_overflow;
+ uint64_t invalid_attribute;
+ uint64_t attribute_too_short;
+ uint64_t attribute_overflow;
+ uint64_t ma_invalid_length;
+ uint64_t attribute_underflow;
+ uint64_t too_many_attributes;
+ uint64_t ma_missing;
+} rs_malformed_t;
+
+/** One set of statistics
+ *
*/
-#define ETHER_HDRLEN 14
+typedef struct rs_stats {
+ int intervals; //!< Number of stats intervals.
-/*
- * Structure of an internet header, naked of options.
+ rs_latency_t exchange[PW_CODE_MAX]; //!< We end up allocating ~16K, but memory is cheap so
+ //!< what the hell. This is required because instances of
+ //!< FreeRADIUS delay Access-Rejects, which would artificially
+ //!< increase latency stats for Access-Requests.
+
+ struct timeval quiet; //!< We may need to 'mute' the stats if libpcap starts
+ //!< dropping packets, or we run out of memory.
+} rs_stats_t;
+
+/** Wrapper for RADIUS_PACKET
+ *
+ * Allows an event to be associated with a request packet. This is required because we need to disarm
+ * the event timer when a response is received, so we don't erroneously log the response as lost.
+ */
+typedef struct rs_request {
+ uint64_t id; //!< Monotonically increasing packet counter.
+ fr_event_t *event; //!< Event created when we received the original request.
+
+ struct timeval when; //!< Time when the packet was received, or next time an event
+ //!< is scheduled.
+ fr_pcap_t *in; //!< PCAP handle the original request was received on.
+ RADIUS_PACKET *packet; //!< The original packet.
+ RADIUS_PACKET *expect; //!< Request/response.
+ RADIUS_PACKET *linked; //!< The subsequent response or forwarded request the packet
+ //!< was linked against.
+
+ uint64_t rt_req; //!< Number of times we saw the same request packet.
+ uint64_t rt_rsp; //!< Number of times we saw a retransmitted response
+ //!< packet.
+ rs_latency_t *stats_req; //!< Latency entry for the request type.
+ rs_latency_t *stats_rsp; //!< Latency entry for the request type.
+
+ bool silent_cleanup; //!< Cleanup was forced before normal expiry period,
+ //!< ignore stats about packet loss.
+
+ VALUE_PAIR *link_vps; //!< VALUE_PAIRs used to link retransmissions.
+
+ bool in_request_tree; //!< Whether the request is currently in the request tree.
+ bool in_link_tree; //!< Whether the request is currently in the linked tree.
+} rs_request_t;
+
+/** Statistic write/print event
+ *
+ */
+typedef struct rs_event {
+ fr_event_list_t *list; //!< The event list.
+
+ fr_pcap_t *in; //!< PCAP handle event occurred on.
+ fr_pcap_t *out; //!< Where to write output.
+
+ rs_stats_t *stats; //!< Where to write stats.
+} rs_event_t;
+
+/** FD data which gets passed to callbacks
+ *
+ */
+typedef struct rs_update {
+ fr_event_list_t *list; //!< List to insert new event into.
+
+ fr_pcap_t *in; //!< Linked list of PCAP handles to check for drops.
+ rs_stats_t *stats; //!< Stats to process.
+} rs_update_t;
+
+
+struct rs {
+ bool from_file; //!< Were reading pcap data from files.
+ bool from_dev; //!< Were reading pcap data from devices.
+ bool from_stdin; //!< Were reading pcap data from stdin.
+ bool to_file; //!< Were writing pcap data to files.
+ bool to_stdout; //!< Were writing pcap data to stdout.
+
+ bool daemonize; //!< Daemonize and write PID out to file.
+ char const *pidfile; //!< File to write PID to.
+
+ bool from_auto; //!< From list was auto-generated.
+ bool promiscuous; //!< Capture in promiscuous mode.
+ bool print_packet; //!< Print packet info, disabled with -W
+ bool decode_attrs; //!< Whether we should decode attributes in the request
+ //!< and response.
+
+ char const *radius_secret; //!< Secret to decode encrypted attributes.
+
+ char *pcap_filter; //!< PCAP filter string applied to live capture devices.
+
+ char *list_attributes; //!< Raw attribute filter string.
+ DICT_ATTR const *list_da[RS_MAX_ATTRS]; //!< Output CSV with these attribute values.
+ int list_da_num;
+
+ char *link_attributes; //!< Names of DICT_ATTRs to use for rtx.
+ DICT_ATTR const *link_da[RS_MAX_ATTRS]; //!< DICT_ATTRs to link on.
+ int link_da_num; //!< Number of rtx DICT_ATTRs.
+
+ char const *filter_request; //!< Raw request filter string.
+ char const *filter_response; //!< Raw response filter string.
+
+ VALUE_PAIR *filter_request_vps; //!< Sorted filter vps.
+ VALUE_PAIR *filter_response_vps; //!< Sorted filter vps.
+ PW_CODE filter_request_code; //!< Filter request packets by code.
+ PW_CODE filter_response_code; //!< Filter response packets by code.
+
+ rs_status_t event_flags; //!< Events we log and capture on.
+ rs_packet_logger_t logger; //!< Packet logger
+
+ int buffer_pkts; //!< Size of the ring buffer to setup for live capture.
+ uint64_t limit; //!< Maximum number of packets to capture
+
+ struct {
+ int interval; //!< Time between stats updates in seconds.
+ stats_out_t out; //!< Where to write stats.
+ int timeout; //!< Maximum length of time we wait for a response.
+
+#ifdef HAVE_COLLECTDC_H
+ char const *collectd; //!< Collectd server/port/unixsocket
+ char const *prefix; //!< Prefix collectd stats with this value.
+ lcc_connection_t *handle; //!< Collectd client handle.
+ rs_stats_tmpl_t *tmpl; //!< The stats templates we created on startup.
+#endif
+ } stats;
+};
+
+#ifdef HAVE_COLLECTDC_H
+
+/** Callback for processing stats values.
+ *
*/
-struct ip_header {
- uint8_t ip_vhl; /* header length, version */
-#define IP_V(ip) (((ip)->ip_vhl & 0xf0) >> 4)
-#define IP_HL(ip) ((ip)->ip_vhl & 0x0f)
- uint8_t ip_tos; /* type of service */
- uint16_t ip_len; /* total length */
- uint16_t ip_id; /* identification */
- uint16_t ip_off; /* fragment offset field */
-#define I_DF 0x4000 /* dont fragment flag */
-#define IP_MF 0x2000 /* more fragments flag */
-#define IP_OFFMASK 0x1fff /* mask for fragmenting bits */
- uint8_t ip_ttl; /* time to live */
- uint8_t ip_p; /* protocol */
- uint16_t ip_sum; /* checksum */
- struct in_addr ip_src,ip_dst; /* source and dest address */
+typedef void (*rs_stats_cb_t)(rs_t *conf, rs_stats_value_tmpl_t *tmpl);
+struct rs_stats_value_tmpl {
+ void *src; //!< Pointer to source field in struct. Must be set by
+ //!< stats_collectdc_init caller.
+ int type; //!< Stats type.
+ rs_stats_cb_t cb; //!< Callback used to process stats
+ void *dst; //!< Pointer to dst field in value struct. Must be set
+ //!< by stats_collectdc_init caller.
};
-/*
- * UDP protocol header.
- * Per RFC 768, September, 1981.
+/** Stats templates
+ *
+ * This gets processed to turn radsniff stats structures into collectd lcc_value_list_t structures.
*/
-struct udp_header {
- uint16_t udp_sport; /* source port */
- uint16_t udp_dport; /* destination port */
- uint16_t udp_ulen; /* udp length */
- uint16_t udp_sum; /* udp checksum */
+struct rs_stats_tmpl
+{
+ rs_stats_value_tmpl_t *value_tmpl; //!< Value template
+ void *stats; //!< Struct containing the raw stats to process
+ lcc_value_list_t *value; //!< Collectd stats struct to populate
+
+ rs_stats_tmpl_t *next; //!< Next...
};
/*
- * RADIUS packet length.
- * RFC 2865, Section 3., subsection 'length' says:
- * " ... and maximum length is 4096."
+ * collectd.c - Registration and processing functions
*/
-#define MAX_RADIUS_LEN 4096
-#define MIN_RADIUS_LEN 20
-#define SNAPLEN (sizeof(struct ethernet_header) + sizeof(struct ip_header) + sizeof(struct udp_header) + MAX_RADIUS_LEN)
-
-typedef struct radius_packet_t {
- uint8_t code;
- uint8_t id;
- uint8_t length[2];
- uint8_t vector[AUTH_VECTOR_LEN];
- uint8_t data[1];
-} radius_packet_t;
-
-#define AUTH_HDR_LEN 20
+rs_stats_tmpl_t *rs_stats_collectd_init_latency(TALLOC_CTX *ctx, rs_stats_tmpl_t **out, rs_t *conf,
+ char const *type, rs_latency_t *stats, PW_CODE code);
+void rs_stats_collectd_do_stats(rs_t *conf, rs_stats_tmpl_t *tmpls, struct timeval *now);
+int rs_stats_collectd_open(rs_t *conf);
+int rs_stats_collectd_close(rs_t *conf);
+
+#endif
#
TARGET := libfreeradius-radius.a
-SOURCES := cbuff.c cursor.c debug.c dict.c filters.c hash.c hmac.c \
- hmacsha1.c isaac.c log.c misc.c missing.c md4.c \
- md5.c print.c radius.c rbtree.c sha1.c snprintf.c \
- strlcat.c strlcpy.c token.c udpfromto.c \
- valuepair.c fifo.c packet.c event.c getaddrinfo.c \
- heap.c tcp.c base64.c version.c
+SOURCES := cbuff.c cursor.c debug.c dict.c filters.c hash.c hmac.c hmacsha1.c \
+ isaac.c log.c misc.c missing.c md4.c md5.c pcap.c print.c radius.c rbtree.c \
+ sha1.c snprintf.c strlcat.c strlcpy.c token.c udpfromto.c valuepair.c fifo.c \
+ packet.c event.c getaddrinfo.c heap.c tcp.c base64.c version.c
SRC_CFLAGS := -D_LIBRADIUS -I$(top_builddir)/src
# System libraries discovered by our top level configure script, links things
# like pthread and the regexp libraries.
-TGT_LDLIBS := $(LIBS)
+TGT_LDLIBS := $(LIBS) $(PCAP_LIBS)
+TGT_LDFLAGS := $(LDFLAGS) $(PCAP_LDFLAGS)
return el;
}
+int fr_event_list_num_fds(fr_event_list_t *el)
+{
+ if (!el) return 0;
+
+ return el->num_readers;
+}
+
int fr_event_list_num_elements(fr_event_list_t *el)
{
if (!el) return 0;
el->exit = code;
}
+bool fr_event_loop_exiting(fr_event_list_t *el)
+{
+ return (el->exit != 0);
+}
+
int fr_event_loop(fr_event_list_t *el)
{
int i, rcode, maxfd = 0;
--- /dev/null
+/*
+ * This program is is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, version 2 if the
+ * License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+/**
+ * $Id$
+ * @file pcap.c
+ * @brief Wrappers around libpcap functions
+ *
+ * @author Arran Cudbard-Bell <a.cudbardb@freeradius.org>
+ * @copyright 2013 Arran Cudbard-Bell <a.cudbardb@freeradius.org>
+ */
+#ifdef HAVE_LIBPCAP
+
+#include <sys/ioctl.h>
+#include <pcap/pcap.h>
+#include <freeradius-devel/pcap.h>
+
+const FR_NAME_NUMBER pcap_types[] = {
+ { "interface", PCAP_INTERFACE_IN },
+ { "file", PCAP_FILE_IN },
+ { "stdio", PCAP_STDIO_IN },
+ { "interface", PCAP_INTERFACE_OUT },
+ { "file", PCAP_FILE_OUT },
+ { "stdio", PCAP_STDIO_OUT },
+
+ { NULL, 0}
+};
+
+/** Talloc destructor to free pcap resources associated with a handle.
+ *
+ * @param pcap to free.
+ * @return 0
+ */
+static int _free_pcap(fr_pcap_t *pcap) {
+ switch (pcap->type) {
+ case PCAP_INTERFACE_IN:
+ case PCAP_INTERFACE_OUT:
+ case PCAP_FILE_IN:
+ case PCAP_STDIO_IN:
+ if (pcap->handle) {
+ pcap_close(pcap->handle);
+
+ if (pcap->fd > 0) {
+ close(pcap->fd);
+ }
+ }
+
+ break;
+
+ case PCAP_FILE_OUT:
+ case PCAP_STDIO_OUT:
+ if (pcap->dumper) {
+ pcap_dump_flush(pcap->dumper);
+ pcap_dump_close(pcap->dumper);
+ }
+
+ break;
+ case PCAP_INVALID:
+ break;
+ }
+
+ return 0;
+}
+
+/** Initialise a pcap handle abstraction
+ *
+ * @param ctx talloc TALLOC_CTX to allocate handle in.
+ * @param name of interface or file to open.
+ * @param type of handle to initialise.
+ * @return new handle or NULL on error.
+ */
+fr_pcap_t *fr_pcap_init(TALLOC_CTX *ctx, char const *name, fr_pcap_type_t type)
+{
+ fr_pcap_t *this = talloc_zero(ctx, fr_pcap_t);
+ if (!this) {
+ return NULL;
+ }
+
+ talloc_set_destructor(this, _free_pcap);
+ this->name = talloc_typed_strdup(this, name);
+ this->type = type;
+ this->link_type = -1;
+
+ return this;
+}
+
+/** Open a PCAP handle abstraction
+ *
+ * This opens interfaces for capture or injection, or files/streams for reading/writing.
+ * @param pcap created with fr_pcap_init.
+ * @return 0 on success, -1 on error.
+ */
+int fr_pcap_open(fr_pcap_t *pcap)
+{
+ switch (pcap->type) {
+ case PCAP_INTERFACE_OUT:
+ case PCAP_INTERFACE_IN:
+ {
+#if defined(HAVE_PCAP_CREATE) && defined(HAVE_PCAP_ACTIVATE)
+ pcap->handle = pcap_create(pcap->name, pcap->errbuf);
+ if (!pcap->handle) {
+ fr_strerror_printf("%s", pcap->errbuf);
+ return -1;
+ }
+ if (pcap_set_snaplen(pcap->handle, SNAPLEN) != 0) {
+ create_error:
+ fr_strerror_printf("%s", pcap_geterr(pcap->handle));
+ pcap_close(pcap->handle);
+ pcap->handle = NULL;
+ return -1;
+ }
+ if (pcap_set_timeout(pcap->handle, PCAP_NONBLOCK_TIMEOUT) != 0) {
+ goto create_error;
+ }
+ if (pcap_set_promisc(pcap->handle, pcap->promiscuous) != 0) {
+ goto create_error;
+ }
+
+ if (pcap_set_buffer_size(pcap->handle, SNAPLEN *
+ (pcap->buffer_pkts ? pcap->buffer_pkts : PCAP_BUFFER_DEFAULT)) != 0) {
+ goto create_error;
+ }
+ if (pcap_activate(pcap->handle) != 0) {
+ goto create_error;
+ }
+#else
+ /*
+ * Alternative functions for libpcap < 1.0
+ */
+ pcap->handle = pcap_open_live(pcap->name, SNAPLEN, pcap->promiscuous, PCAP_NONBLOCK_TIMEOUT,
+ pcap->errbuf);
+ if (!pcap->handle) {
+ fr_strerror_printf("%s", pcap->errbuf);
+ return -1;
+ }
+#endif
+ /*
+ * Despite accepting an errbuff, pcap_setnonblock doesn't seem to write
+ * error message there in newer versions.
+ */
+ if (pcap_setnonblock(pcap->handle, true, pcap->errbuf) != 0) {
+ fr_strerror_printf("%s", *pcap->errbuf != '\0' ?
+ pcap->errbuf : pcap_geterr(pcap->handle));
+ pcap_close(pcap->handle);
+ pcap->handle = NULL;
+ return -1;
+ }
+
+ pcap->fd = pcap_get_selectable_fd(pcap->handle);
+ pcap->link_type = pcap_datalink(pcap->handle);
+#ifndef __linux__
+ {
+ int value = 1;
+ if (ioctl(pcap->fd, BIOCIMMEDIATE, &value) < 0) {
+ fr_strerror_printf("Failed setting BIOCIMMEDIATE: %s", fr_syserror(errno));
+ }
+ }
+#endif
+ }
+ break;
+
+ case PCAP_FILE_IN:
+ pcap->handle = pcap_open_offline(pcap->name, pcap->errbuf);
+ if (!pcap->handle) {
+ fr_strerror_printf("%s", pcap->errbuf);
+
+ return -1;
+ }
+ pcap->fd = pcap_get_selectable_fd(pcap->handle);
+ pcap->link_type = pcap_datalink(pcap->handle);
+ break;
+
+ case PCAP_FILE_OUT:
+ if (pcap->link_type < 0) {
+ pcap->link_type = DLT_EN10MB;
+ }
+ pcap->handle = pcap_open_dead(pcap->link_type, SNAPLEN);
+ if (!pcap->handle) {
+ fr_strerror_printf("Unknown error occurred opening dead PCAP handle");
+
+ return -1;
+ }
+ pcap->dumper = pcap_dump_open(pcap->handle, pcap->name);
+ if (!pcap->dumper) {
+ fr_strerror_printf("%s", pcap_geterr(pcap->handle));
+
+ return -1;
+ }
+ break;
+
+#ifdef HAVE_PCAP_FOPEN_OFFLINE
+ case PCAP_STDIO_IN:
+ pcap->handle = pcap_fopen_offline(stdin, pcap->errbuf);
+ if (!pcap->handle) {
+ fr_strerror_printf("%s", pcap->errbuf);
+
+ return -1;
+ }
+ pcap->fd = pcap_get_selectable_fd(pcap->handle);
+ pcap->link_type = pcap_datalink(pcap->handle);
+ break;
+#else
+ case PCAP_STDIO_IN:
+ fr_strerror_printf("This version of libpcap does not support reading pcap data from streams");
+
+ return -1;
+#endif
+#ifdef HAVE_PCAP_DUMP_FOPEN
+ case PCAP_STDIO_OUT:
+ pcap->handle = pcap_open_dead(DLT_EN10MB, SNAPLEN);
+ pcap->dumper = pcap_dump_fopen(pcap->handle, stdout);
+ if (!pcap->dumper) {
+ fr_strerror_printf("%s", pcap_geterr(pcap->handle));
+
+ return -1;
+ }
+ break;
+#else
+ case PCAP_STDIO_OUT:
+ fr_strerror_printf("This version of libpcap does not support writing pcap data to streams");
+
+ return -1;
+#endif
+ case PCAP_INVALID:
+ default:
+ fr_assert(0);
+ fr_strerror_printf("Bad handle type (%i)", pcap->type);
+ return -1;
+ }
+
+ return 0;
+}
+
+/** Apply capture filter to an interface
+ *
+ * @param pcap handle to apply filter to.
+ * @param expression PCAP expression to use as a filter.
+ * @return 0 on success, 1 can't apply to interface, -1 on error.
+ */
+int fr_pcap_apply_filter(fr_pcap_t *pcap, char const *expression)
+{
+ bpf_u_int32 mask = 0; /* Our netmask */
+ bpf_u_int32 net = 0; /* Our IP */
+ struct bpf_program fp;
+
+ /*
+ * nflog devices are in the set of devices selected by default.
+ * Unfortunately there's a bug in all released version of libpcap (as of 2/1/2014)
+ * which triggers an abort if pcap_setfilter is called on an nflog interface.
+ *
+ * See here:
+ * https://github.com/the-tcpdump-group/libpcap/commit/676cf8a61ed240d0a86d471ef419f45ba35dba80
+ */
+#ifdef DLT_NFLOG
+ if (pcap->link_type == DLT_NFLOG) {
+ fr_strerror_printf("NFLOG link-layer type filtering not implemented");
+
+ return 1;
+ }
+#endif
+
+ if (pcap->type == PCAP_INTERFACE_IN) {
+ if (pcap_lookupnet(pcap->name, &net, &mask, pcap->errbuf) < 0) {
+ fr_strerror_printf("Failed getting IP for interface \"%s\", using defaults: %s",
+ pcap->name, pcap->errbuf);
+ }
+ }
+
+ if (pcap_compile(pcap->handle, &fp, expression, 0, net) < 0) {
+ fr_strerror_printf("%s", pcap_geterr(pcap->handle));
+
+ return -1;
+ }
+
+ if (pcap_setfilter(pcap->handle, &fp) < 0) {
+ fr_strerror_printf("%s", pcap_geterr(pcap->handle));
+
+ return -1;
+ }
+
+ return 0;
+}
+
+char *fr_pcap_device_names(TALLOC_CTX *ctx, fr_pcap_t *pcap, char c)
+{
+ fr_pcap_t *pcap_p;
+ char *buff, *p;
+ size_t len = 0, left = 0, wrote;
+
+ if (!pcap) {
+ goto null;
+ }
+
+ for (pcap_p = pcap;
+ pcap_p;
+ pcap_p = pcap_p->next) {
+ len += talloc_array_length(pcap_p->name); // Talloc array length includes the \0
+ }
+
+ if (!len) {
+ null:
+ return talloc_zero_array(ctx, char, 1);
+ }
+
+ left = len + 1;
+ buff = p = talloc_zero_array(ctx, char, left);
+ for (pcap_p = pcap;
+ pcap_p;
+ pcap_p = pcap_p->next) {
+ wrote = snprintf(p, left, "%s%c", pcap_p->name, c);
+ left -= wrote;
+ p += wrote;
+ }
+ buff[len - 1] = '\0';
+
+ return buff;
+}
+
+/** Returns the length of the link layer header
+ *
+ * Libpcap does not include a decoding function to skip the L2 header, but it does
+ * at least inform us of the type.
+ *
+ * Unfortunately some headers are of variable length (like ethernet), so additional
+ * decoding logic is required.
+ *
+ * @note No header data is returned, this is only meant to be used to determine how
+ * data to consume before attempting to parse the IP header.
+ *
+ * @param data start of PCAP data.
+ * @param len caplen.
+ * @param link_type value returned from pcap_linktype.
+ * @return the length of the header, or -1 on error.
+ */
+ssize_t fr_pcap_link_layer_offset(uint8_t const *data, size_t len, int link_type)
+{
+ uint8_t const *p = data;
+
+ switch (link_type) {
+ case DLT_RAW:
+ break;
+
+ case DLT_NULL:
+ case DLT_LOOP:
+ p += 4;
+ if (((size_t)(p - data)) > len) {
+ goto ood;
+ }
+ break;
+
+ case DLT_EN10MB:
+ {
+ uint16_t ether_type; /* Ethernet type */
+ int i;
+
+ p += 12; /* SRC/DST Mac-Addresses */
+ if (((size_t)(p - data)) > len) {
+ goto ood;
+ }
+
+ for (i = 0; i < 3; i++) {
+ ether_type = ntohs(*((uint16_t const *) p));
+ switch (ether_type) {
+ /*
+ * There are a number of devices out there which
+ * double tag with 0x8100 *sigh*
+ */
+ case 0x8100: /* CVLAN */
+ case 0x9100: /* SVLAN */
+ case 0x9200: /* SVLAN */
+ case 0x9300: /* SVLAN */
+ p += 4;
+ if (((size_t)(p - data)) > len) {
+ goto ood;
+ }
+ break;
+
+ default:
+ p += 2;
+ if (((size_t)(p - data)) > len) {
+ goto ood;
+ }
+ goto done;
+ }
+ }
+ fr_strerror_printf("Exceeded maximum level of VLAN tag nesting (2)");
+ return -1;
+ }
+
+ case DLT_LINUX_SLL:
+ p += 16;
+ if (((size_t)(p - data)) > len) {
+ goto ood;
+ }
+ break;
+
+ case DLT_PFLOG:
+ p += 28;
+ if (((size_t)(p - data)) > len) {
+ goto ood;
+ }
+ break;
+
+ default:
+ fr_strerror_printf("Unsupported link layer type %i", link_type);
+ }
+
+ done:
+ return p - data;
+
+ ood:
+ fr_strerror_printf("Out of data, needed %zu bytes, have %zu bytes", (size_t)(p - data), len);
+
+ return -1;
+}
+
+/** Calculate UDP checksum
+ *
+ * Zero out UDP checksum in UDP header before calling fr_udp_checksum to get 'expected' checksum.
+ *
+ * @param data Pointer to the start of the UDP header
+ * @param len value of udp length field in host byte order. Must be validated to make
+ * sure it won't overrun data buffer.
+ * @param checksum current checksum, leave as 0 to just enable validation.
+ * @param src_addr in network byte order.
+ * @param dst_addr in network byte order.
+ * @return 0 if the checksum is correct, else another number.
+ */
+uint16_t fr_udp_checksum(uint8_t const *data, uint16_t len, uint16_t checksum,
+ struct in_addr const src_addr, struct in_addr const dst_addr)
+{
+ uint64_t sum = 0; /* using 64bits avoids overflow check */
+ uint16_t const *p = (uint16_t const *)data;
+
+ uint16_t const *ip_src = (void const *) &src_addr.s_addr;
+ uint16_t const *ip_dst = (void const *) &dst_addr.s_addr;
+ uint16_t i;
+
+ sum += *(ip_src++);
+ sum += *ip_src;
+ sum += *(ip_dst++);
+ sum += *ip_dst;
+
+ sum += htons(IPPROTO_UDP);
+ sum += htons(len);
+
+ for (i = len; i > 1; i -= 2) {
+ sum += *p++;
+ }
+
+ if (i) {
+ sum += (0xff & *(uint8_t const *)p) << 8;
+ }
+
+ sum -= checksum;
+
+ while (sum >> 16) {
+ sum = (sum & 0xffff) + (sum >> 16);
+ }
+
+ return ((uint16_t) ~sum);
+}
+#endif
case PW_TYPE_IPV6PREFIX:
case PW_TYPE_IPV4PREFIX:
case PW_TYPE_ABINARY:
+ case PW_TYPE_ETHERNET: /* just in case */
data = (uint8_t const *) &vp->data;
break;
case PW_TYPE_BYTE:
len = 1; /* just in case */
- array[0] = vp->vp_integer & 0xff;
+ array[0] = vp->vp_byte;
data = array;
break;
case PW_TYPE_SHORT:
len = 2; /* just in case */
- array[0] = (vp->vp_integer >> 8) & 0xff;
- array[1] = vp->vp_integer & 0xff;
+ array[0] = (vp->vp_short >> 8) & 0xff;
+ array[1] = vp->vp_short & 0xff;
data = array;
break;
}
default: /* unknown type: ignore it */
- fr_strerror_printf("ERROR: Unknown attribute type %d",
- vp->da->type);
+ fr_strerror_printf("ERROR: Unknown attribute type %d", vp->da->type);
return -1;
}
case PW_CODE_AUTHENTICATION_REJECT:
case PW_CODE_ACCESS_CHALLENGE:
if (!original) {
- fr_strerror_printf("ERROR: Cannot sign response packet without a request packet.");
+ fr_strerror_printf("ERROR: Cannot sign response packet without a request packet");
return -1;
}
break;
* It wasn't assigned an Id, this is bad!
*/
if (packet->id < 0) {
- fr_strerror_printf("ERROR: RADIUS packets must be assigned an Id.");
+ fr_strerror_printf("ERROR: RADIUS packets must be assigned an Id");
return -1;
}
case PW_CODE_DISCONNECT_NAK:
case PW_CODE_COA_REQUEST:
case PW_CODE_COA_ACK:
- case PW_CODE_COA_NAK:
memset(hdr->vector, 0, AUTH_VECTOR_LEN);
break;
case PW_CODE_AUTHENTICATION_REJECT:
case PW_CODE_ACCESS_CHALLENGE:
if (!original) {
- fr_strerror_printf("ERROR: Cannot sign response packet without a request packet.");
+ fr_strerror_printf("ERROR: Cannot sign response packet without a request packet");
return -1;
}
memcpy(hdr->vector, original->vector,
}
-/**
- * @brief See if the data pointed to by PTR is a valid RADIUS packet.
+/** See if the data pointed to by PTR is a valid RADIUS packet.
+ *
+ * Packet is not 'const * const' because we may update data_len, if there's more data
+ * in the UDP packet than in the RADIUS packet.
*
- * packet is not 'const * const' because we may update data_len,
- * if there's more data in the UDP packet than in the RADIUS packet.
+ * @param packet to check
+ * @param flags to control decoding
+ * @param reason if not NULL, will have the failure reason written to where it points.
+ * @return bool, true on success, false on failure.
*/
-int rad_packet_ok(RADIUS_PACKET *packet, int flags)
+bool rad_packet_ok(RADIUS_PACKET *packet, int flags, decode_fail_t *reason)
{
uint8_t *attr;
size_t totallen;
bool require_ma = false;
bool seen_ma = false;
int num_attributes;
+ decode_fail_t failure = DECODE_FAIL_NONE;
/*
* Check for packets smaller than the packet header.
&packet->src_ipaddr.ipaddr,
host_ipaddr, sizeof(host_ipaddr)),
packet->data_len, AUTH_HDR_LEN);
- return 0;
+ failure = DECODE_FAIL_MIN_LENGTH_PACKET;
+ goto finish;
}
&packet->src_ipaddr.ipaddr,
host_ipaddr, sizeof(host_ipaddr)),
hdr->code);
- return 0;
+ failure = DECODE_FAIL_UNKNOWN_PACKET_CODE;
+ goto finish;
}
/*
&packet->src_ipaddr.ipaddr,
host_ipaddr, sizeof(host_ipaddr)),
totallen, AUTH_HDR_LEN);
- return 0;
+ failure = DECODE_FAIL_MIN_LENGTH_FIELD;
+ goto finish;
}
/*
&packet->src_ipaddr.ipaddr,
host_ipaddr, sizeof(host_ipaddr)),
packet->data_len, totallen);
- return 0;
+ failure = DECODE_FAIL_MIN_LENGTH_MISMATCH;
+ goto finish;
}
/*
inet_ntop(packet->src_ipaddr.af,
&packet->src_ipaddr.ipaddr,
host_ipaddr, sizeof(host_ipaddr)));
- return 0;
+ failure = DECODE_FAIL_HEADER_OVERFLOW;
+ goto finish;
}
/*
inet_ntop(packet->src_ipaddr.af,
&packet->src_ipaddr.ipaddr,
host_ipaddr, sizeof(host_ipaddr)));
- return 0;
+ failure = DECODE_FAIL_INVALID_ATTRIBUTE;
+ goto finish;
}
/*
&packet->src_ipaddr.ipaddr,
host_ipaddr, sizeof(host_ipaddr)),
attr[0]);
- return 0;
+ failure = DECODE_FAIL_ATTRIBUTE_TOO_SHORT;
+ goto finish;
}
/*
&packet->src_ipaddr.ipaddr,
host_ipaddr, sizeof(host_ipaddr)),
attr[0]);
- return 0;
+ failure = DECODE_FAIL_ATTRIBUTE_OVERFLOW;
+ goto finish;
}
/*
&packet->src_ipaddr.ipaddr,
host_ipaddr, sizeof(host_ipaddr)),
attr[1] - 2);
- return 0;
+ failure = DECODE_FAIL_MA_INVALID_LENGTH;
+ goto finish;
}
seen_ma = true;
break;
inet_ntop(packet->src_ipaddr.af,
&packet->src_ipaddr.ipaddr,
host_ipaddr, sizeof(host_ipaddr)));
- return 0;
+ failure = DECODE_FAIL_ATTRIBUTE_UNDERFLOW;
+ goto finish;
}
/*
&packet->src_ipaddr.ipaddr,
host_ipaddr, sizeof(host_ipaddr)),
num_attributes, fr_max_attributes);
- return 0;
+ failure = DECODE_FAIL_TOO_MANY_ATTRIBUTES;
+ goto finish;
}
/*
* Similarly, Status-Server packets MUST contain
* Message-Authenticator attributes.
*/
- if (require_ma && ! seen_ma) {
+ if (require_ma && !seen_ma) {
fr_strerror_printf("WARNING: Insecure packet from host %s: Packet does not contain required Message-Authenticator attribute",
inet_ntop(packet->src_ipaddr.af,
&packet->src_ipaddr.ipaddr,
host_ipaddr, sizeof(host_ipaddr)));
- return 0;
+ failure = DECODE_FAIL_MA_MISSING;
+ goto finish;
}
/*
packet->id = hdr->id;
memcpy(packet->vector, hdr->vector, AUTH_VECTOR_LEN);
- return 1;
+
+ finish:
+
+ if (reason) {
+ *reason = failure;
+ }
+ return (failure == DECODE_FAIL_NONE);
}
* packet.
*/
if (packet->data_len > MAX_PACKET_LEN) {
- fr_strerror_printf("Discarding packet: Larger than RFC limitation of 4096 bytes.");
+ fr_strerror_printf("Discarding packet: Larger than RFC limitation of 4096 bytes");
/* packet->data is NULL */
rad_free(&packet);
return NULL;
* packet->data == NULL
*/
if ((packet->data_len == 0) || !packet->data) {
- fr_strerror_printf("Empty packet: Socket is not ready.");
+ fr_strerror_printf("Empty packet: Socket is not ready");
rad_free(&packet);
return NULL;
}
/*
* See if it's a well-formed RADIUS packet.
*/
- if (!rad_packet_ok(packet, flags)) {
+ if (!rad_packet_ok(packet, flags, NULL)) {
rad_free(&packet);
return NULL;
}
case PW_CODE_COA_ACK:
case PW_CODE_COA_NAK:
if (!original) {
- fr_strerror_printf("ERROR: Cannot validate Message-Authenticator in response packet without a request packet.");
+ fr_strerror_printf("ERROR: Cannot validate Message-Authenticator in response packet without a request packet");
return -1;
}
memcpy(packet->data + 4, original->vector, AUTH_VECTOR_LEN);
}
-static ssize_t data2vp(RADIUS_PACKET *packet,
- RADIUS_PACKET const *original,
- char const *secret,
- DICT_ATTR const *da, uint8_t const *start,
- size_t const attrlen, size_t const packetlen,
- VALUE_PAIR **pvp);
-
/**
* @brief convert a "concatenated" attribute to one long VP.
*/
*
* @return -1 on error, or "length".
*/
-static ssize_t data2vp(RADIUS_PACKET *packet,
- RADIUS_PACKET const *original,
- char const *secret,
- DICT_ATTR const *da, uint8_t const *start,
- size_t const attrlen, size_t const packetlen,
- VALUE_PAIR **pvp)
+ssize_t data2vp(RADIUS_PACKET *packet,
+ RADIUS_PACKET const *original,
+ char const *secret,
+ DICT_ATTR const *da, uint8_t const *start,
+ size_t const attrlen, size_t const packetlen,
+ VALUE_PAIR **pvp)
{
int tag = 0;
size_t datalen;
break;
case PW_TYPE_BYTE:
- vp->vp_integer = data[0];
+ vp->vp_byte = data[0];
break;
case PW_TYPE_SHORT:
- vp->vp_integer = (data[0] << 8) | data[1];
+ vp->vp_short = (data[0] << 8) | data[1];
break;
case PW_TYPE_INTEGER:
ret = fr_thread_local_set(rad_vp2data_buff, buffer);
if (ret != 0) {
- fr_strerror_printf("Failed setting up TLS for rad_vp2data buffer: %s", fr_syserror(errno));
+ fr_strerror_printf("Failed setting up TLS for rad_vp2data buffer: %s", strerror(errno));
free(buffer);
return -1;
}
if (!radius_packet_ptr || !*radius_packet_ptr) return;
radius_packet = *radius_packet_ptr;
+ VERIFY_PACKET(radius_packet);
+
pairfree(&radius_packet->vps);
talloc_free(radius_packet);
/*
* See if it's a well-formed RADIUS packet.
*/
- if (!rad_packet_ok(packet, flags)) {
+ if (!rad_packet_ok(packet, flags, NULL)) {
return -1;
}
return paircmp_op(b, a->op, a);
}
+/** Determine equality of two lists
+ *
+ * This is useful for comparing lists of attributes inserted into a binary tree.
+ *
+ * @param a first list of VALUE_PAIRs.
+ * @param b second list of VALUE_PAIRs.
+ * @return -1 if a < b, 0 if the two lists are equal, 1 if a > b, -2 on error.
+ */
+int8_t pairlistcmp(VALUE_PAIR *a, VALUE_PAIR *b)
+{
+ vp_cursor_t a_cursor, b_cursor;
+ VALUE_PAIR *a_p, *b_p;
+ int ret;
+
+ for (a_p = fr_cursor_init(&a_cursor, &a), b_p = fr_cursor_init(&b_cursor, &b);
+ a_p && b_p;
+ a_p = fr_cursor_next(&a_cursor), b_p = fr_cursor_next(&b_cursor)) {
+ /* Same VP, no point doing expensive checks */
+ if (a_p == b_p) {
+ continue;
+ }
+
+ if (a_p->da < b_p->da) {
+ return -1;
+ }
+ if (a_p->da > b_p->da) {
+ return 1;
+ }
+
+ if (a_p->tag < b_p->tag) {
+ return -1;
+ }
+ if (a_p->tag > b_p->tag) {
+ return 1;
+ }
+
+ ret = paircmp_value(a_p, b_p);
+ if (ret != 0) {
+ fr_assert(ret >= -1); /* Comparison error */
+ return ret;
+ }
+ }
+
+ if (!a_p && !b_p) {
+ return 0;
+ }
+
+ if (!a_p) {
+ return -1;
+ }
+
+ /* if(!b_p) */
+ return 1;
+}
/** Set the type of the VALUE_PAIR value buffer to match it's DICT_ATTR
*
vp->vp_octets = talloc_steal(vp, src);
vp->type = VT_DATA;
- vp->length = talloc_array_length(vp->vp_octets);
+ vp->length = talloc_array_length(vp->vp_strvalue);
pairtypeset(vp);
}
--- /dev/null
+/*
+ * This program is is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, version 2 if the
+ * License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+/**
+ * $Id$
+ * @file collectd.c
+ * @brief Helper functions to enabled radsniff to talk to collectd
+ *
+ * @copyright 2013 Arran Cudbard-Bell <a.cudbardb@freeradius.org>
+ */
+#ifdef HAVE_COLLECTDC_H
+#include <assert.h>
+#include <ctype.h>
+
+#include <collectd/client.h>
+#include <freeradius-devel/radsniff.h>
+
+/** Copy a 64bit unsigned integer into a double
+ *
+ */
+/*
+static void _copy_uint64_to_double(UNUSED rs_t *conf, rs_stats_value_tmpl_t *tmpl)
+{
+ assert(tmpl->src);
+ assert(tmpl->dst);
+
+ *((double *) tmpl->dst) = *((uint64_t *) tmpl->src);
+}
+*/
+
+/*
+static void _copy_uint64_to_uint64(UNUSED rs_t *conf, rs_stats_value_tmpl_t *tmpl)
+{
+ assert(tmpl->src);
+ assert(tmpl->dst);
+
+ *((uint64_t *) tmpl->dst) = *((uint64_t *) tmpl->src);
+}
+*/
+
+static void _copy_double_to_double(UNUSED rs_t *conf, rs_stats_value_tmpl_t *tmpl)
+{
+ assert(tmpl->src);
+ assert(tmpl->dst);
+
+ *((double *) tmpl->dst) = *((double*) tmpl->src);
+}
+
+
+/** Allocates a stats template which describes a single guage/counter
+ *
+ * This is just intended to simplify allocating a fairly complex memory structure
+ * src and dst pointers must be set
+ *
+ * @param ctx Context to allocate collectd struct in.
+ * @param conf Radsniff configuration.
+ * @param plugin_instance usually the type of packet (in our case).
+ * @param type string, the name of a collection of stats e.g. exchange
+ * @param type_instance the name of the counter/guage within the collection e.g. latency.
+ * @param stats structure to derive statistics from.
+ * @param values Value templates used to populate lcc_value_list.
+ * @return a new rs_stats_tmpl_t on success or NULL on failure.
+ */
+static rs_stats_tmpl_t *rs_stats_collectd_init(TALLOC_CTX *ctx, rs_t *conf,
+ char const *plugin_instance,
+ char const *type, char const *type_instance,
+ void *stats,
+ rs_stats_value_tmpl_t const *values)
+{
+ static char hostname[255];
+ static char fqdn[LCC_NAME_LEN];
+
+ size_t len;
+ int i;
+ char *p;
+
+ rs_stats_tmpl_t *tmpl;
+ lcc_value_list_t *value;
+
+ assert(conf);
+ assert(type);
+ assert(type_instance);
+
+ for (len = 0; values[len].src; len++) {} ;
+ assert(len > 0);
+
+ /*
+ * Initialise hostname once so we don't call gethostname every time
+ */
+ if (*fqdn == '\0') {
+ int ret;
+ struct addrinfo hints, *info = NULL;
+
+ if (gethostname(hostname, sizeof(hostname)) < 0) {
+ ERROR("Error getting hostname: %s", fr_syserror(errno));
+
+ return NULL;
+ }
+
+ memset(&hints, 0, sizeof hints);
+ hints.ai_family = AF_UNSPEC; /*either IPV4 or IPV6*/
+ hints.ai_socktype = SOCK_STREAM;
+ hints.ai_flags = AI_CANONNAME;
+
+ if ((ret = getaddrinfo(hostname, "radius", &hints, &info)) != 0) {
+ ERROR("Error getting hostname: %s", gai_strerror(ret));
+ return NULL;
+ }
+
+ strlcpy(fqdn, info->ai_canonname, sizeof(fqdn));
+
+ freeaddrinfo(info);
+ }
+
+ tmpl = talloc_zero(ctx, rs_stats_tmpl_t);
+ if (!tmpl) {
+ return NULL;
+ }
+
+ tmpl->value_tmpl = talloc_zero_array(tmpl, rs_stats_value_tmpl_t, len);
+ if (!tmpl->value_tmpl) {
+ goto error;
+ }
+
+ tmpl->stats = stats;
+
+ value = talloc_zero(tmpl, lcc_value_list_t);
+ if (!value) {
+ goto error;
+ }
+ tmpl->value = value;
+
+ value->interval = conf->stats.interval;
+ value->values_len = len;
+
+ value->values_types = talloc_zero_array(value, int, len);
+ if (!value->values_types) {
+ goto error;
+ }
+
+ value->values = talloc_zero_array(value, value_t, len);
+ if (!value->values) {
+ goto error;
+ }
+
+ for (i = 0; i < (int) len; i++) {
+ assert(values[i].src);
+ assert(values[i].cb);
+
+ tmpl->value_tmpl[i] = values[i];
+ switch (tmpl->value_tmpl[i].type) {
+ case LCC_TYPE_COUNTER:
+ tmpl->value_tmpl[i].dst = &value->values[i].counter;
+ break;
+
+ case LCC_TYPE_GAUGE:
+ tmpl->value_tmpl[i].dst = &value->values[i].gauge;
+ break;
+
+ case LCC_TYPE_DERIVE:
+ tmpl->value_tmpl[i].dst = &value->values[i].derive;
+ break;
+
+ case LCC_TYPE_ABSOLUTE:
+ tmpl->value_tmpl[i].dst = &value->values[i].absolute;
+ break;
+ default:
+ assert(0);
+ }
+ value->values_types[i] = tmpl->value_tmpl[i].type;
+ }
+
+ /*
+ * These should be OK as is
+ */
+ strlcpy(value->identifier.host, fqdn, sizeof(value->identifier.host));
+
+ /*
+ * Plugin is ASCII only and no '/'
+ */
+ fr_print_string(conf->stats.prefix, strlen(conf->stats.prefix),
+ value->identifier.plugin, sizeof(value->identifier.plugin));
+ for (p = value->identifier.plugin; *p; ++p) {
+ if ((*p == '-') || (*p == '/'))*p = '_';
+ }
+
+ /*
+ * Plugin instance is ASCII only (assuming printable only) and no '/'
+ */
+ fr_print_string(plugin_instance, strlen(plugin_instance),
+ value->identifier.plugin_instance, sizeof(value->identifier.plugin_instance));
+ for (p = value->identifier.plugin_instance; *p; ++p) {
+ if ((*p == '-') || (*p == '/')) *p = '_';
+ }
+
+ /*
+ * Type is ASCII only (assuming printable only) and no '/' or '-'
+ */
+ fr_print_string(type, strlen(type),
+ value->identifier.type, sizeof(value->identifier.type));
+ for (p = value->identifier.type; *p; ++p) {
+ if ((*p == '-') || (*p == '/')) *p = '_';
+ }
+
+ fr_print_string(type_instance, strlen(type_instance),
+ value->identifier.type_instance, sizeof(value->identifier.type_instance));
+ for (p = value->identifier.type_instance; *p; ++p) {
+ if ((*p == '-') || (*p == '/')) *p = '_';
+ }
+
+
+ return tmpl;
+
+ error:
+ talloc_free(tmpl);
+ return NULL;
+}
+
+
+/** Setup stats templates for latency
+ *
+ */
+rs_stats_tmpl_t *rs_stats_collectd_init_latency(TALLOC_CTX *ctx, rs_stats_tmpl_t **out, rs_t *conf,
+ char const *type, rs_latency_t *stats, PW_CODE code)
+{
+ rs_stats_tmpl_t **tmpl, *last;
+ char *p;
+ char buffer[LCC_NAME_LEN];
+ tmpl = out;
+
+ rs_stats_value_tmpl_t rtx[(RS_RETRANSMIT_MAX + 1) + 1 + 1]; // RTX bins + 0 bin + lost + NULL
+ int i;
+
+ /* not static so were thread safe */
+ rs_stats_value_tmpl_t const _packet_count[] = {
+ { &stats->interval.received, LCC_TYPE_GAUGE, _copy_double_to_double, NULL },
+ { &stats->interval.linked, LCC_TYPE_GAUGE, _copy_double_to_double, NULL },
+ { &stats->interval.unlinked, LCC_TYPE_GAUGE, _copy_double_to_double, NULL },
+ { &stats->interval.reused, LCC_TYPE_GAUGE, _copy_double_to_double, NULL },
+ { NULL, 0, NULL, NULL }
+ };
+
+ rs_stats_value_tmpl_t const _latency[] = {
+ { &stats->latency_smoothed, LCC_TYPE_GAUGE, _copy_double_to_double, NULL },
+ { &stats->interval.latency_average, LCC_TYPE_GAUGE, _copy_double_to_double, NULL },
+ { &stats->interval.latency_high, LCC_TYPE_GAUGE, _copy_double_to_double, NULL },
+ { &stats->interval.latency_low, LCC_TYPE_GAUGE, _copy_double_to_double, NULL },
+ { NULL, 0, NULL, NULL }
+ };
+
+#define INIT_STATS(_ti, _v) do {\
+ strlcpy(buffer, fr_packet_codes[code], sizeof(buffer)); \
+ for (p = buffer; *p; ++p) *p = tolower(*p);\
+ last = *tmpl = rs_stats_collectd_init(ctx, conf, type, _ti, buffer, stats, _v);\
+ if (!*tmpl) {\
+ TALLOC_FREE(*out);\
+ return NULL;\
+ }\
+ tmpl = &(*tmpl)->next;\
+ ctx = *tmpl;\
+ } while (0)
+
+
+ INIT_STATS("radius_count", _packet_count);
+ INIT_STATS("radius_latency", _latency);
+
+ for (i = 0; i < (RS_RETRANSMIT_MAX + 1); i++) {
+ rtx[i].src = &stats->interval.rt[i];
+ rtx[i].type = LCC_TYPE_GAUGE;
+ rtx[i].cb = _copy_double_to_double;
+ rtx[i].dst = NULL;
+ }
+
+ rtx[i].src = &stats->interval.lost;
+ rtx[i].type = LCC_TYPE_GAUGE;
+ rtx[i].cb = _copy_double_to_double;
+ rtx[i].dst = NULL;
+
+ memset(&rtx[++i], 0, sizeof(rs_stats_value_tmpl_t));
+
+ INIT_STATS("radius_rtx", rtx);
+
+ return last;
+}
+
+/** Refresh and send the stats to the collectd server
+ *
+ */
+void rs_stats_collectd_do_stats(rs_t *conf, rs_stats_tmpl_t *tmpls, struct timeval *now)
+{
+ rs_stats_tmpl_t *tmpl = tmpls;
+ char identifier[6 * LCC_NAME_LEN];
+ int i;
+
+ while (tmpl) {
+ /*
+ * Refresh the value of whatever were sending
+ */
+ for (i = 0; i < (int) tmpl->value->values_len; i++) {
+ tmpl->value_tmpl[i].cb(conf, &tmpl->value_tmpl[i]);
+ }
+
+ tmpl->value->time = now->tv_sec;
+
+ lcc_identifier_to_string(conf->stats.handle, identifier, sizeof(identifier), &tmpl->value->identifier);
+
+ if (lcc_putval(conf->stats.handle, tmpl->value) < 0) {
+ char const *error;
+
+ error = lcc_strerror(conf->stats.handle);
+ ERROR("Failed PUTVAL \"%s\" interval=%i %" PRIu64 " : %s",
+ identifier,
+ (int) tmpl->value->interval,
+ (uint64_t) tmpl->value->time,
+ error ? error : "unknown error");
+ }
+
+ tmpl = tmpl->next;
+ }
+}
+
+/** Connect to a collectd server for stats output
+ *
+ * @param[in,out] conf radsniff configuration, we write the generated handle here.
+ * @return 0 on success -1 on failure.
+ */
+int rs_stats_collectd_open(rs_t *conf)
+{
+ assert(conf->stats.collectd);
+
+ /*
+ * Tear down stale connections gracefully.
+ */
+ rs_stats_collectd_close(conf);
+
+ /*
+ * There's no way to get the error from the connection handle
+ * because it's freed on failure, before lcc returns.
+ */
+ if (lcc_connect(conf->stats.collectd, &conf->stats.handle) < 0) {
+ ERROR("Failed opening connection to collectd: %s", fr_syserror(errno));
+ return -1;
+ }
+ DEBUG2("Connected to \"%s\"", conf->stats.collectd);
+
+ assert(conf->stats.handle);
+ return 0;
+}
+
+/** Close connection
+ *
+ * @param[in,out] conf radsniff configuration.
+ * @return 0 on success -1 on failure.
+ */
+int rs_stats_collectd_close(rs_t *conf)
+{
+ assert(conf->stats.collectd);
+
+ int ret = 0;
+
+ if (conf->stats.handle) {
+ ret = lcc_disconnect(conf->stats.handle);
+ conf->stats.handle = NULL;
+ }
+
+ return ret;
+}
+#endif
/*
- * radsniff.c Display the RADIUS traffic on the network.
+ * This program is is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, version 2 if the
+ * License as published by the Free Software Foundation.
*
- * Version: $Id$
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
*
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+/**
+ * $Id$
+ * @file radsniff.c
+ * @brief Capture, filter, and generate statistics for RADIUS traffic
*
- * Copyright 2006 The FreeRADIUS server project
- * Copyright 2006 Nicolas Baradakis <nicolas.baradakis@cegetel.net>
+ * @copyright 2013 Arran Cudbard-Bell <a.cudbardb@freeradius.org>
+ * @copyright 2006 The FreeRADIUS server project
+ * @copyright 2006 Nicolas Baradakis <nicolas.baradakis@cegetel.net>
*/
RCSID("$Id$")
#define _LIBRADIUS 1
+#include <assert.h>
+#include <time.h>
+#include <math.h>
#include <freeradius-devel/libradius.h>
-
-#include <pcap.h>
+#include <freeradius-devel/event.h>
#include <freeradius-devel/radpaths.h>
#include <freeradius-devel/conf.h>
+#include <freeradius-devel/pcap.h>
#include <freeradius-devel/radsniff.h>
-static char const *radius_secret = "testing123";
-static VALUE_PAIR *filter_vps = NULL;
-
-static bool do_sort = false;
-static bool to_stdout = false;
-static FILE *log_dst;
-
-#ifndef PCAP_NETMASK_UNKNOWN
-# define PCAP_NETMASK_UNKNOWN 0
+#ifdef HAVE_COLLECTDC_H
+# include <collectd/client.h>
#endif
-#undef DEBUG1
-#define DEBUG1 if (fr_debug_flag > 2) fprintf
-#undef DEBUG
-#define DEBUG if (fr_debug_flag > 1) fprintf
-#undef INFO
-#define INFO if (fr_debug_flag > 0) fprintf
-
+static rs_t *conf;
struct timeval start_pcap = {0, 0};
-static rbtree_t *filter_tree = NULL;
+static char timestr[50];
+
static rbtree_t *request_tree = NULL;
-static pcap_dumper_t *out = NULL;
-static RADIUS_PACKET *nullpacket = NULL;
+static rbtree_t *link_tree = NULL;
+static fr_event_list_t *events;
+static bool cleanup;
+
+static int self_pipe[2] = {-1, -1}; //!< Signals from sig handlers
typedef int (*rbcmp)(void const *, void const *);
#endif
", built on " __DATE__ " at " __TIME__;
-static int filter_packet(RADIUS_PACKET *packet)
+static int rs_useful_codes[] = {
+ PW_CODE_AUTHENTICATION_REQUEST, //!< RFC2865 - Authentication request
+ PW_CODE_AUTHENTICATION_ACK, //!< RFC2865 - Access-Accept
+ PW_CODE_AUTHENTICATION_REJECT, //!< RFC2865 - Access-Reject
+ PW_CODE_ACCOUNTING_REQUEST, //!< RFC2866 - Accounting-Request
+ PW_CODE_ACCOUNTING_RESPONSE, //!< RFC2866 - Accounting-Response
+ PW_CODE_ACCESS_CHALLENGE, //!< RFC2865 - Access-Challenge
+ PW_CODE_STATUS_SERVER, //!< RFC2865/RFC5997 - Status Server (request)
+ PW_CODE_STATUS_CLIENT, //!< RFC2865/RFC5997 - Status Server (response)
+ PW_CODE_DISCONNECT_REQUEST, //!< RFC3575/RFC5176 - Disconnect-Request
+ PW_CODE_DISCONNECT_ACK, //!< RFC3575/RFC5176 - Disconnect-Ack (positive)
+ PW_CODE_DISCONNECT_NAK, //!< RFC3575/RFC5176 - Disconnect-Nak (not willing to perform)
+ PW_CODE_COA_REQUEST, //!< RFC3575/RFC5176 - CoA-Request
+ PW_CODE_COA_ACK, //!< RFC3575/RFC5176 - CoA-Ack (positive)
+ PW_CODE_COA_NAK, //!< RFC3575/RFC5176 - CoA-Nak (not willing to perform)
+};
+
+const FR_NAME_NUMBER rs_events[] = {
+ { "received", RS_NORMAL },
+ { "norsp", RS_LOST },
+ { "rtx", RS_RTX },
+ { "noreq", RS_UNLINKED },
+ { "reused", RS_REUSED },
+ { "error", RS_ERROR },
+ { NULL , -1 }
+};
+
+static void NEVER_RETURNS usage(int status);
+
+/** Fork and kill the parent process, writing out our PID
+ *
+ * @param pidfile the PID file to write our PID to
+ */
+static void rs_daemonize(char const *pidfile)
{
- vp_cursor_t cursor, check_cursor;
- VALUE_PAIR *check_item;
- VALUE_PAIR *vp;
- unsigned int pass, fail;
- int compare;
+ FILE *fp;
+ pid_t pid, sid;
- pass = fail = 0;
- for (vp = fr_cursor_init(&cursor, &packet->vps);
- vp;
- vp = fr_cursor_next(&cursor)) {
- for (check_item = fr_cursor_init(&check_cursor, &filter_vps);
- check_item;
- check_item = fr_cursor_next(&check_cursor))
- if ((check_item->da == vp->da)
- && (check_item->op != T_OP_SET)) {
- compare = paircmp(check_item, vp);
- if (compare == 1)
- pass++;
- else
- fail++;
- }
+ pid = fork();
+ if (pid < 0) {
+ exit(EXIT_FAILURE);
}
- if (fail == 0 && pass != 0) {
- /*
- * Cache authentication requests, as the replies
- * may not match the RADIUS filter.
- */
- if ((packet->code == PW_CODE_AUTHENTICATION_REQUEST) ||
- (packet->code == PW_CODE_ACCOUNTING_REQUEST)) {
- rbtree_deletebydata(filter_tree, packet);
-
- if (!rbtree_insert(filter_tree, packet)) {
- oom:
- fprintf(stderr, "radsniff: Out of memory\n");
- exit(1);
- }
- }
- return 0; /* matched */
+ /*
+ * Kill the parent...
+ */
+ if (pid > 0) {
+ close(self_pipe[0]);
+ close(self_pipe[1]);
+ exit(EXIT_SUCCESS);
}
/*
- * Don't create erroneous matches.
+ * Continue as the child.
*/
- if ((packet->code == PW_CODE_AUTHENTICATION_REQUEST) ||
- (packet->code == PW_CODE_ACCOUNTING_REQUEST)) {
- rbtree_deletebydata(filter_tree, packet);
- return 1;
+
+ /* Create a new SID for the child process */
+ sid = setsid();
+ if (sid < 0) {
+ exit(EXIT_FAILURE);
}
/*
- * Else see if a previous Access-Request
- * matched. If so, also print out the
- * matching accept, reject, or challenge.
+ * Change the current working directory. This prevents the current
+ * directory from being locked; hence not being able to remove it.
*/
- if ((packet->code == PW_CODE_AUTHENTICATION_ACK) ||
- (packet->code == PW_CODE_AUTHENTICATION_REJECT) ||
- (packet->code == PW_CODE_ACCESS_CHALLENGE) ||
- (packet->code == PW_CODE_ACCOUNTING_RESPONSE)) {
- RADIUS_PACKET *reply;
+ if ((chdir("/")) < 0) {
+ exit(EXIT_FAILURE);
+ }
- /*
- * This swaps the various fields.
- */
- reply = rad_alloc_reply(NULL, packet);
- if (!reply) goto oom;
+ /*
+ * And write it AFTER we've forked, so that we write the
+ * correct PID.
+ */
+ fp = fopen(pidfile, "w");
+ if (fp != NULL) {
+ fprintf(fp, "%d\n", (int) sid);
+ fclose(fp);
+ } else {
+ ERROR("Failed creating PID file %s: %s", pidfile, fr_syserror(errno));
+ exit(EXIT_FAILURE);
+ }
- compare = 1;
- if (rbtree_finddata(filter_tree, reply)) {
- compare = 0;
+ /*
+ * Close stdout and stderr if they've not been redirected.
+ */
+ if (isatty(fileno(stdout))) {
+ if (!freopen("/dev/null", "w", stdout)) {
+ exit(EXIT_FAILURE);
}
-
- rad_free(&reply);
- return compare;
}
- return 1;
+ if (isatty(fileno(stderr))) {
+ if (!freopen("/dev/null", "w", stderr)) {
+ exit(EXIT_FAILURE);
+ }
+ }
}
#define USEC 1000000
-static void tv_sub(struct timeval const *end, struct timeval const *start,
- struct timeval *elapsed)
+static void rs_tv_sub(struct timeval const *end, struct timeval const *start, struct timeval *elapsed)
{
elapsed->tv_sec = end->tv_sec - start->tv_sec;
if (elapsed->tv_sec > 0) {
}
}
-static void got_packet(UNUSED uint8_t *args, struct pcap_pkthdr const*header, uint8_t const *data)
+static void rs_tv_add_ms(struct timeval const *start, unsigned long interval, struct timeval *result) {
+ result->tv_sec = start->tv_sec + (interval / 1000);
+ result->tv_usec = start->tv_usec + ((interval % 1000) * 1000);
+
+ if (result->tv_usec > USEC) {
+ result->tv_usec -= USEC;
+ result->tv_sec++;
+ }
+}
+
+static void rs_time_print(char *out, size_t len, struct timeval const *t)
+{
+ size_t ret;
+ struct timeval now;
+ uint32_t usec;
+
+ if (!t) {
+ gettimeofday(&now, NULL);
+ t = &now;
+ }
+
+ ret = strftime(out, len, "%Y-%m-%d %H:%M:%S", localtime(&t->tv_sec));
+ if (ret >= len) {
+ return;
+ }
+
+ usec = t->tv_usec;
+
+ if (usec) {
+ while (usec < 100000) usec *= 10;
+ snprintf(out + ret, len - ret, ".%i", usec);
+ } else {
+ snprintf(out + ret, len - ret, ".000000");
+ }
+}
+
+static void rs_packet_print_null(UNUSED uint64_t count, UNUSED rs_status_t status, UNUSED fr_pcap_t *handle,
+ UNUSED RADIUS_PACKET *packet, UNUSED struct timeval *elapsed,
+ UNUSED struct timeval *latency, UNUSED bool response, UNUSED bool body)
+{
+ return;
+}
+
+static size_t rs_prints_csv(char *out, size_t outlen, char const *in, size_t inlen)
+{
+ char const *start = out;
+ uint8_t const *str = (uint8_t const *) in;
+
+ if (!in) {
+ if (outlen) {
+ *out = '\0';
+ }
+
+ return 0;
+ }
+
+ if (inlen == 0) {
+ inlen = strlen(in);
+ }
+
+ while ((inlen > 0) && (outlen > 2)) {
+ /*
+ * Escape double quotes with... MORE DOUBLE QUOTES!
+ */
+ if (*str == '"') {
+ *out++ = '"';
+ outlen--;
+ }
+
+ /*
+ * Safe chars which require no escaping
+ */
+ if ((*str == '\r') || (*str == '\n') || ((*str >= '\x20') && (*str <= '\x7E'))) {
+ *out++ = *str++;
+ outlen--;
+ inlen--;
+
+ continue;
+ }
+
+ /*
+ * Everything else is dropped
+ */
+ str++;
+ inlen--;
+ }
+ *out = '\0';
+
+ return out - start;
+}
+
+static void rs_packet_print_csv_header(void)
+{
+ char buffer[2048];
+ char *p = buffer;
+ int i;
+
+ ssize_t len, s = sizeof(buffer);
+
+ len = strlcpy(p, "\"Status\",\"Count\",\"Time\",\"Latency\",\"Type\",\"Interface\","
+ "\"Src IP\",\"Src Port\",\"Dst IP\",\"Dst Port\",\"ID\",", s);
+ p += len;
+ s -= len;
+
+ if (s <= 0) return;
+
+ for (i = 0; i < conf->list_da_num; i++) {
+ char const *in;
+
+ *p++ = '"';
+ s -= 1;
+ if (s <= 0) return;
+
+ for (in = conf->list_da[i]->name; *in; in++) {
+ *p++ = *in;
+ s -= len;
+ if (s <= 0) return;
+ }
+
+ *p++ = '"';
+ s -= 1;
+ if (s <= 0) return;
+ *p++ = ',';
+ s -= 1;
+ if (s <= 0) return;
+ }
+
+ *--p = '\0';
+
+ fprintf(stdout , "%s\n", buffer);
+}
+
+static void rs_packet_print_csv(uint64_t count, rs_status_t status, fr_pcap_t *handle, RADIUS_PACKET *packet,
+ UNUSED struct timeval *elapsed, struct timeval *latency, UNUSED bool response,
+ bool body)
+{
+ char const *status_str;
+ char buffer[2048];
+ char *p = buffer;
+
+ char src[INET6_ADDRSTRLEN];
+ char dst[INET6_ADDRSTRLEN];
+
+ ssize_t len, s = sizeof(buffer);
+
+ inet_ntop(packet->src_ipaddr.af, &packet->src_ipaddr.ipaddr, src, sizeof(src));
+ inet_ntop(packet->dst_ipaddr.af, &packet->dst_ipaddr.ipaddr, dst, sizeof(dst));
+
+ status_str = fr_int2str(rs_events, status, NULL);
+ assert(status_str);
+
+ len = snprintf(p, s, "%s,%" PRIu64 ",%s,", status_str, count, timestr);
+ p += len;
+ s -= len;
+
+ if (s <= 0) return;
+
+ if (latency) {
+ len = snprintf(p, s, "%u.%03u,",
+ (unsigned int) latency->tv_sec, ((unsigned int) latency->tv_usec / 1000));
+ p += len;
+ s -= len;
+ } else {
+ *p = ',';
+ p += 1;
+ s -= 1;
+ }
+
+ if (s <= 0) return;
+
+ /* Status, Type, Interface, Src, Src port, Dst, Dst port, ID */
+ if (is_radius_code(packet->code)) {
+ len = snprintf(p, s, "%s,%s,%s,%i,%s,%i,%i,", fr_packet_codes[packet->code], handle->name,
+ src, packet->src_port, dst, packet->dst_port, packet->id);
+ } else {
+ len = snprintf(p, s, "%i,%s,%s,%i,%s,%i,%i,", packet->code, handle->name,
+ src, packet->src_port, dst, packet->dst_port, packet->id);
+ }
+ p += len;
+ s -= len;
+
+ if (s <= 0) return;
+
+ if (body) {
+ int i;
+ VALUE_PAIR *vp;
+
+ for (i = 0; i < conf->list_da_num; i++) {
+ vp = pairfind_da(packet->vps, conf->list_da[i], TAG_ANY);
+ if (vp && (vp->length > 0)) {
+ if (conf->list_da[i]->type == PW_TYPE_STRING) {
+ *p++ = '"';
+ s--;
+ if (s <= 0) return;
+
+ len = rs_prints_csv(p, s, vp->vp_strvalue, vp->length);
+ p += len;
+ s -= len;
+ if (s <= 0) return;
+
+ *p++ = '"';
+ s--;
+ if (s <= 0) return;
+ } else {
+ len = vp_prints_value(p, s, vp, 0);
+ p += len;
+ s -= len;
+ if (s <= 0) return;
+ }
+ }
+
+ *p++ = ',';
+ s -= 1;
+ if (s <= 0) return;
+ }
+ } else {
+ s -= conf->list_da_num;
+ if (s <= 0) return;
+
+ memset(p, ',', conf->list_da_num);
+ p += conf->list_da_num;
+ }
+
+ *--p = '\0';
+ fprintf(stdout , "%s\n", buffer);
+}
+
+static void rs_packet_print_fancy(uint64_t count, rs_status_t status, fr_pcap_t *handle, RADIUS_PACKET *packet,
+ struct timeval *elapsed, struct timeval *latency, bool response, bool body)
+{
+ char buffer[2048];
+ char *p = buffer;
+
+ char src[INET6_ADDRSTRLEN];
+ char dst[INET6_ADDRSTRLEN];
+
+ ssize_t len, s = sizeof(buffer);
+
+ inet_ntop(packet->src_ipaddr.af, &packet->src_ipaddr.ipaddr, src, sizeof(src));
+ inet_ntop(packet->dst_ipaddr.af, &packet->dst_ipaddr.ipaddr, dst, sizeof(dst));
+
+ /* Only print out status str if something's not right */
+ if (status != RS_NORMAL) {
+ char const *status_str;
+
+ status_str = fr_int2str(rs_events, status, NULL);
+ assert(status_str);
+
+ len = snprintf(p, s, "** %s ** ", status_str);
+ p += len;
+ s -= len;
+ if (s <= 0) return;
+ }
+
+ if (is_radius_code(packet->code)) {
+ len = snprintf(p, s, "%s Id %i %s:%s:%d %s %s:%i ",
+ fr_packet_codes[packet->code],
+ packet->id,
+ handle->name,
+ response ? dst : src,
+ response ? packet->dst_port : packet->src_port,
+ response ? "<-" : "->",
+ response ? src : dst ,
+ response ? packet->src_port : packet->dst_port);
+ } else {
+ len = snprintf(p, s, "%i Id %i %s:%s:%i %s %s:%i ",
+ packet->code,
+ packet->id,
+ handle->name,
+ response ? dst : src,
+ response ? packet->dst_port : packet->src_port,
+ response ? "<-" : "->",
+ response ? src : dst ,
+ response ? packet->src_port : packet->dst_port);
+ }
+ p += len;
+ s -= len;
+ if (s <= 0) return;
+
+ if (elapsed) {
+ len = snprintf(p, s, "+%u.%03u ",
+ (unsigned int) elapsed->tv_sec, ((unsigned int) elapsed->tv_usec / 1000));
+ p += len;
+ s -= len;
+ if (s <= 0) return;
+ }
+
+ if (latency) {
+ len = snprintf(p, s, "+%u.%03u ",
+ (unsigned int) latency->tv_sec, ((unsigned int) latency->tv_usec / 1000));
+ p += len;
+ s -= len;
+ if (s <= 0) return;
+ }
+
+ *--p = '\0';
+
+ RIDEBUG("%s", buffer);
+
+ if (body) {
+ /*
+ * Print out verbose HEX output
+ */
+ if (conf->print_packet && (fr_debug_flag > 3)) {
+ rad_print_hex(packet);
+ }
+
+ if (conf->print_packet && (fr_debug_flag > 1) && packet->vps) {
+ pairsort(&packet->vps, attrtagcmp);
+ vp_printlist(fr_log_fp, packet->vps);
+ }
+ }
+}
+
+static void rs_stats_print(rs_latency_t *stats, PW_CODE code)
+{
+ int i;
+ bool have_rt = false;
+
+ for (i = 0; i <= RS_RETRANSMIT_MAX; i++) {
+ if (stats->interval.rt[i]) {
+ have_rt = true;
+ }
+ }
+
+ if (!stats->interval.received && !have_rt && !stats->interval.reused) {
+ return;
+ }
+
+ if (stats->interval.received || stats->interval.linked) {
+ INFO("%s counters:", fr_packet_codes[code]);
+ if (stats->interval.received > 0) {
+ INFO("\tTotal : %.3lf/s" , stats->interval.received);
+ }
+ }
+
+ if (stats->interval.linked > 0) {
+ INFO("\tLinked : %.3lf/s", stats->interval.linked);
+ INFO("\tUnlinked : %.3lf/s", stats->interval.unlinked);
+ INFO("%s latency:", fr_packet_codes[code]);
+ INFO("\tHigh : %.3lfms", stats->interval.latency_high);
+ INFO("\tLow : %.3lfms", stats->interval.latency_low);
+ INFO("\tAverage : %.3lfms", stats->interval.latency_average);
+ INFO("\tMA : %.3lfms", stats->latency_smoothed);
+ }
+
+ if (have_rt || stats->interval.lost || stats->interval.reused) {
+ INFO("%s retransmits & loss:", fr_packet_codes[code]);
+
+ if (stats->interval.lost) {
+ INFO("\tLost : %.3lf/s", stats->interval.lost);
+ }
+
+ if (stats->interval.reused) {
+ INFO("\tID Reused : %.3lf/s", stats->interval.reused);
+ }
+
+ for (i = 0; i <= RS_RETRANSMIT_MAX; i++) {
+ if (!stats->interval.rt[i]) {
+ continue;
+ }
+
+ if (i != RS_RETRANSMIT_MAX) {
+ INFO("\tRT (%i) : %.3lf/s", i, stats->interval.rt[i]);
+ } else {
+ INFO("\tRT (%i+) : %.3lf/s", i, stats->interval.rt[i]);
+ }
+ }
+ }
+}
+
+/** Query libpcap to see if it dropped any packets
+ *
+ * We need to check to see if libpcap dropped any packets and if it did, we need to stop stats output for long
+ * enough for inaccurate statistics to be cleared out.
+ *
+ * @param in pcap handle to check.
+ * @param interval time between checks (used for debug output)
+ * @return 0, no drops, -1 we couldn't check, -2 dropped because of buffer exhaustion, -3 dropped because of NIC.
+ */
+static int rs_check_pcap_drop(fr_pcap_t *in, int interval) {
+ int ret = 0;
+ struct pcap_stat pstats;
+
+ if (pcap_stats(in->handle, &pstats) != 0) {
+ ERROR("%s failed retrieving pcap stats: %s", in->name, pcap_geterr(in->handle));
+ return -1;
+ }
+
+ INFO("\t%s%*s: %.3lf/s", in->name, (int) (10 - strlen(in->name)), "",
+ ((double) (pstats.ps_recv - in->pstats.ps_recv)) / interval);
+
+ if (pstats.ps_drop - in->pstats.ps_drop > 0) {
+ ERROR("%s dropped %i packets: Buffer exhaustion", in->name, pstats.ps_drop - in->pstats.ps_drop);
+ ret = -2;
+ }
+
+ if (pstats.ps_ifdrop - in->pstats.ps_ifdrop > 0) {
+ ERROR("%s dropped %i packets: Interface", in->name, pstats.ps_ifdrop - in->pstats.ps_ifdrop);
+ ret = -3;
+ }
+
+ in->pstats = pstats;
+
+ return ret;
+}
+
+/** Update smoothed average
+ *
+ */
+static void rs_stats_process_latency(rs_latency_t *stats)
+{
+ /*
+ * If we didn't link any packets during this interval, we don't have a value to return.
+ * returning 0 is misleading as it would be like saying the latency had dropped to 0.
+ * We instead set NaN which libcollectd converts to a 'U' or unknown value.
+ *
+ * This will cause gaps in graphs, but is completely legitimate as we are missing data.
+ * This is unfortunately an effect of being just a passive observer.
+ */
+ if (stats->interval.linked_total == 0) {
+ double unk = strtod("NAN()", (char **) NULL);
+
+ stats->interval.latency_average = unk;
+ stats->interval.latency_high = unk;
+ stats->interval.latency_low = unk;
+
+ /*
+ * We've not yet been able to determine latency, so latency_smoothed is also NaN
+ */
+ if (stats->latency_smoothed_count == 0) {
+ stats->latency_smoothed = unk;
+ }
+ return;
+ }
+
+ if (stats->interval.linked_total && stats->interval.latency_total) {
+ stats->interval.latency_average = (stats->interval.latency_total / stats->interval.linked_total);
+ }
+
+ if (isnan(stats->latency_smoothed)) {
+ stats->latency_smoothed = 0;
+ }
+ if (stats->interval.latency_average > 0) {
+ stats->latency_smoothed_count++;
+ stats->latency_smoothed += ((stats->interval.latency_average - stats->latency_smoothed) /
+ ((stats->latency_smoothed_count < 100) ? stats->latency_smoothed_count : 100));
+ }
+}
+
+static void rs_stats_process_counters(rs_latency_t *stats)
+{
+ int i;
+
+ stats->interval.received = ((long double) stats->interval.received_total) / conf->stats.interval;
+ stats->interval.linked = ((long double) stats->interval.linked_total) / conf->stats.interval;
+ stats->interval.unlinked = ((long double) stats->interval.unlinked_total) / conf->stats.interval;
+ stats->interval.reused = ((long double) stats->interval.reused_total) / conf->stats.interval;
+ stats->interval.lost = ((long double) stats->interval.lost_total) / conf->stats.interval;
+
+ for (i = 0; i < RS_RETRANSMIT_MAX; i++) {
+ stats->interval.rt[i] = ((long double) stats->interval.rt_total[i]) / conf->stats.interval;
+ }
+}
+
+/** Process stats for a single interval
+ *
+ */
+static void rs_stats_process(void *ctx)
{
+ size_t i;
+ size_t rs_codes_len = (sizeof(rs_useful_codes) / sizeof(*rs_useful_codes));
+ fr_pcap_t *in_p;
+ rs_update_t *this = ctx;
+ rs_stats_t *stats = this->stats;
+ struct timeval now;
+
+ gettimeofday(&now, NULL);
+
+ stats->intervals++;
- static int count = 1; /* Packets seen */
+ INFO("######### Stats Iteration %i #########", stats->intervals);
/*
- * Define pointers for packet's attributes
+ * Verify that none of the pcap handles have dropped packets.
*/
- const struct ip_header *ip; /* The IP header */
- const struct udp_header *udp; /* The UDP header */
- const uint8_t *payload; /* Packet payload */
+ INFO("Interface capture rate:");
+ for (in_p = this->in;
+ in_p;
+ in_p = in_p->next) {
+ if (rs_check_pcap_drop(in_p, conf->stats.interval) < 0) {
+ ERROR("Muting stats for the next %i milliseconds", conf->stats.timeout);
+
+ rs_tv_add_ms(&now, conf->stats.timeout, &stats->quiet);
+ goto clear;
+ }
+ }
+
+ if ((stats->quiet.tv_sec + (stats->quiet.tv_usec / 1000000.0)) -
+ (now.tv_sec + (now.tv_usec / 1000000.0)) > 0) {
+ INFO("Stats muted because of warmup, or previous error");
+ goto clear;
+ }
/*
- * And define the size of the structures we're using
+ * Latency stats need a bit more work to calculate the SMA.
+ *
+ * No further work is required for codes.
*/
- int size_ethernet = sizeof(struct ethernet_header);
- int size_ip = sizeof(struct ip_header);
- int size_udp = sizeof(struct udp_header);
+ for (i = 0; i < rs_codes_len; i++) {
+ rs_stats_process_latency(&stats->exchange[rs_useful_codes[i]]);
+ rs_stats_process_counters(&stats->exchange[rs_useful_codes[i]]);
+ if (fr_debug_flag > 0) {
+ rs_stats_print(&stats->exchange[rs_useful_codes[i]], rs_useful_codes[i]);
+ }
+ }
+#ifdef HAVE_COLLECTDC_H
/*
- * For FreeRADIUS
+ * Update stats in collectd using the complex structures we
+ * initialised earlier.
*/
- RADIUS_PACKET *packet, *original;
- struct timeval elapsed;
+ if ((conf->stats.out == RS_STATS_OUT_COLLECTD) && conf->stats.handle) {
+ rs_stats_collectd_do_stats(conf, conf->stats.tmpl, &now);
+ }
+#endif
+ clear:
/*
- * Define our packet's attributes
+ * Rinse and repeat...
*/
+ for (i = 0; i < rs_codes_len; i++) {
+ memset(&stats->exchange[rs_useful_codes[i]].interval, 0,
+ sizeof(stats->exchange[rs_useful_codes[i]].interval));
+ }
- if ((data[0] == 2) && (data[1] == 0) &&
- (data[2] == 0) && (data[3] == 0)) {
- ip = (struct ip_header const *) (data + 4);
+ {
+ static fr_event_t *event;
- } else {
- ip = (struct ip_header const *)(data + size_ethernet);
+ now.tv_sec += conf->stats.interval;
+ now.tv_usec = 0;
+
+ if (!fr_event_insert(this->list, rs_stats_process, ctx, &now, &event)) {
+ ERROR("Failed inserting stats interval event");
+ }
}
+}
- udp = (struct udp_header const *)(((uint8_t const *) ip) + size_ip);
- payload = (uint8_t const *)(((uint8_t const *) udp) + size_udp);
- packet = rad_alloc(NULL, 0);
- if (!packet) {
- fprintf(stderr, "Out of memory\n");
- return;
+/** Update latency statistics for request/response and forwarded packets
+ *
+ */
+static void rs_stats_update_latency(rs_latency_t *stats, struct timeval *latency)
+{
+ double lint;
+
+ stats->interval.linked_total++;
+ /* More useful is this in milliseconds */
+ lint = (latency->tv_sec + (latency->tv_usec / 1000000.0)) * 1000;
+ if (lint > stats->interval.latency_high) {
+ stats->interval.latency_high = lint;
}
+ if (!stats->interval.latency_low || (lint < stats->interval.latency_low)) {
+ stats->interval.latency_low = lint;
+ }
+ stats->interval.latency_total += lint;
- packet->src_ipaddr.af = AF_INET;
- packet->src_ipaddr.ipaddr.ip4addr.s_addr = ip->ip_src.s_addr;
- packet->src_port = ntohs(udp->udp_sport);
- packet->dst_ipaddr.af = AF_INET;
- packet->dst_ipaddr.ipaddr.ip4addr.s_addr = ip->ip_dst.s_addr;
- packet->dst_port = ntohs(udp->udp_dport);
+}
- memcpy(&packet->data, &payload, sizeof(packet->data));
- packet->data_len = header->len - (payload - data);
+/** Copy a subset of attributes from one list into the other
+ *
+ * Should be O(n) if all the attributes exist. List must be pre-sorted.
+ */
+static int rs_get_pairs(TALLOC_CTX *ctx, VALUE_PAIR **out, VALUE_PAIR *vps, DICT_ATTR const *da[], int num)
+{
+ vp_cursor_t list_cursor, out_cursor;
+ VALUE_PAIR *match, *last_match, *copy;
+ uint64_t count = 0;
+ int i;
+
+ last_match = vps;
+
+ fr_cursor_init(&list_cursor, &last_match);
+ fr_cursor_init(&out_cursor, out);
+ for (i = 0; i < num; i++) {
+ match = fr_cursor_next_by_da(&list_cursor, da[i], TAG_ANY);
+ if (!match) {
+ fr_cursor_init(&list_cursor, &last_match);
+ continue;
+ }
- if (!rad_packet_ok(packet, 0)) {
- DEBUG(log_dst, "Packet: %s\n", fr_strerror());
+ do {
+ copy = paircopyvp(ctx, match);
+ if (!copy) {
+ pairfree(out);
+ return -1;
+ }
+ fr_cursor_insert(&out_cursor, copy);
+ last_match = match;
- DEBUG(log_dst, " From %s:%d\n", inet_ntoa(ip->ip_src), ntohs(udp->udp_sport));
- DEBUG(log_dst, " To: %s:%d\n", inet_ntoa(ip->ip_dst), ntohs(udp->udp_dport));
- DEBUG(log_dst, " Type: %s\n", fr_packet_codes[packet->code]);
+ count++;
+ } while ((match = fr_cursor_next_by_da(&list_cursor, da[i], TAG_ANY)));
+ }
- rad_free(&packet);
- return;
+ return count;
+}
+
+static int _request_free(rs_request_t *request)
+{
+ /*
+ * If were attempting to cleanup the request, and it's no longer in the request_tree
+ * something has gone very badly wrong.
+ */
+ if (request->in_request_tree) {
+ assert(rbtree_deletebydata(request_tree, request));
}
- switch (packet->code) {
- case PW_CODE_COA_REQUEST:
- /* we need a 16 x 0 byte vector for decrypting encrypted VSAs */
- original = nullpacket;
- break;
- case PW_CODE_AUTHENTICATION_ACK:
- /* look for a matching request and use it for decoding */
- original = rbtree_finddata(request_tree, packet);
- break;
- case PW_CODE_AUTHENTICATION_REQUEST:
- /* save the request for later matching */
- original = rad_alloc_reply(NULL, packet);
- if (original) { /* just ignore allocation failures */
- rbtree_deletebydata(request_tree, original);
- rbtree_insert(request_tree, original);
- }
- /* fallthrough */
- default:
- /* don't attempt to decode any encrypted attributes */
- original = NULL;
+ if (request->in_link_tree) {
+ assert(rbtree_deletebydata(link_tree, request));
+ }
+
+ if (request->event) {
+ assert(fr_event_delete(events, &request->event));
+ }
+
+ rad_free(&request->packet);
+ rad_free(&request->expect);
+ rad_free(&request->linked);
+
+ return 0;
+}
+
+static void rs_packet_cleanup(rs_request_t *request)
+{
+
+ RADIUS_PACKET *packet = request->packet;
+ uint64_t count = request->id;
+
+ assert(request->stats_req);
+ assert(!request->rt_rsp || request->stats_rsp);
+ assert(packet);
+
+ /*
+ * Don't pollute stats or print spurious messages as radsniff closes.
+ */
+ if (cleanup) {
+ talloc_free(request);
+ return;
+ }
+
+ if (RIDEBUG_ENABLED()) {
+ rs_time_print(timestr, sizeof(timestr), &request->when);
+ }
+
+ /*
+ * Were at packet cleanup time which is when the packet was received + timeout
+ * and it's not been linked with a forwarded packet or a response.
+ *
+ * We now count it as lost.
+ */
+ if (!request->silent_cleanup) {
+ if (!request->linked) {
+ request->stats_req->interval.lost_total++;
+
+ if (conf->event_flags & RS_LOST) {
+ /* @fixme We should use flags in the request to indicate whether it's been dumped
+ * to a PCAP file or logged yet, this simplifies the body logging logic */
+ conf->logger(request->id, RS_LOST, request->in, packet, NULL, NULL, false,
+ conf->filter_response_vps || !(conf->event_flags & RS_NORMAL));
+ }
+ }
+
+ if (request->in->type == PCAP_INTERFACE_IN) {
+ RDEBUG("Cleaning up request packet ID %i", request->expect->id);
+ }
+ }
+
+ /*
+ * Now the request is done, we can update the retransmission stats
+ */
+ if (request->rt_req > RS_RETRANSMIT_MAX) {
+ request->stats_req->interval.rt_total[RS_RETRANSMIT_MAX]++;
+ } else {
+ request->stats_req->interval.rt_total[request->rt_req]++;
+ }
+
+ if (request->rt_rsp) {
+ if (request->rt_rsp > RS_RETRANSMIT_MAX) {
+ request->stats_rsp->interval.rt_total[RS_RETRANSMIT_MAX]++;
+ } else {
+ request->stats_rsp->interval.rt_total[request->rt_rsp]++;
+ }
+ }
+
+ talloc_free(request);
+}
+
+static void _rs_event(void *ctx)
+{
+ rs_request_t *request = talloc_get_type_abort(ctx, rs_request_t);
+ request->event = NULL;
+ rs_packet_cleanup(request);
+}
+
+/** Wrapper around fr_packet_cmp to strip off the outer request struct
+ *
+ */
+static int rs_packet_cmp(rs_request_t const *a, rs_request_t const *b)
+{
+ return fr_packet_cmp(a->expect, b->expect);
+}
+
+/* This is the same as immediately scheduling the cleanup event */
+#define RS_CLEANUP_NOW(_x, _s)\
+ {\
+ _x->silent_cleanup = _s;\
+ _x->when = header->ts;\
+ rs_packet_cleanup(_x);\
+ _x = NULL;\
+ } while (0)
+
+static void rs_packet_process(uint64_t count, rs_event_t *event, struct pcap_pkthdr const *header, uint8_t const *data)
+{
+ rs_stats_t *stats = event->stats;
+ struct timeval elapsed = {0, 0};
+ struct timeval latency;
+
+ /*
+ * Pointers into the packet data we just received
+ */
+ ssize_t len;
+ uint8_t const *p = data;
+
+ ip_header_t const *ip = NULL; /* The IP header */
+ ip_header6_t const *ip6 = NULL; /* The IPv6 header */
+ udp_header_t const *udp; /* The UDP header */
+ uint8_t version; /* IP header version */
+ bool response; /* Was it a response code */
+
+ decode_fail_t reason; /* Why we failed decoding the packet */
+ static uint64_t captured = 0;
+
+ rs_status_t status = RS_NORMAL; /* Any special conditions (RTX, Unlinked, ID-Reused) */
+ RADIUS_PACKET *current; /* Current packet were processing */
+ rs_request_t *original = NULL;
+
+ rs_request_t search;
+
+ memset(&search, 0, sizeof(search));
+
+ if (!start_pcap.tv_sec) {
+ start_pcap = header->ts;
+ }
+
+ if (RIDEBUG_ENABLED()) {
+ rs_time_print(timestr, sizeof(timestr), &header->ts);
+ }
+
+ len = fr_pcap_link_layer_offset(data, header->caplen, event->in->link_type);
+ if (len < 0) {
+ REDEBUG("Failed determining link layer header offset");
+ return;
+ }
+ p += len;
+
+ version = (p[0] & 0xf0) >> 4;
+ switch (version) {
+ case 4:
+ ip = (ip_header_t const *)p;
+ len = (0x0f & ip->ip_vhl) * 4; /* ip_hl specifies length in 32bit words */
+ p += len;
+ break;
+
+ case 6:
+ ip6 = (ip_header6_t const *)p;
+ p += sizeof(ip_header6_t);
+
+ break;
+
+ default:
+ REDEBUG("IP version invalid %i", version);
+ return;
+ }
+
+ /*
+ * End of variable length bits, do basic check now to see if packet looks long enough
+ */
+ len = (p - data) + sizeof(udp_header_t) + (sizeof(radius_packet_t) - 1); /* length value */
+ if ((size_t) len > header->caplen) {
+ REDEBUG("Packet too small, we require at least %zu bytes, captured %i bytes",
+ (size_t) len, header->caplen);
+ return;
+ }
+
+ /*
+ * UDP header validation.
+ */
+ udp = (udp_header_t const *)p;
+ {
+ uint16_t udp_len;
+ ssize_t diff;
+
+ udp_len = ntohs(udp->len);
+ diff = udp_len - (header->caplen - (p - data));
+ /* Truncated data */
+ if (diff > 0) {
+ REDEBUG("Packet too small by %zi bytes, UDP header + Payload should be %hu bytes",
+ diff, udp_len);
+ return;
+ }
+ /* Trailing data */
+ else if (diff < 0) {
+ REDEBUG("Packet too big by %zi bytes, UDP header + Payload should be %hu bytes",
+ diff * -1, udp_len);
+ return;
+ }
+ }
+ if (version == 4) {
+ uint16_t expected;
+
+ expected = fr_udp_checksum((uint8_t const *) udp, ntohs(udp->len), udp->checksum,
+ ip->ip_src, ip->ip_dst);
+ if (udp->checksum != expected) {
+ REDEBUG("UDP checksum invalid, packet: 0x%04hx calculated: 0x%04hx",
+ ntohs(udp->checksum), ntohs(expected));
+ /* Not a fatal error */
+ }
+ }
+ p += sizeof(udp_header_t);
+
+ /*
+ * With artificial talloc memory limits there's a good chance we can
+ * recover once some requests timeout, so make an effort to deal
+ * with allocation failures gracefully.
+ */
+ current = rad_alloc(conf, 0);
+ if (!current) {
+ REDEBUG("Failed allocating memory to hold decoded packet");
+ rs_tv_add_ms(&header->ts, conf->stats.timeout, &stats->quiet);
+ return;
+ }
+
+ current->timestamp = header->ts;
+ current->data_len = header->caplen - (p - data);
+ memcpy(¤t->data, &p, sizeof(current->data));
+
+ /*
+ * Populate IP/UDP fields from PCAP data
+ */
+ if (ip) {
+ current->src_ipaddr.af = AF_INET;
+ current->src_ipaddr.ipaddr.ip4addr.s_addr = ip->ip_src.s_addr;
+
+ current->dst_ipaddr.af = AF_INET;
+ current->dst_ipaddr.ipaddr.ip4addr.s_addr = ip->ip_dst.s_addr;
+ } else {
+ current->src_ipaddr.af = AF_INET6;
+ memcpy(¤t->src_ipaddr.ipaddr.ip6addr.s6_addr, &ip6->ip_src.s6_addr,
+ sizeof(current->src_ipaddr.ipaddr.ip6addr.s6_addr));
+
+ current->dst_ipaddr.af = AF_INET6;
+ memcpy(¤t->dst_ipaddr.ipaddr.ip6addr.s6_addr, &ip6->ip_dst.s6_addr,
+ sizeof(current->dst_ipaddr.ipaddr.ip6addr.s6_addr));
+ }
+
+ current->src_port = ntohs(udp->src);
+ current->dst_port = ntohs(udp->dst);
+
+ if (!rad_packet_ok(current, 0, &reason)) {
+ REDEBUG("%s", fr_strerror());
+ if (conf->event_flags & RS_ERROR) {
+ conf->logger(count, RS_ERROR, event->in, current, &elapsed, NULL, false, false);
+ }
+ rad_free(¤t);
+
+ return;
+ }
+
+ switch (current->code) {
+ case PW_CODE_ACCOUNTING_RESPONSE:
+ case PW_CODE_AUTHENTICATION_REJECT:
+ case PW_CODE_AUTHENTICATION_ACK:
+ case PW_CODE_COA_NAK:
+ case PW_CODE_COA_ACK:
+ case PW_CODE_DISCONNECT_NAK:
+ case PW_CODE_DISCONNECT_ACK:
+ case PW_CODE_STATUS_CLIENT:
+ {
+ /* look for a matching request and use it for decoding */
+ search.expect = current;
+ original = rbtree_finddata(request_tree, &search);
+
+ /*
+ * Verify this code is allowed
+ */
+ if (conf->filter_response_code && (conf->filter_response_code != current->code)) {
+ drop_response:
+ RDEBUG2("Response dropped by filter");
+ rad_free(¤t);
+
+ /* We now need to cleanup the original request too */
+ if (original) {
+ RS_CLEANUP_NOW(original, true);
+ }
+ return;
+ }
+
+ /*
+ * Only decode attributes if we want to print them or filter on them
+ * rad_packet_ok does checks to verify the packet is actually valid.
+ */
+ if (conf->decode_attrs) {
+ int ret;
+ FILE *log_fp = fr_log_fp;
+
+ fr_log_fp = NULL;
+ ret = rad_decode(current, original ? original->expect : NULL, conf->radius_secret);
+ fr_log_fp = log_fp;
+ if (ret != 0) {
+ rad_free(¤t);
+ REDEBUG("Failed decoding");
+ return;
+ }
+ }
+
+ /*
+ * Check if we've managed to link it to a request
+ */
+ if (original) {
+ /*
+ * Now verify the packet passes the attribute filter
+ */
+ if (conf->filter_response_vps) {
+ pairsort(¤t->vps, attrtagcmp);
+ if (!pairvalidate_relaxed(conf->filter_response_vps, current->vps)) {
+ goto drop_response;
+ }
+ }
+
+ /*
+ * Is this a retransmission?
+ */
+ if (original->linked) {
+ status = RS_RTX;
+ original->rt_rsp++;
+
+ rad_free(&original->linked);
+ fr_event_delete(event->list, &original->event);
+ /*
+ * ...nope it's the first response to a request.
+ */
+ } else {
+ original->stats_rsp = &stats->exchange[current->code];
+ }
+
+ /*
+ * Insert a callback to remove the request and response
+ * from the tree after the timeout period.
+ * The delay is so we can detect retransmissions.
+ */
+ original->linked = talloc_steal(original, current);
+ rs_tv_add_ms(&header->ts, conf->stats.timeout, &original->when);
+ if (!fr_event_insert(event->list, _rs_event, original, &original->when,
+ &original->event)) {
+ REDEBUG("Failed inserting new event");
+ /*
+ * Delete the original request/event, it's no longer valid
+ * for statistics.
+ */
+ talloc_free(original);
+ return;
+ }
+ /*
+ * No request seen, or request was dropped by attribute filter
+ */
+ } else {
+ /*
+ * If conf->filter_request_vps are set assume the original request was dropped,
+ * the alternative is maintaining another 'filter', but that adds
+ * complexity, reduces max capture rate, and is generally a PITA.
+ */
+ if (conf->filter_request) {
+ rad_free(¤t);
+ RDEBUG2("Original request dropped by filter");
+ return;
+ }
+
+ status = RS_UNLINKED;
+ stats->exchange[current->code].interval.unlinked_total++;
+ }
+
+ response = true;
+ break;
+ }
+
+ case PW_CODE_ACCOUNTING_REQUEST:
+ case PW_CODE_AUTHENTICATION_REQUEST:
+ case PW_CODE_COA_REQUEST:
+ case PW_CODE_DISCONNECT_REQUEST:
+ case PW_CODE_STATUS_SERVER:
+ {
+ /*
+ * Verify this code is allowed
+ */
+ if (conf->filter_request_code && (conf->filter_request_code != current->code)) {
+ drop_request:
+
+ RDEBUG2("Request dropped by filter");
+ rad_free(¤t);
+
+ return;
+ }
+
+ /*
+ * Only decode attributes if we want to print them or filter on them
+ * rad_packet_ok does checks to verify the packet is actually valid.
+ */
+ if (conf->decode_attrs) {
+ int ret;
+ FILE *log_fp = fr_log_fp;
+
+ fr_log_fp = NULL;
+ ret = rad_decode(current, NULL, conf->radius_secret);
+ fr_log_fp = log_fp;
+
+ if (ret != 0) {
+ rad_free(¤t);
+ REDEBUG("Failed decoding");
+ return;
+ }
+
+ pairsort(¤t->vps, attrtagcmp);
+ }
+
+ /*
+ * Save the request for later matching
+ */
+ search.expect = rad_alloc_reply(current, current);
+ if (!search.expect) {
+ REDEBUG("Failed allocating memory to hold expected reply");
+ rs_tv_add_ms(&header->ts, conf->stats.timeout, &stats->quiet);
+ rad_free(¤t);
+ return;
+ }
+ search.expect->code = current->code;
+
+ if ((conf->link_da_num > 0) && current->vps) {
+ int ret;
+ ret = rs_get_pairs(current, &search.link_vps, current->vps, conf->link_da,
+ conf->link_da_num);
+ if (ret < 0) {
+ ERROR("Failed extracting RTX linking pairs from request");
+ rad_free(¤t);
+ return;
+ }
+ }
+
+ /*
+ * If we have linking attributes set, attempt to find a request in the linking tree.
+ */
+ if (search.link_vps) {
+ rs_request_t *tuple;
+
+ original = rbtree_finddata(link_tree, &search);
+ tuple = rbtree_finddata(request_tree, &search);
+
+ /*
+ * If the packet we matched using attributes is not the same
+ * as the packet in the request tree, then we need to clean up
+ * the packet in the request tree.
+ */
+ if (tuple && (original != tuple)) {
+ RS_CLEANUP_NOW(tuple, true);
+ }
+ /*
+ * Detect duplicates using the normal 5-tuple of src/dst ips/ports id
+ */
+ } else {
+ original = rbtree_finddata(request_tree, &search);
+ if (original && memcmp(original->expect->vector, current->vector,
+ sizeof(original->expect->vector)) != 0) {
+ /*
+ * ID reused before the request timed out (which may be an issue)...
+ */
+ if (!original->linked) {
+ status = RS_REUSED;
+ stats->exchange[current->code].interval.reused_total++;
+ /* Occurs regularly downstream of proxy servers (so don't complain) */
+ RS_CLEANUP_NOW(original, true);
+ /*
+ * ...and before we saw a response (which may be a bigger issue).
+ */
+ } else {
+ RS_CLEANUP_NOW(original, false);
+ }
+ /* else it's a proper RTX with the same src/dst id authenticator/nonce */
+ }
+ }
+
+ /*
+ * Now verify the packet passes the attribute filter
+ */
+ if (conf->filter_request_vps) {
+ if (!pairvalidate_relaxed(conf->filter_request_vps, current->vps)) {
+ goto drop_request;
+ }
+ }
+
+ /*
+ * Is this a retransmission?
+ */
+ if (original) {
+ status = RS_RTX;
+ original->rt_req++;
+
+ rad_free(&original->packet);
+
+ /* We may of seen the response, but it may of been lost upstream */
+ rad_free(&original->linked);
+
+ original->packet = talloc_steal(original, current);
+
+ /* Request may need to be reinserted as the 5 tuple of the response may of changed */
+ if (rs_packet_cmp(original, &search) != 0) {
+ rbtree_deletebydata(request_tree, original);
+ }
+
+ rad_free(&original->expect);
+ original->expect = talloc_steal(original, search.expect);
+
+ /* Disarm the timer for the cleanup event for the original request */
+ fr_event_delete(event->list, &original->event);
+ /*
+ * ...nope it's a new request.
+ */
+ } else {
+ original = talloc_zero(conf, rs_request_t);
+ talloc_set_destructor(original, _request_free);
+
+ original->id = count;
+ original->in = event->in;
+ original->stats_req = &stats->exchange[current->code];
+
+ original->packet = talloc_steal(original, current);
+ original->expect = talloc_steal(original, search.expect);
+
+ if (search.link_vps) {
+ original->link_vps = pairsteal(original, search.link_vps);
+
+ /* We should never have conflicts */
+ assert(rbtree_insert(link_tree, original));
+ original->in_link_tree = true;
+ }
+
+ /*
+ * Special case for when were filtering by response,
+ * we never count any requests as lost, because we
+ * don't know what the response to that request would
+ * of been.
+ */
+ if (conf->filter_response_vps) {
+ original->silent_cleanup = true;
+ }
+ }
+
+ if (!original->in_request_tree) {
+ /* We should never have conflicts */
+ assert(rbtree_insert(request_tree, original));
+ original->in_request_tree = true;
+ }
+
+ /*
+ * Insert a callback to remove the request from the tree
+ */
+ original->packet->timestamp = header->ts;
+ rs_tv_add_ms(&header->ts, conf->stats.timeout, &original->when);
+ if (!fr_event_insert(event->list, _rs_event, original,
+ &original->when, &original->event)) {
+ REDEBUG("Failed inserting new event");
+
+ talloc_free(original);
+ return;
+ }
+ response = false;
+ break;
+ }
+
+ default:
+ REDEBUG("Unsupported code %i", current->code);
+ rad_free(¤t);
+
+ return;
+ }
+
+ if (event->out) {
+ pcap_dump((void *) (event->out->dumper), header, data);
+ }
+
+ rs_tv_sub(&header->ts, &start_pcap, &elapsed);
+
+ /*
+ * Increase received count
+ */
+ stats->exchange[current->code].interval.received_total++;
+
+ /*
+ * It's a linked response
+ */
+ if (original && original->linked) {
+ rs_tv_sub(¤t->timestamp, &original->packet->timestamp, &latency);
+
+ /*
+ * Update stats for both the request and response types.
+ *
+ * This isn't useful for things like Access-Requests, but will be useful for
+ * CoA and Disconnect Messages, as we get the average latency across both
+ * response types.
+ *
+ * It also justifies allocating PW_CODE_MAX instances of rs_latency_t.
+ */
+ rs_stats_update_latency(&stats->exchange[current->code], &latency);
+ rs_stats_update_latency(&stats->exchange[original->expect->code], &latency);
+
+ /*
+ * Were filtering on response, now print out the full data from the request
+ */
+ if (conf->filter_response && RIDEBUG_ENABLED() && (conf->event_flags & RS_NORMAL)) {
+ rs_time_print(timestr, sizeof(timestr), &original->packet->timestamp);
+ rs_tv_sub(&original->packet->timestamp, &start_pcap, &elapsed);
+ conf->logger(original->id, RS_NORMAL, original->in, original->packet, &elapsed, NULL, false, true);
+ rs_tv_sub(&header->ts, &start_pcap, &elapsed);
+ rs_time_print(timestr, sizeof(timestr), &header->ts);
+ }
+
+ if (conf->event_flags & status) {
+ conf->logger(count, status, event->in, current, &elapsed, &latency, response, true);
+ }
+ /*
+ * It's the original request
+ *
+ * If were filtering on responses we can only indicate we received it on response, or timeout.
+ */
+ } else if (!conf->filter_response && (conf->event_flags & status)) {
+ conf->logger(original ? original->id : count, status, event->in,
+ current, &elapsed, NULL, response, true);
+ }
+
+ fflush(fr_log_fp);
+
+ /*
+ * If it's a unlinked response, we need to free it explicitly, as it will
+ * not be done by the event queue.
+ */
+ if (response && !original) {
+ rad_free(¤t);
+ }
+
+ captured++;
+ /*
+ * We've hit our capture limit, break out of the event loop
+ */
+ if ((conf->limit > 0) && (captured >= conf->limit)) {
+ INFO("Captured %" PRIu64 " packets, exiting...", captured);
+ fr_event_loop_exit(events, 1);
+ }
+}
+
+static void rs_got_packet(UNUSED fr_event_list_t *el, int fd, void *ctx)
+{
+ static uint64_t count = 0; /* Packets seen */
+ rs_event_t *event = ctx;
+ pcap_t *handle = event->in->handle;
+
+ int i;
+ int ret;
+ const uint8_t *data;
+ struct pcap_pkthdr *header;
+
+ /*
+ * Consume entire capture, interleaving not currently possible
+ */
+ if ((event->in->type == PCAP_FILE_IN) || (event->in->type == PCAP_STDIO_IN)) {
+ while (!fr_event_loop_exiting(el)) {
+ struct timeval now;
+
+ ret = pcap_next_ex(handle, &header, &data);
+ if (ret == 0) {
+ /* No more packets available at this time */
+ return;
+ }
+ if (ret == -2) {
+ DEBUG("Done reading packets (%s)", event->in->name);
+ fr_event_fd_delete(events, 0, fd);
+
+ if (fr_event_list_num_fds(events) == 0) {
+ fr_event_loop_exit(events, 1);
+ }
+
+ return;
+ }
+ if (ret < 0) {
+ ERROR("Error requesting next packet, got (%i): %s", ret, pcap_geterr(handle));
+ return;
+ }
+
+ do {
+ now = header->ts;
+ } while (fr_event_run(el, &now) == 1);
+ count++;
+
+ rs_packet_process(count, event, header, data);
+ }
+ return;
+ }
+
+ /*
+ * Consume multiple packets from the capture buffer.
+ * We occasionally need to yield to allow events to run.
+ */
+ for (i = 0; i < RS_FORCE_YIELD; i++) {
+ ret = pcap_next_ex(handle, &header, &data);
+ if (ret == 0) {
+ /* No more packets available at this time */
+ return;
+ }
+ if (ret < 0) {
+ ERROR("Error requesting next packet, got (%i): %s", ret, pcap_geterr(handle));
+ return;
+ }
+
+ count++;
+ rs_packet_process(count, event, header, data);
+ }
+}
+
+static void _rs_event_status(struct timeval *wake)
+{
+ if (wake && ((wake->tv_sec != 0) || (wake->tv_usec >= 100000))) {
+ DEBUG2("Waking up in %d.%01u seconds.", (int) wake->tv_sec, (unsigned int) wake->tv_usec / 100000);
+
+ if (RIDEBUG_ENABLED()) {
+ rs_time_print(timestr, sizeof(timestr), wake);
+ }
+ }
+}
+
+/** Compare requests using packet info and lists of attributes
+ *
+ */
+static int rs_rtx_cmp(rs_request_t const *a, rs_request_t const *b)
+{
+ int rcode;
+
+ assert(a->link_vps);
+ assert(b->link_vps);
+
+ rcode = (int) a->expect->code - (int) b->expect->code;
+ if (rcode != 0) return rcode;
+
+ rcode = a->expect->sockfd - b->expect->sockfd;
+ if (rcode != 0) return rcode;
+
+ rcode = fr_ipaddr_cmp(&a->expect->src_ipaddr, &b->expect->src_ipaddr);
+ if (rcode != 0) return rcode;
+
+ rcode = fr_ipaddr_cmp(&a->expect->dst_ipaddr, &b->expect->dst_ipaddr);
+ if (rcode != 0) return rcode;
+
+ return pairlistcmp(a->link_vps, b->link_vps);
+}
+
+static int rs_build_dict_list(DICT_ATTR const **out, size_t len, char *list)
+{
+ size_t i = 0;
+ char *p, *tok;
+
+ p = list;
+ while ((tok = strsep(&p, "\t ,")) != NULL) {
+ DICT_ATTR const *da;
+ if ((*tok == '\t') || (*tok == ' ') || (*tok == '\0')) {
+ continue;
+ }
+
+ if (i == len) {
+ ERROR("Too many attributes, maximum allowed is %zu", len);
+ return -1;
+ }
+
+ da = dict_attrbyname(tok);
+ if (!da) {
+ ERROR("Error parsing attribute name \"%s\"", tok);
+ return -1;
+ }
+
+ out[i] = da;
+ i++;
+ }
+
+ return i;
+}
+
+static int rs_build_filter(VALUE_PAIR **out, char const *filter)
+{
+ vp_cursor_t cursor;
+ VALUE_PAIR *vp;
+ FR_TOKEN code;
+
+ code = userparse(conf, filter, out);
+ if (code == T_OP_INVALID) {
+ ERROR("Invalid RADIUS filter \"%s\" (%s)", filter, fr_strerror());
+ return -1;
+ }
+
+ if (!*out) {
+ ERROR("Empty RADIUS filter '%s'", filter);
+ return -1;
}
- /*
- * Decode the data without bothering to check the signatures.
- */
- if (rad_decode(packet, original, radius_secret) != 0) {
- rad_free(&packet);
- fr_perror("decode");
- return;
+ for (vp = fr_cursor_init(&cursor, out);
+ vp;
+ vp = fr_cursor_next(&cursor)) {
+ /*
+ * xlat expansion isn't support here
+ */
+ if (vp->type == VT_XLAT) {
+ vp->type = VT_DATA;
+ vp->vp_strvalue = vp->value.xlat;
+ }
}
/*
- * We've seen a successful reply to this, so delete it now
+ * This allows efficient list comparisons later
*/
- if (original)
- rbtree_deletebydata(request_tree, original);
+ pairsort(out, attrtagcmp);
- if (filter_vps && filter_packet(packet)) {
- rad_free(&packet);
- DEBUG(log_dst, "Packet number %d doesn't match\n", count++);
- return;
- }
+ return 0;
+}
- if (out) {
- pcap_dump((void *) out, header, data);
- goto check_filter;
- }
+static int rs_build_flags(int *flags, FR_NAME_NUMBER const *map, char *list)
+{
+ size_t i = 0;
+ char *p, *tok;
- INFO(log_dst, "%s Id %d\t", fr_packet_codes[packet->code], packet->id);
+ p = list;
+ while ((tok = strsep(&p, "\t ,")) != NULL) {
+ int flag;
- /*
- * Print the RADIUS packet
- */
- INFO(log_dst, "%s:%d -> ", inet_ntoa(ip->ip_src), ntohs(udp->udp_sport));
- INFO(log_dst, "%s:%d", inet_ntoa(ip->ip_dst), ntohs(udp->udp_dport));
+ if ((*tok == '\t') || (*tok == ' ') || (*tok == '\0')) {
+ continue;
+ }
- DEBUG1(log_dst, "\t(%d packets)", count++);
+ *flags |= flag = fr_str2int(map, tok, -1);
+ if (flag < 0) {
+ ERROR("Invalid flag \"%s\"", tok);
+ return -1;
+ }
- if (!start_pcap.tv_sec) {
- start_pcap = header->ts;
+ i++;
}
- tv_sub(&header->ts, &start_pcap, &elapsed);
+ return i;
+}
- INFO(log_dst, "\t+%u.%03u", (unsigned int) elapsed.tv_sec,
- (unsigned int) elapsed.tv_usec / 1000);
+/** Callback for when the request is removed from the request tree
+ *
+ * @param request being removed.
+ */
+static void _unmark_request(void *request)
+{
+ rs_request_t *this = request;
+ this->in_request_tree = false;
+}
- if (fr_debug_flag > 1) {
- DEBUG(log_dst, "\n");
- if (packet->vps) {
- if (do_sort) {
- pairsort(&packet->vps, attrtagcmp);
- }
- vp_printlist(log_dst, packet->vps);
- pairfree(&packet->vps);
- }
+/** Callback for when the request is removed from the link tree
+ *
+ * @param request being removed.
+ */
+static void _unmark_link(void *request)
+{
+ rs_request_t *this = request;
+ this->in_link_tree = false;
+}
+
+/** Write the last signal to the signal pipe
+ *
+ * @param sig raised
+ */
+static void rs_signal_self(int sig)
+{
+ if (write(self_pipe[1], &sig, sizeof(sig)) < 0) {
+ ERROR("Failed writing signal %s to pipe: %s", strsignal(sig), fr_syserror(errno));
+ exit(EXIT_FAILURE);
}
+}
- INFO(log_dst, "\n");
+#ifdef HAVE_COLLECTDC_H
+/** Re-open the collectd socket
+ *
+ */
+static void rs_collectd_reopen(void *ctx)
+{
+ fr_event_list_t *list = ctx;
+ static fr_event_t *event;
+ struct timeval now, when;
- if (!to_stdout && (fr_debug_flag > 4)) {
- rad_print_hex(packet);
+ if (rs_stats_collectd_open(conf) == 0) {
+ DEBUG2("Stats output socket (re)opened");
+ return;
}
- fflush(log_dst);
+ ERROR("Will attempt to re-establish connection in %i ms", RS_SOCKET_REOPEN_DELAY);
- check_filter:
- /*
- * If we're doing filtering, Access-Requests are cached in the
- * filter tree.
- */
- if (!filter_vps ||
- ((packet->code != PW_CODE_AUTHENTICATION_REQUEST) &&
- (packet->code != PW_CODE_ACCOUNTING_REQUEST))) {
- rad_free(&packet);
+ gettimeofday(&now, NULL);
+ rs_tv_add_ms(&now, RS_SOCKET_REOPEN_DELAY, &when);
+ if (!fr_event_insert(list, rs_collectd_reopen, list, &when, &event)) {
+ ERROR("Failed inserting re-open event");
+ assert(0);
}
}
+#endif
-
-/** Wrapper function to allow rad_free to be called as an rbtree destructor callback
+/** Read the last signal from the signal pipe
*
- * @param packet to free.
*/
-static void _rb_rad_free(void *packet)
+static void rs_signal_action(UNUSED fr_event_list_t *list, int fd, UNUSED void *ctx)
{
- rad_free((RADIUS_PACKET **) &packet);
+ int sig;
+ ssize_t ret;
+
+ ret = read(fd, &sig, sizeof(sig));
+ if (ret < 0) {
+ ERROR("Failed reading signal from pipe: %s", fr_syserror(errno));
+ exit(EXIT_FAILURE);
+ }
+
+ if (ret != sizeof(sig)) {
+ ERROR("Failed reading signal from pipe: "
+ "Expected signal to be %zu bytes but only read %zu byes", sizeof(sig), ret);
+ exit(EXIT_FAILURE);
+ }
+
+ switch (sig) {
+#ifdef HAVE_COLLECTDC_H
+ case SIGPIPE:
+ rs_collectd_reopen(list);
+ break;
+#endif
+
+ case SIGINT:
+ case SIGTERM:
+ case SIGQUIT:
+ DEBUG2("Signalling event loop to exit");
+ fr_event_loop_exit(events, 1);
+ break;
+
+ default:
+ ERROR("Unhandled signal %s", strsignal(sig));
+ exit(EXIT_FAILURE);
+ }
}
+
static void NEVER_RETURNS usage(int status)
{
FILE *output = status ? stderr : stdout;
- fprintf(output, "Usage: radsniff [options]\n");
+ fprintf(output, "Usage: radsniff [options][stats options] -- [pcap files]\n");
fprintf(output, "options:\n");
- fprintf(output, " -c <count> Number of packets to capture.\n");
- fprintf(output, " -d <directory> Set dictionary directory.\n");
- fprintf(output, " -F Filter PCAP file from stdin to stdout.\n");
- fprintf(output, " -f <filter> PCAP filter (default is 'udp port <port> or <port + 1> or 3799')\n");
- fprintf(output, " -h This help message.\n");
- fprintf(output, " -i <interface> Capture packets from interface (defaults to any if supported).\n");
- fprintf(output, " -I <file> Read packets from file (overrides input of -F).\n");
- fprintf(output, " -p <port> Filter packets by port (default is 1812).\n");
- fprintf(output, " -q Print less debugging information.\n");
- fprintf(output, " -r <filter> RADIUS attribute filter.\n");
- fprintf(output, " -s <secret> RADIUS secret.\n");
- fprintf(output, " -S Sort attributes in the packet (useful for diffing responses).\n");
- fprintf(output, " -v Show program version information.\n");
- fprintf(output, " -w <file> Write output packets to file (overrides output of -F).\n");
- fprintf(output, " -x Print more debugging information (defaults to -xx).\n");
+ fprintf(output, " -a List all interfaces available for capture.\n");
+ fprintf(output, " -c <count> Number of packets to capture.\n");
+ fprintf(output, " -d <directory> Set dictionary directory.\n");
+ fprintf(stderr, " -d <raddb> Set configuration directory (defaults to " RADDBDIR ").\n");
+ fprintf(stderr, " -D <dictdir> Set main dictionary directory (defaults to " DICTDIR ").\n");
+ fprintf(output, " -e <event>[,<event>] Only log requests with these event flags.\n");
+ fprintf(output, " Event may be one of the following:\n");
+ fprintf(output, " - received - a request or response.\n");
+ fprintf(output, " - norsp - seen for a request.\n");
+ fprintf(output, " - rtx - of a request that we've seen before.\n");
+ fprintf(output, " - noreq - could be matched with the response.\n");
+ fprintf(output, " - reused - ID too soon.\n");
+ fprintf(output, " - error - decoding the packet.\n");
+ fprintf(output, " -f <filter> PCAP filter (default is 'udp port <port> or <port + 1> or 3799')\n");
+ fprintf(output, " -h This help message.\n");
+ fprintf(output, " -i <interface> Capture packets from interface (defaults to all if supported).\n");
+ fprintf(output, " -I <file> Read packets from file (overrides input of -F).\n");
+ fprintf(output, " -l <attr>[,<attr>] Output packet sig and a list of attributes.\n");
+ fprintf(output, " -L <attr>[,<attr>] Detect retransmissions using these attributes to link requests.\n");
+ fprintf(output, " -m Don't put interface(s) into promiscuous mode.\n");
+ fprintf(output, " -p <port> Filter packets by port (default is 1812).\n");
+ fprintf(output, " -P <pidfile> Daemonize and write out <pidfile>.\n");
+ fprintf(output, " -q Print less debugging information.\n");
+ fprintf(output, " -r <filter> RADIUS attribute request filter.\n");
+ fprintf(output, " -R <filter> RADIUS attribute response filter.\n");
+ fprintf(output, " -s <secret> RADIUS secret.\n");
+ fprintf(output, " -S Write PCAP data to stdout.\n");
+ fprintf(output, " -v Show program version information.\n");
+ fprintf(output, " -w <file> Write output packets to file.\n");
+ fprintf(output, " -x Print more debugging information (defaults to -xx).\n");
+ fprintf(output, "stats options:\n");
+ fprintf(output, " -W <interval> Periodically write out statistics every <interval> seconds.\n");
+ fprintf(output, " -T <timeout> How many milliseconds before the request is counted as lost "
+ "(defaults to %i).\n", RS_DEFAULT_TIMEOUT);
+#ifdef HAVE_COLLECTDC_H
+ fprintf(output, " -N <prefix> The instance name passed to the collectd plugin.\n");
+ fprintf(output, " -O <server> Write statistics to this collectd server.\n");
+#endif
exit(status);
}
int main(int argc, char *argv[])
{
- char const *from_dev = NULL; /* Capture from device */
- char const *from_file = NULL; /* Read from pcap file */
- bool from_stdin = false; /* Read from stdin */
-
- pcap_t *in = NULL; /* PCAP input handle */
+ fr_pcap_t *in = NULL, *in_p;
+ fr_pcap_t **in_head = ∈
+ fr_pcap_t *out = NULL;
- int limit = -1; /* How many packets to sniff */
+ int ret = 1; /* Exit status */
char errbuf[PCAP_ERRBUF_SIZE]; /* Error buffer */
-
- char *to_file = NULL; /* PCAP output file */
-
- char *pcap_filter = NULL; /* PCAP filter string */
- char *radius_filter = NULL;
int port = 1812;
- struct bpf_program fp; /* Holds compiled filter */
- bpf_u_int32 ip_mask = PCAP_NETMASK_UNKNOWN; /* Device Subnet mask */
- bpf_u_int32 ip_addr = 0; /* Device IP */
-
char buffer[1024];
int opt;
- FR_TOKEN parsecode;
- char const *radius_dir = RADIUS_DIR;
+ char const *radius_dir = RADDBDIR;
char const *dict_dir = DICTDIR;
- fr_debug_flag = 2;
- log_dst = stdout;
+ rs_stats_t stats;
+
+ fr_debug_flag = 1;
+ fr_log_fp = stdout;
/*
* Useful if using radsniff as a long running stats daemon
talloc_set_log_stderr();
+ conf = talloc_zero(NULL, rs_t);
+ if (!fr_assert(conf)) {
+ exit (1);
+ }
+
+ /*
+ * We don't really want probes taking down machines
+ */
+#ifdef HAVE_TALLOC_SET_MEMLIMIT
+ /*
+ * @fixme causes hang in talloc steal
+ */
+ //talloc_set_memlimit(conf, 524288000); /* 50 MB */
+#endif
+
+ /*
+ * Set some defaults
+ */
+ conf->print_packet = true;
+ conf->limit = 0;
+ conf->promiscuous = true;
+#ifdef HAVE_COLLECTDC_H
+ conf->stats.prefix = RS_DEFAULT_PREFIX;
+#endif
+ conf->radius_secret = RS_DEFAULT_SECRET;
+ conf->logger = rs_packet_print_null;
+
+#ifdef HAVE_COLLECTDC_H
+ conf->stats.prefix = RS_DEFAULT_PREFIX;
+#endif
+
/*
* Get options
*/
- while ((opt = getopt(argc, argv, "c:d:D:Ff:hi:I:p:qr:s:Svw:xX")) != EOF) {
+ while ((opt = getopt(argc, argv, "ab:c:d:D:e:Ff:hi:I:l:L:mp:P:qr:R:s:Svw:xXW:T:P:N:O:")) != EOF) {
switch (opt) {
+ case 'a':
+ {
+ pcap_if_t *all_devices = NULL;
+ pcap_if_t *dev_p;
+
+ if (pcap_findalldevs(&all_devices, errbuf) < 0) {
+ ERROR("Error getting available capture devices: %s", errbuf);
+ goto finish;
+ }
+
+ int i = 1;
+ for (dev_p = all_devices;
+ dev_p;
+ dev_p = dev_p->next) {
+ INFO("%i.%s", i++, dev_p->name);
+ }
+ ret = 0;
+ goto finish;
+ }
+
+ /* super secret option */
+ case 'b':
+ conf->buffer_pkts = atoi(optarg);
+ if (conf->buffer_pkts == 0) {
+ ERROR("Invalid buffer length \"%s\"", optarg);
+ usage(1);
+ }
+ break;
+
case 'c':
- limit = atoi(optarg);
- if (limit <= 0) {
- fprintf(stderr, "radsniff: Invalid number of packets \"%s\"\n", optarg);
- exit(1);
+ conf->limit = atoi(optarg);
+ if (conf->limit == 0) {
+ ERROR("Invalid number of packets \"%s\"", optarg);
+ usage(1);
}
break;
+
case 'd':
radius_dir = optarg;
break;
+
case 'D':
dict_dir = optarg;
break;
- case 'F':
- from_stdin = true;
- to_stdout = true;
+
+ case 'e':
+ if (rs_build_flags((int *) &conf->event_flags, rs_events, optarg) < 0) {
+ usage(64);
+ }
break;
+
case 'f':
- pcap_filter = optarg;
+ conf->pcap_filter = optarg;
break;
+
case 'h':
usage(0);
break;
+
case 'i':
- from_dev = optarg;
+ *in_head = fr_pcap_init(conf, optarg, PCAP_INTERFACE_IN);
+ if (!*in_head) {
+ goto finish;
+ }
+ in_head = &(*in_head)->next;
+ conf->from_dev = true;
break;
+
case 'I':
- from_file = optarg;
+ *in_head = fr_pcap_init(conf, optarg, PCAP_FILE_IN);
+ if (!*in_head) {
+ goto finish;
+ }
+ in_head = &(*in_head)->next;
+ conf->from_file = true;
+ break;
+
+ case 'l':
+ conf->list_attributes = optarg;
+ break;
+
+ case 'L':
+ conf->link_attributes = optarg;
+ break;
+
+ case 'm':
+ conf->promiscuous = false;
break;
+
case 'p':
port = atoi(optarg);
break;
+
+ case 'P':
+ conf->daemonize = true;
+ conf->pidfile = optarg;
+ break;
+
case 'q':
if (fr_debug_flag > 0) {
fr_debug_flag--;
}
break;
+
case 'r':
- radius_filter = optarg;
+ conf->filter_request = optarg;
break;
+
+ case 'R':
+ conf->filter_response = optarg;
+ break;
+
case 's':
- radius_secret = optarg;
+ conf->radius_secret = optarg;
break;
+
case 'S':
- do_sort = true;
+ conf->to_stdout = true;
break;
+
case 'v':
- INFO(log_dst, "%s %s\n", radsniff_version, pcap_lib_version());
- exit(0);
+#ifdef HAVE_COLLECTDC_H
+ INFO("%s, %s, collectdclient version %s", radsniff_version, pcap_lib_version(),
+ lcc_version_string());
+#else
+ INFO("%s %s", radsniff_version, pcap_lib_version());
+#endif
+ exit(EXIT_SUCCESS);
break;
+
case 'w':
- to_file = optarg;
+ out = fr_pcap_init(conf, optarg, PCAP_FILE_OUT);
+ conf->to_file = true;
break;
+
case 'x':
case 'X':
fr_debug_flag++;
break;
+
+ case 'W':
+ conf->stats.interval = atoi(optarg);
+ conf->print_packet = false;
+ if (conf->stats.interval <= 0) {
+ ERROR("Stats interval must be > 0");
+ usage(64);
+ }
+ break;
+
+ case 'T':
+ conf->stats.timeout = atoi(optarg);
+ if (conf->stats.timeout <= 0) {
+ ERROR("Timeout value must be > 0");
+ usage(64);
+ }
+ break;
+
+#ifdef HAVE_COLLECTDC_H
+ case 'N':
+ conf->stats.prefix = optarg;
+ break;
+
+ case 'O':
+ conf->stats.collectd = optarg;
+ conf->stats.out = RS_STATS_OUT_COLLECTD;
+ break;
+#endif
default:
usage(64);
}
*/
if (fr_check_lib_magic(RADIUSD_MAGIC_NUMBER) < 0) {
fr_perror("radsniff");
- exit(1);
+ exit(EXIT_FAILURE);
+ }
+
+ /* Useful for file globbing */
+ while (optind < argc) {
+ *in_head = fr_pcap_init(conf, argv[optind], PCAP_FILE_IN);
+ if (!*in_head) {
+ goto finish;
+ }
+ in_head = &(*in_head)->next;
+ conf->from_file = true;
+ optind++;
+ }
+
+ /* Is stdin not a tty? If so it's probably a pipe */
+ if (!isatty(fileno(stdin))) {
+ conf->from_stdin = true;
}
/* What's the point in specifying -F ?! */
- if (from_stdin && from_file && to_file) {
+ if (conf->from_stdin && conf->from_file && conf->to_file) {
usage(64);
}
/* Can't read from both... */
- if (from_file && from_dev) {
+ if (conf->from_file && conf->from_dev) {
usage(64);
}
/* Reading from file overrides stdin */
- if (from_stdin && (from_file || from_dev)) {
- from_stdin = false;
+ if (conf->from_stdin && (conf->from_file || conf->from_dev)) {
+ conf->from_stdin = false;
}
/* Writing to file overrides stdout */
- if (to_file && to_stdout) {
- to_stdout = false;
+ if (conf->to_file && conf->to_stdout) {
+ conf->to_stdout = false;
+ }
+
+ if (conf->to_stdout) {
+ out = fr_pcap_init(conf, "stdout", PCAP_STDIO_OUT);
+ if (!out) {
+ goto finish;
+ }
+ }
+
+ if (conf->from_stdin) {
+ *in_head = fr_pcap_init(conf, "stdin", PCAP_STDIO_IN);
+ if (!*in_head) {
+ goto finish;
+ }
+ in_head = &(*in_head)->next;
+ }
+
+ if (conf->stats.interval && !conf->stats.out) {
+ conf->stats.out = RS_STATS_OUT_STDIO;
+ }
+
+ if (conf->stats.timeout == 0) {
+ conf->stats.timeout = RS_DEFAULT_TIMEOUT;
}
/*
- * If were writing pcap data stdout we *really* don't want to send
- * logging there as well.
+ * If were writing pcap data, or CSV to stdout we *really* don't want to send
+ * logging there as well.
*/
- log_dst = to_stdout ? stderr : stdout;
+ if (conf->to_stdout || conf->list_attributes) {
+ fr_log_fp = stderr;
+ }
+
+ if (conf->list_attributes) {
+ conf->logger = rs_packet_print_csv;
+ } else if (fr_debug_flag > 0) {
+ conf->logger = rs_packet_print_fancy;
+ }
#if !defined(HAVE_PCAP_FOPEN_OFFLINE) || !defined(HAVE_PCAP_DUMP_FOPEN)
- if (from_stdin || to_stdout) {
- fprintf(stderr, "radsniff: PCAP streams not supported.\n");
- exit(64);
+ if (conf->from_stdin || conf->to_stdout) {
+ ERROR("PCAP streams not supported");
+ goto finish;
}
#endif
- if (!pcap_filter) {
- pcap_filter = buffer;
+ if (!conf->pcap_filter) {
snprintf(buffer, sizeof(buffer), "udp port %d or %d or %d",
port, port + 1, 3799);
+ conf->pcap_filter = buffer;
}
- /*
- * There are times when we don't need the dictionaries.
- */
- if (!to_stdout) {
- if (dict_init(dict_dir, RADIUS_DICTIONARY) < 0) {
- fr_perror("radsniff");
- exit(64);
+ if (dict_init(dict_dir, RADIUS_DICTIONARY) < 0) {
+ fr_perror("radsniff");
+ ret = 64;
+ goto finish;
+ }
+
+ if (dict_read(radius_dir, RADIUS_DICTIONARY) == -1) {
+ fr_perror("radsniff");
+ ret = 64;
+ goto finish;
+ }
+
+ fr_strerror(); /* Clear out any non-fatal errors */
+
+ if (conf->list_attributes) {
+ conf->list_da_num = rs_build_dict_list(conf->list_da, sizeof(conf->list_da) / sizeof(*conf->list_da),
+ conf->list_attributes);
+ if (conf->list_da_num < 0) {
+ usage(64);
+ }
+ rs_packet_print_csv_header();
+ }
+
+ if (conf->link_attributes) {
+ conf->link_da_num = rs_build_dict_list(conf->link_da, sizeof(conf->link_da) / sizeof(*conf->link_da),
+ conf->link_attributes);
+ if (conf->link_da_num < 0) {
+ usage(64);
}
- if (dict_read(radius_dir, RADIUS_DICTIONARY) == -1) {
- fr_perror("radsniff");
- exit(64);
+ link_tree = rbtree_create((rbcmp) rs_rtx_cmp, _unmark_link, 0);
+ if (!link_tree) {
+ ERROR("Failed creating RTX tree");
+ goto finish;
}
}
- if (radius_filter) {
- parsecode = userparse(NULL, radius_filter, &filter_vps);
- if (parsecode == T_OP_INVALID) {
- fprintf(stderr, "radsniff: Invalid RADIUS filter \"%s\" (%s)\n", radius_filter, fr_strerror());
- exit(64);
+ if (conf->filter_request) {
+ vp_cursor_t cursor;
+ VALUE_PAIR *type;
+
+ if (rs_build_filter(&conf->filter_request_vps, conf->filter_request) < 0) {
+ usage(64);
+ }
+
+ fr_cursor_init(&cursor, &conf->filter_request_vps);
+ type = fr_cursor_next_by_num(&cursor, PW_PACKET_TYPE, 0, TAG_ANY);
+ if (type) {
+ fr_cursor_remove(&cursor);
+ conf->filter_request_code = type->vp_integer;
+ talloc_free(type);
}
+ }
- if (!filter_vps) {
- fprintf(stderr, "radsniff: Empty RADIUS filter \"%s\"\n", radius_filter);
- exit(64);
+ if (conf->filter_response) {
+ vp_cursor_t cursor;
+ VALUE_PAIR *type;
+
+ if (rs_build_filter(&conf->filter_response_vps, conf->filter_response) < 0) {
+ usage(64);
}
- filter_tree = rbtree_create((rbcmp) fr_packet_cmp, _rb_rad_free, 0);
- if (!filter_tree) {
- fprintf(stderr, "radsniff: Failed creating filter tree\n");
- exit(1);
+ fr_cursor_init(&cursor, &conf->filter_response_vps);
+ type = fr_cursor_next_by_num(&cursor, PW_PACKET_TYPE, 0, TAG_ANY);
+ if (type) {
+ fr_cursor_remove(&cursor);
+ conf->filter_response_code = type->vp_integer;
+ talloc_free(type);
}
}
/*
- * Setup the request tree
+ * Default to logging and capturing all events
*/
- request_tree = rbtree_create((rbcmp) fr_packet_cmp, _rb_rad_free, 0);
- if (!request_tree) {
- fprintf(stderr, "radsniff: Failed creating request tree\n");
- exit(1);
+ if (conf->event_flags == 0) {
+ DEBUG("Logging all events");
+ memset(&conf->event_flags, 0xff, sizeof(conf->event_flags));
+ }
+
+ /*
+ * If we need to list attributes, link requests using attributes, filter attributes
+ * or print the packet contents, we need to decode the attributes.
+ *
+ * But, if were just logging requests, or graphing packets, we don't need to decode
+ * attributes.
+ */
+ if (conf->list_da_num || conf->link_da_num || conf->filter_response_vps || conf->filter_request_vps ||
+ conf->print_packet) {
+ conf->decode_attrs = true;
}
/*
- * Allocate a null packet for decrypting attributes in CoA requests
+ * Setup the request tree
*/
- nullpacket = rad_alloc(NULL, 0);
- if (!nullpacket) {
- fprintf(stderr, "radsniff: Out of memory\n");
- exit(1);
+ request_tree = rbtree_create((rbcmp) rs_packet_cmp, _unmark_request, 0);
+ if (!request_tree) {
+ ERROR("Failed creating request tree");
+ goto finish;
}
/*
- * Get the default capture device
+ * Get the default capture device
*/
- if (!from_stdin && !from_file && !from_dev) {
- from_dev = pcap_lookupdev(errbuf);
- if (!from_dev) {
- fprintf(stderr, "radsniff: Failed discovering default interface (%s)\n", errbuf);
- exit(1);
+ if (!conf->from_stdin && !conf->from_file && !conf->from_dev) {
+ pcap_if_t *all_devices; /* List of all devices libpcap can listen on */
+ pcap_if_t *dev_p;
+
+ if (pcap_findalldevs(&all_devices, errbuf) < 0) {
+ ERROR("Error getting available capture devices: %s", errbuf);
+ goto finish;
+ }
+
+ if (!all_devices) {
+ ERROR("No capture files specified and no live interfaces available");
+ ret = 64;
+ goto finish;
}
- INFO(log_dst, "Capturing from interface \"%s\"\n", from_dev);
+ for (dev_p = all_devices;
+ dev_p;
+ dev_p = dev_p->next) {
+ /* Don't use the any devices, it's horribly broken */
+ if (!strcmp(dev_p->name, "any")) continue;
+ *in_head = fr_pcap_init(conf, dev_p->name, PCAP_INTERFACE_IN);
+ in_head = &(*in_head)->next;
+ }
+ conf->from_auto = true;
+ conf->from_dev = true;
+ INFO("Defaulting to capture on all interfaces");
}
/*
- * Print captures values which will be used
+ * Print captures values which will be used
*/
if (fr_debug_flag > 2) {
- DEBUG1(log_dst, "Sniffing with options:\n");
- if (from_dev) DEBUG1(log_dst, " Device : [%s]\n", from_dev);
- if (limit > 0) DEBUG1(log_dst, " Capture limit (packets) : [%d]\n", limit);
- DEBUG1(log_dst, " PCAP filter : [%s]\n", pcap_filter);
- DEBUG1(log_dst, " RADIUS secret : [%s]\n", radius_secret);
- if (filter_vps){DEBUG1(log_dst, " RADIUS filter :\n");
- vp_printlist(log_dst, filter_vps);
+ DEBUG2("Sniffing with options:");
+ if (conf->from_dev) {
+ char *buff = fr_pcap_device_names(conf, in, ' ');
+ DEBUG2(" Device(s) : [%s]", buff);
+ talloc_free(buff);
+ }
+ if (conf->to_file || conf->to_stdout) {
+ DEBUG2(" Writing to : [%s]", out->name);
+ }
+ if (conf->limit > 0) {
+ DEBUG2(" Capture limit (packets) : [%" PRIu64 "]", conf->limit);
+ }
+ DEBUG2(" PCAP filter : [%s]", conf->pcap_filter);
+ DEBUG2(" RADIUS secret : [%s]", conf->radius_secret);
+
+ if (conf->filter_request_code) {
+ DEBUG2(" RADIUS request code : [%s]", fr_packet_codes[conf->filter_request_code]);
+ }
+
+ if (conf->filter_request_vps){
+ DEBUG2(" RADIUS request filter :");
+ vp_printlist(fr_log_fp, conf->filter_request_vps);
+ }
+
+ if (conf->filter_response_code) {
+ DEBUG2(" RADIUS response code : [%s]", fr_packet_codes[conf->filter_response_code]);
+ }
+
+ if (conf->filter_response_vps){
+ DEBUG2(" RADIUS response filter :");
+ vp_printlist(fr_log_fp, conf->filter_response_vps);
}
}
/*
- * Figure out whether were doing a reading from a file, doing a live
- * capture or reading from stdin.
+ * Setup collectd templates
*/
- if (from_file) {
- in = pcap_open_offline(from_file, errbuf);
-#ifdef HAVE_PCAP_FOPEN_OFFLINE
- } else if (from_stdin) {
- in = pcap_fopen_offline(stdin, errbuf);
-#endif
- } else if (from_dev) {
- pcap_lookupnet(from_dev, &ip_addr, &ip_mask, errbuf);
- in = pcap_open_live(from_dev, 65536, 1, 1, errbuf);
- } else {
- fprintf(stderr, "radsniff: No capture devices available\n");
+#ifdef HAVE_COLLECTDC_H
+ if (conf->stats.out == RS_STATS_OUT_COLLECTD) {
+ size_t i;
+ rs_stats_tmpl_t *tmpl, **next;
+
+ if (rs_stats_collectd_open(conf) < 0) {
+ exit(EXIT_FAILURE);
+ }
+
+ next = &conf->stats.tmpl;
+
+ for (i = 0; i < (sizeof(rs_useful_codes) / sizeof(*rs_useful_codes)); i++) {
+ tmpl = rs_stats_collectd_init_latency(conf, next, conf, "exchanged",
+ &stats.exchange[rs_useful_codes[i]],
+ rs_useful_codes[i]);
+ if (!tmpl) {
+ ERROR("Error allocating memory for stats template");
+ goto finish;
+ }
+ next = &(tmpl->next);
+ }
}
+#endif
- if (!in) {
- fprintf(stderr, "radsniff: Failed opening input (%s)\n", errbuf);
- exit(1);
+ /*
+ * This actually opens the capture interfaces/files (we just allocated the memory earlier)
+ */
+ {
+ fr_pcap_t *tmp;
+ fr_pcap_t **tmp_p = &tmp;
+
+ for (in_p = in;
+ in_p;
+ in_p = in_p->next) {
+ in_p->promiscuous = conf->promiscuous;
+ in_p->buffer_pkts = conf->buffer_pkts;
+ if (fr_pcap_open(in_p) < 0) {
+ ERROR("Failed opening pcap handle (%s): %s", in_p->name, fr_strerror());
+ if (conf->from_auto || (in_p->type == PCAP_FILE_IN)) {
+ continue;
+ }
+
+ goto finish;
+ }
+
+ if (conf->pcap_filter) {
+ if (fr_pcap_apply_filter(in_p, conf->pcap_filter) < 0) {
+ ERROR("Failed applying filter");
+ goto finish;
+ }
+ }
+
+ *tmp_p = in_p;
+ tmp_p = &(in_p->next);
+ }
+ *tmp_p = NULL;
+ in = tmp;
+
+ if (!in) {
+ ERROR("No PCAP sources available");
+ exit(EXIT_FAILURE);
+ }
+
+ /* Clear any irrelevant errors */
+ fr_strerror();
}
- if (to_file) {
- out = pcap_dump_open(in, to_file);
- if (!out) {
- fprintf(stderr, "radsniff: Failed opening output file (%s)\n", pcap_geterr(in));
- exit(1);
+ /*
+ * Open our output interface (if we have one);
+ */
+ if (out) {
+ out->link_type = -1; /* Infer output link type from input */
+
+ for (in_p = in;
+ in_p;
+ in_p = in_p->next) {
+ if (out->link_type < 0) {
+ out->link_type = in_p->link_type;
+ continue;
+ }
+
+ if (out->link_type != in_p->link_type) {
+ ERROR("Asked to write to output file, but inputs do not have the same link type");
+ ret = 64;
+ goto finish;
+ }
}
-#ifdef HAVE_PCAP_DUMP_FOPEN
- } else if (to_stdout) {
- out = pcap_dump_fopen(in, stdout);
- if (!out) {
- fprintf(stderr, "radsniff: Failed opening stdout (%s)\n", pcap_geterr(in));
- exit(1);
+
+ assert(out->link_type > 0);
+
+ if (fr_pcap_open(out) < 0) {
+ ERROR("Failed opening pcap output (%s): %s", out->name, fr_strerror());
+ goto finish;
}
-#endif
}
/*
- * Apply the rules
+ * Setup and enter the main event loop. Who needs libev when you can roll your own...
*/
- if (pcap_compile(in, &fp, pcap_filter, 0, ip_mask) < 0) {
- fprintf(stderr, "radsniff: Failed compiling PCAP filter (%s)\n", pcap_geterr(in));
- exit(1);
+ {
+ struct timeval now;
+ rs_update_t update;
+
+ char *buff;
+
+ memset(&stats, 0, sizeof(stats));
+ memset(&update, 0, sizeof(update));
+
+ events = fr_event_list_create(conf, _rs_event_status);
+ if (!events) {
+ ERROR();
+ goto finish;
+ }
+
+ /*
+ * Initialise the signal handler pipe
+ */
+ if (pipe(self_pipe) < 0) {
+ ERROR("Couldn't open signal pipe: %s", fr_syserror(errno));
+ exit(EXIT_FAILURE);
+ }
+
+ if (!fr_event_fd_insert(events, 0, self_pipe[0], rs_signal_action, events)) {
+ ERROR("Failed inserting signal pipe descriptor: %s", fr_strerror());
+ goto finish;
+ }
+
+ /*
+ * Now add fd's for each of the pcap sessions we opened
+ */
+ for (in_p = in;
+ in_p;
+ in_p = in_p->next) {
+ rs_event_t *event;
+
+ event = talloc_zero(events, rs_event_t);
+ event->list = events;
+ event->in = in_p;
+ event->out = out;
+ event->stats = &stats;
+
+ if (!fr_event_fd_insert(events, 0, in_p->fd, rs_got_packet, event)) {
+ ERROR("Failed inserting file descriptor");
+ goto finish;
+ }
+ }
+
+ buff = fr_pcap_device_names(conf, in, ' ');
+ DEBUG("Sniffing on (%s)", buff);
+ talloc_free(buff);
+
+ gettimeofday(&now, NULL);
+
+ /*
+ * Insert our stats processor
+ */
+ if (conf->stats.interval) {
+ static fr_event_t *event;
+
+ update.list = events;
+ update.stats = &stats;
+ update.in = in;
+
+ now.tv_sec += conf->stats.interval;
+ now.tv_usec = 0;
+ if (!fr_event_insert(events, rs_stats_process, (void *) &update, &now, &event)) {
+ ERROR("Failed inserting stats event");
+ }
+
+ INFO("Muting stats for the next %i milliseconds (warmup)", conf->stats.timeout);
+ rs_tv_add_ms(&now, conf->stats.timeout, &stats.quiet);
+ }
}
- if (pcap_setfilter(in, &fp) < 0) {
- fprintf(stderr, "radsniff: Failed applying PCAP filter (%s)\n", pcap_geterr(in));
- exit(1);
+
+ /*
+ * Do this as late as possible so we can return an error code if something went wrong.
+ */
+ if (conf->daemonize) {
+ rs_daemonize(conf->pidfile);
}
/*
- * Enter the main capture loop...
+ * Setup signal handlers so we always exit gracefully, ensuring output buffers are always
+ * flushed.
*/
- pcap_loop(in, limit, got_packet, NULL);
+ fr_set_signal(SIGPIPE, rs_signal_self);
+ fr_set_signal(SIGINT, rs_signal_self);
+ fr_set_signal(SIGTERM, rs_signal_self);
+#ifdef SIGQUIT
+ fr_set_signal(SIGQUIT, rs_signal_self);
+#endif
+
+ fr_event_loop(events); /* Enter the main event loop */
+
+ DEBUG("Done sniffing");
+
+ finish:
+
+ cleanup = true;
/*
- * ...were done capturing.
+ * Free all the things! This also closes all the sockets and file descriptors
*/
- pcap_close(in);
- if (out) {
- pcap_dump_close(out);
- }
+ talloc_free(conf);
- if (filter_tree) {
- rbtree_free(filter_tree);
+ if (conf->daemonize) {
+ unlink(conf->pidfile);
}
- INFO(log_dst, "Done sniffing\n");
-
- return 0;
+ return ret;
}
TARGET :=
endif
-SOURCES := radsniff.c
+SOURCES := radsniff.c collectd.c
TGT_PREREQS := libfreeradius-radius.a
-TGT_LDLIBS := $(LIBS) $(PCAP_LIBS)
+TGT_LDLIBS := $(LIBS) $(PCAP_LIBS) $(COLLECTDC_LIBS)
+TGT_LDFLAGS := $(LDFLAGS) $(PCAP_LDFLAGS) $(COLLECTDC_LDFLAGS)
packet->vps = NULL;
PTHREAD_MUTEX_UNLOCK(&sock->mutex);
- if (!rad_packet_ok(packet, 0)) {
+ if (!rad_packet_ok(packet, 0, NULL)) {
RDEBUG("Received bad packet: %s", fr_strerror());
DEBUG("Closing TLS socket from client");
PTHREAD_MUTEX_LOCK(&sock->mutex);